OpenCV学习笔记之一——图像亮度对比度变换

由于毕设的关系,开始折腾计算机视觉
双目测距的具体实现,现在刚有点眉目而已
看了下图像亮度/对比度的变换的资料
结果又发现漫山遍野的都是同一份代码
而且几乎没有什么解释
原本决定等Harris角点那些弄完再写篇文章
现在想想
还是先记下这份简单的笔记并加以讲解下

那些计算机科班出身的人就不用看这篇了
这只是给我们这些物理/电子系中没有学过”数字图像处理“这门课的人看的

术语解释

亮度(Brightness)

也叫亮度,中文翻译不同而已,你可以看Wikipedia
RGB 色彩空间中,明度可以被认为是R(红色),G(绿色)和B(蓝色)座标的算术平均 μ(尽管这三个成分中的某个要比其他看起来更明亮,但这可以被某些显示系统自动补偿):

 \mu = {R + G + B \over 3 }

对比度(Contrast)

我实在google不到满意的解释
大概上来说
灰度图像的对比度指的是图像中的最黑与最白的点,他们灰度值的比值关系
彩色图像由于有3种通道,我的理解是各个通道中的灰度值的比值关系,确切的定义还望有人指教

实现思路

知道明度跟对比度的定义,接下来
要修改亮度,就把图像的通道的灰度值一起增加或者减少就可以
要修改对比度,需要把图像的通道的灰度值以一个值为临界点,往相反两个方向变化
比如,取128为阈值,要增强对比度,低于128的值修改得比原来更小,高于128的值再修改得更大,要降低对比度就反向操作

下面给出我自己写的一份代码,演示明度以及对比度的调整
对比度的公式参考自Photoshop的公式:
nRGB = RGB + (RGB – Threshold) * Contrast / 255

源代码

#include "highgui.h"
#pragma comment(lib,"cv200d.lib")
#pragma comment(lib,"cxcore200d.lib")
#pragma comment(lib,"highgui200d.lib")

int BrightnessAdjust(const IplImage* srcImg,
					 IplImage* dstImg,
					 float brightness)
{
	assert(srcImg != NULL);
	assert(dstImg != NULL);

	int x,y,i;
	float val;
	for (i = 0; i < 3; i++)//彩色图像需要处理3个通道,灰度图像这里可以删掉
	{
		for (y = 0; y < srcImg->height; y++)
		{
			for (x = 0; x < srcImg->width; x++)
			{

				val = ((uchar*)(srcImg->imageData + srcImg->widthStep*y))[x*3+i];
				val += brightness;
				//对灰度值的可能溢出进行处理
				if(val>255)	val=255;
				if(val<0) val=0;
				((uchar*)(dstImg->imageData + dstImg->widthStep*y))[x*3+i] = (uchar)val;
			}
		}
	}

	return 0;
}

int ContrastAdjust(const IplImage* srcImg,
				   IplImage* dstImg,
				   float nPercent)
{
	assert(srcImg != NULL);
	assert(dstImg != NULL);

	int x,y,i;
	float val;
	for (i = 0; i < 3; i++)//彩色图像需要处理3个通道,灰度图像这里可以删掉
	{
		for (y = 0; y < srcImg->height; y++)
		{
			for (x = 0; x < srcImg->width; x++)
			{

				val = ((uchar*)(srcImg->imageData + srcImg->widthStep*y))[x*3+i];
				val = 128 + (val - 128) * nPercent;
				//对灰度值的可能溢出进行处理
				if(val>255) val=255;
				if(val<0) val=0;
				((uchar*)(dstImg->imageData + dstImg->widthStep*y))[x*3+i] = (uchar)val;
			}
		}
	}
	return 0;
}

int main(int argc, char** argv)
{
	IplImage* srcImg = cvLoadImage("lena.jpg");
	assert( srcImg != NULL );

	IplImage* brightnessImg = cvCloneImage(srcImg);
	//亮度变换,最后数值取值为正时变亮,负则变暗
	BrightnessAdjust(srcImg, brightnessImg, 80.0f);

	IplImage* contrastImg = cvCloneImage(srcImg);
	//对比度变换,数值小于1降低对比度,大于1增强对比度
	ContrastAdjust(srcImg, contrastImg, 1.3f);

	cvNamedWindow("Source",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("BrightnessAdjust",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("ContrastAdjust",CV_WINDOW_AUTOSIZE);
	cvShowImage("Source",srcImg);
	cvShowImage("BrightnessAdjust",brightnessImg);
	cvShowImage("ContrastAdjust",contrastImg);
	cvWaitKey(0);
	cvReleaseImage(&srcImg);
	cvReleaseImage(&brightnessImg);
	cvReleaseImage(&contrastImg);
	cvDestroyWindow("Source");
	cvDestroyWindow("BrightnessAdjust");
	cvDestroyWindow("ContrastAdjustrast");

	return 0;
}

对新手提示几句,运行这个代码请在工程文件的目录下放一个图片,名字是lena.jpg
另外,对彩色通道的处理,循环只有3次,这种循环最好放在最外围,因为图像的长宽一般都远大于这个值
如果你把小循环放最里面,频繁的循环切换,效率会低不少
这只是程序编写技巧上的小提示

本代码在Visual Studio 2008+OpenCV 2.0下运行通过,效果如下


并且与photoshop的调整效果对比过
亮度变换与ps旧版效果一致,貌似ps对亮度变换的公式进行过调整,新版不是这么单纯的加减灰度值
对比度就几乎都差不多了

更多资料

关于OpenCV的安装、配置以及基础学习,可以在OpenCV中文官网查得
官网的入门说明异常详细,各种平台各种IDE都有介绍,我就不多废话了

下次再说说Harris角点的事情吧

Tagged

发表评论

电子邮件地址不会被公开。