#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
//载入源图像,彩色图
cv::Mat src = cv::imread("C:\\Users\\dell\\Desktop\\xin1.jpg", IMREAD_COLOR);
//检查源图像的有效性
if (src.empty() || src.channels() != 3)
{
cout << "source image load failed!" << endl;
return -1;
}
//用户指定变量alpha和beta的值
float alpha = 0.0f;
int beta = 0;
cout << "please input alpah(1.0 - 3.0) and beta(0 - 100): " << endl;
cin >> alpha;
cin >> beta;
//初始化目标图像
cv::Mat dst = cv::Mat::zeros(src.size(), src.type());
//对每个像素值进行变化 Dst(i,j) = Src(i,j)*alpha + beta
for (int j = 0; j < src.rows; j++)
{
for (int i = 0; i < src.cols; i++)
{
for (int c = 0; c < 3; c++)
{
dst.at<Vec3b>(j, i)[c] = saturate_cast<uchar>((src.at<Vec3b>(j, i))[c] * alpha + beta);
}
}
}
cv::imshow("src", src);
cv::imshow("dst", dst);
cv::waitKey(0);
return 0;
}
输入alpha = 1.5 beta = 30 ,因此变换公式为Dst(i,j) = alpha * Src(i,j) + beta = 1.5 * Src(i,j) + 30
源图像
目标图像
来验证一下是否按照公式Dst(i,j) = alpha * Src(i,j) + beta = 1.5 * Src(i,j) + 30变换的??
源图像中(0,0)处B | G | R = 161 | 198 | 96
按照公式计算目标图像(0,0)处:
Dst(0,0)[B] = 161 * 1.5 + 30 = 271.5
Dst(0,0)[G] = 198 * 1.5 + 30 = 327
Dst(0,0)[R] = 96 * 1.5 + 30 = 174
注意,程序中用了saturate_cast<uchar>限制了像素值的范围为0-255.因此 Dst(0,0)[B] = 255, Dst(0,0)[G] = 255, Dst(0,0)[R] = 174.
看一下目标图像中是否如此??
目标图像中像素值确实如公式计算那样。(#^.^#)
官方教程提到可以利用函数convertTo快速完成上述功能。下面研究一下convertTo函数。
先看一下函数说明:
再看一下函数声明:
//! converts matrix to another datatype with optional scalng. See cvConvertScale.
void convertTo( OutputArray m, int rtype, double alpha=1, double beta=0 ) const;
/*!
\param rtype The output matrix data type. When it is =-1, the output array will have the same data type as (*this)
\param alpha The scale factor
\param beta The optional delta added to the scaled values before the conversion
*/
void convertTo( Mat& m, int rtype, double alpha=1, double beta=0 ) const;
下面用convertTo函数实现对比度和亮度调整功能:
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
//载入源图像,彩色图
cv::Mat src = cv::imread("C:\\Users\\dell\\Desktop\\xin1.jpg", IMREAD_COLOR);
//检查源图像的有效性
if (src.empty() || src.channels() != 3)
{
cout << "source image load failed!" << endl;
return -1;
}
cv::imshow("src", src);
//用户指定变量alpha和beta的值
float alpha = 0.0f;
int beta = 0;
cout << "please input alpah(1.0 - 3.0) and beta(0 - 100): " << endl;
cin >> alpha;
cin >> beta;
//初始化目标图像
cv::Mat dst1 = cv::Mat::zeros(src.size(), src.type());
cv::Mat dst2 = cv::Mat::zeros(src.size(), src.type());
//方法一
//对每个像素值进行变化 Dst(i,j) = Src(i,j)*alpha + beta
double tc1 = (double)getTickCount();
for (int j = 0; j < src.rows; j++)
{
for (int i = 0; i < src.cols; i++)
{
for (int c = 0; c < 3; c++)
{
dst1.at<Vec3b>(j, i)[c] = saturate_cast<uchar>((src.at<Vec3b>(j, i))[c] * alpha + beta);
}
}
}
double t1 = ((double)getTickCount() - tc1) / getTickFrequency();
cout << "method1 cost time : " << t1 << endl;
cv::imshow("dst1", dst1);
//方法二
//利用函数convertTo()
double tc2 = (double)getTickCount();
src.convertTo(dst2, -1, alpha, beta);
double t2 = ((double)getTickCount() - tc2) / getTickFrequency();
cout << "method2 cost time : " << t2 << endl;
cv::imshow("dst2", dst2);
cv::waitKey(0);
return 0;
}
可以看出,利用函数convertTo确实比对单个像素进行变换速度更快。
最后,关于saturate_cast防止数据溢出,以后经常会用到,本文涉及的知识用到的相关的是:
template<> inline uchar saturate_cast<uchar>(int v)
{ return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); }
template<> inline uchar saturate_cast<uchar>(float v)
{ int iv = cvRound(v); return saturate_cast<uchar>(iv); }
template<> inline uchar saturate_cast<uchar>(double v)
{ int iv = cvRound(v); return saturate_cast<uchar>(iv); }
可以看到,对于float和double类型,先是利用cvRound转换为int型,然后对于int型,利用选择运算符将像素值限定在0和UCHAR_MAX之间。