学习到范例五的时候,发觉虽然范例都很简单,但是做记录的时候,并且把程序里面使用过的类或方法都弄明白,也就不简单了,接下来介绍一下范例五吧。
1、图像处理
一般来说,图像处理算子是带有一幅或多幅输入图像、产生一幅输出图像的函数。
图像变换可分为以下两种:
点算子(像素变换):图像对比度和亮度,等等
邻域(基于区域的)算子:均值滤波,中值滤波,等等,也就是卷积运算
2、亮度和对比度调整
两种常用的点过程(即点算子),是用常数对点进行 乘法 和 加法 运算:
两个参数 和 一般称作 增益 和 偏置 参数。我们往往用这两个参数来分别控制 对比度 和 亮度 。
你可以把 看成源图像像素,把 看成输出图像像素。这样一来,上面的式子就能写得更清楚些:
其中, 和 表示像素位于 第i行 和 第j列 。
3、运行代码如下:
程序使用三种方式来实现亮度和对比度的调整,并且输出了各自运算的时间。
#include "stdafx.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace std;
using namespace cv;
double alpha; /**< 控制对比度 */
int beta; /**< 控制亮度 */
int main( int argc, char** argv )
{
double t;
/// 读入用户提供的图像
Mat image = imread( "Lena.jpg" );
Mat new_image = Mat::zeros( image.size(), image.type() );
Mat new_image1 = Mat::zeros( image.size(), image.type() );
Mat new_image2 = Mat::zeros( image.size(), image.type() );
/// 初始化
cout << " Basic Linear Transforms " << endl;
cout << "-------------------------" << endl;
cout << "* Enter the alpha value [1.0-3.0]: ";
cin >> alpha;
cout << "* Enter the beta value [0-100]: ";
cin >> beta;
t = (double)getTickCount();
/// 执行运算 new_image(i,j) = alpha*image(i,j) + beta
for( int y = 0; y < image.rows; y++ )
{
for( int x = 0; x < image.cols; x++ )
{
for( int c = 0; c < 3; c++ )
{
new_image.at<Vec3b>(y,x)[c] = saturate_cast<uchar>( alpha*( image.at<Vec3b>(y,x)[c] ) + beta );
}
}
}
t = 1000*((double)getTickCount() - t)/getTickFrequency();
cout << ".at+[] Times passed in milliseconds: " << t << endl;
t = (double)getTickCount();
int nr= image.rows; // number of rows
int nc= image.cols * image.channels(); // total number of elements per line
for (int y=0; y<nr; y++)
{
uchar* data= image.ptr<uchar>(y);
uchar* data1=new_image1.ptr<uchar>(y);
for (int x=0; x<nc; x++)
{
data1[x]=saturate_cast<uchar>(alpha*data[x]+beta);
}
}
t = 1000*((double)getTickCount() - t)/getTickFrequency();
cout << ".ptr+[] Times passed in milliseconds: " << t << endl;
t = (double)getTickCount();
image.convertTo(new_image2, -1, alpha, beta);
t = 1000*((double)getTickCount() - t)/getTickFrequency();
cout << "convertTo Times passed in milliseconds: " << t << endl;
/// 创建窗口
namedWindow("Original Image", 1);
namedWindow("New Image", 1);
namedWindow("New Image1", 1);
namedWindow("New Image2", 1);
/// 显示图像
imshow("Original Image", image);
imshow("New Image", new_image);
imshow("New Image1", new_image1);
imshow("New Image2", new_image2);
/// 等待用户按键
waitKey();
return 0;
}
4、运行结果:
图1、原图 图2、.at方法
图3、.ptr方法 图4、convertTo方法
图5、运行时间
5、结论
从运行时间可以看出,使用OpenCV自带的函数运行效率最高,而使用.ptr方法比.at方法好,这也印证了前面博客学习OpenCV范例(二)——OpenCV如何扫描图像、利用查找表和计时所说的。
6、用到的类
convertTo:
功能:通过缩放比例将数组变换成其他类型
结构:
void Mat::convertTo(OutputArray m, int rtype, double alpha=1, double beta=0 ) const
m:输出图像
rtype:输出图像的类型
alpha:比例因子α,决定对比度
beta:附加值β,决定亮度
函数原理如下:
saturate_cast:
功能:防止数据溢出
为什么上面的函数会用到saturate_cast呢,因为无论是加是减,乘除,都会超出一个像素灰度值的范围(0~255)所以,所以当运算完之后,结果为负,则转为0,结果超出255,则为255。