图像亮度/对比度的调整(一)

2014-11-24 02:00:42 · 作者: · 浏览: 4
要调整正图片的亮度和对比度, 首先要知道亮度和对比度的定义:
“明度”(Brightness)原来用做光度测定术语照度和(错误的)用于辐射测定术语辐射度的同义词。按美国联邦通信术语表(FS-1037C)的规定,明度现在只应用于非定量的提及对光的生理感觉和感知。[1]
一个给定目标亮度在不同的场景中可以引起不同的明度感觉;比如White错觉和Wertheimer-Benary错觉。
在 RGB 色彩空间中,明度可以被认为是 R(红色),G(绿色)和B(蓝色)座标的算术平均 μ(尽管这三个成分中的某个要比其他看起来更明亮,但这可以被某些显示 系统自动补偿):
\mu = {R + G + B \over 3 } 。
即: dst[i] = (src[i + 0] + src[i + 1] + src[i + 2]) / 3 (三通道图片)
明度也是 HSB 或 HSV 色彩空间(色相,饱和度和明度)中的颜色坐标,它的值是这个颜色的 R,G 和 B 三者中的极大值。
对比度,具体的概念解释可以参考Wiki或者百度百科。简单的讲对比度反应了图片上亮区域和暗区域的层次感。而反应到图像编辑上,调整对比度就是在保证平均亮度不变的情况下,扩大或缩小亮的点和暗的点的差异。既然是要保证平均亮度不变,所以对每个点的调整比例必须作用在该值和平均亮度的差值之上,这样才能够保证计算后的平均亮度不变,故有调整公式:
Out = Average + (In – Average) * ( 1 + percent)
其中In表示原始像素点亮度,Average表示整张图片的平均亮度,Out表示调整后的亮度,而percent即调整范围[-1,1]。证明这个公式的正确性相当简单:
设图上有n个像素点,各个点亮度为Ai,平均亮度为A,变化率为alpha,则有:
CodeCogsEqn (1)
但是实际处理中,并没有太多的必要去计算一张图的平均亮度:一来耗时间,二来在平均亮度上的精确度并不会给图像的处理带来太多的好处—-一般就假设一张图的平均亮度为128,即一半亮度,而一张正常拍照拍出来的图平均亮度应该是在[100,150]。在肉眼看来两者基本没有任何区别,而如果真实地去计算平均亮度还会带来很大的计算量。、
即: dst[i] = 128 + (src[i] – 128) * (nPercent) // nPercent = 1 + percent
简单示例:
#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; }

并且与photoshop的调整效果对比过
亮度变换与ps旧版效果一致,貌似ps对亮度变换的公式进行过调整,新版不是这么单纯的加减灰度值对比度就几乎都差不多了
在《Delphi图像处理 -- 亮度/对比度调整》一文实现了Photoshop的亮度/对比度调整功能,这是其C/C++版。
还是先简单介绍一下Photoshop图像亮度/对比度