2.5 改变图像的对比度和明暗
目标
在教程中,你会学到如何:
1、读取像素值
2、用0初始化一个矩阵
3、学习staurate_cast是做什么的
4、获取有关像素变换的一些更酷的信息(Get some cool info about pixel transformations)
理论
注意,下面的解释来自于Richard Szeliski所写的《Computer Vision:Algorithms and Applications》
图像处理
1、一般的图像处理机是一个接受一个或多个输入图像的并且产生一个暑促图像的函数。
2、图像转换可以被看作:
—点处理机(像素转换)
—邻域(基于区域)处理机
像素转换
1、在这种图像处理中,每一个输出的像素值只依赖于与之对应的输入像素值(加,隐式的,一些全局收集的信息或者参数)。
2、例子中的操作包括亮度和对比度的调整也有颜色的修正和转换。
亮度和对比度的调整
1、两个常用于图像处理的被乘和被加的常数:
g(x)=αf(x)+β
2、参数α>0,β经常被称作gain和bias参数;有时候这些参数被独立的(resepctively)称作控制对比度和明暗度的部分。
3、你可以把f(x) 当作源图像的像素,g(x)当作输出图像像素。这样我们可以更为明显的将表达式写为:
g(i,j)=α*f(i,j)+β
其中i和j就是指在第i行和第j列的像素的坐标。
代码
下面就是g(i,j)=α*f(i,j)+β的体现
#include<cv.h>
#include<highgui.h>
#include<iostream>
using namespace cv;
double alpha;
int beta;
int main(int argc,char**argv)
{
Mat image=imread(argv[1]);
Mat new_image=Mat::zeros(image.size(),image.type());
std::cout<<”Basic Linear Transforms”<<std::endl;
std::cout<<”___________________:<<std::endl;
std::cout<<”Enter the alpha value[1.0-3.0]:”;
std::cin>>alpha;
std::cout<<”Enter the beta value[0-100]:”;
std::cin>>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);
}
}
}
nameWindow(“Original Image”,1);
nameWindow(“New Image”,1);
imshow(“Original Image:,image);
imshow(“New Image”,new_Image);
waitKey();
return 0;
}
解释
1、我们首先构造参数来保存α和β,两个参数的值由用户输入:
double alpha;
int beta;
2、使用imread载入图像并将其保存至Mat 对象中:
Mat image=imread(argv[1]);
3、现在,由于我们将要对这个图像进行一些转变,因此我们需要一个新的Mat 对象来存储这个转变。我们希望新的Mat 对象能有一下几个特征:
(1)初始的像素值都为0
(2)和原始图像相同的尺寸和类型
Mat new_image=Mat::zeros(image.size(),image.type());
我们可以看到Mat::zeros在image.size()和image.type()的基础上返回了一个matlab式样的0的初始化对象。
4、现在为了进行g(i,j)=α*f(i,j)+β操作,我们读取图像中每个像素的值。因为我们在RGB图像中进行操作,我们的每个像素中会有三个数值(R,G和B),因此我们要独立的读取他们。这里是部分代码:
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);
}
}
}
请注意下面:
(1)为了进入每一个图像中的像素,我们使用这样的语句:image.at<Vec3b>(y,x)[c]。在这里y是行,x是列,c是R,G或者B(0,1或者2)。
(2)因为α*p(i,j)+β这个操作可能得到的数值超过范围或者不是整数(如果α是float数值),我们使用saturate_cast来确保数值是可用的。
5、最后,我们用最常见的方法创建窗口并且显示图像。
namedWindow(“Original Image”,1);
namedWindow(“New Image,1);
imshow(“Original Image”,image);
imshow(“New Image”,new_image);
waitKey(0);
注意:除了使用for循环来读取每个像素,我们可以简单的使用image.convertTo(new_image,-1,alpha,beta)这个命令。
converTo在new_image=a*image+beta有着高效的性能体现。然而,我们想要让你看一下如何读取每个元素。不管使用哪种方式,都会得到相同的结果。
结果
使用α=2.2,β=50来运行代码,我们可以得到如下结果: