opencv关于对比度和亮度的误解

1 对比度与亮度概念

亮度调整:图像像素强度整体变高/变低。

对比度调整:图像暗处像素强度变低,图像亮处像素强度变高,从而拉大中间某个区域范围的显示精度。


通过设计一个映射曲线就可完成对比度、亮度调整,具体过程如上图所示,(a)为原图;(b)把亮度调高,像素强度+固定值;(c)把亮度调低,像素强度-固定值;(d)增大像素强度75附近的对比度;(e)增大像素强度150附近的对比度;(f)增大像素强度75和225附近的对比度。

曲线斜率大于45度角的区域灰度拉伸、精度上升、对比度变高;小于45度角的区域灰度被压缩、精度下降、对比度变低。

2 Opencv关于对比度和亮度的示例

目前,网络上大部分使用opencv调整图像对比度和亮度的文章,基本都是源于官网的示例

映射曲线公式为g(x) = a*f(x)+b

公式实际上是没错的,除了上述(f)图外,其他映射曲线都能构造出来。但大部分人却错误地认为a是控制对比度,b是控制亮度的

对比度:需要通过a 、b 一起控制(仅调整a只能控制像素强度0附近的对比度,而这种做法只会导致像素强度大于0的部分更亮而已,根本看不到对比度提高的效果)

亮度:通过b控制


3 正确的对比度调整

降低对比度: a = 0.6 

调整中心:灰度125(即映射曲线经过(125,125)这个点)

可以计算出b = 125*(1-0.6)。 注意这里的b与亮度没有任何关系,仅仅用于对比度调整

效果图如下



提高对比度: a = 1.68 

调整中心:灰度125(即映射曲线经过(125,125)这个点)

可以计算出b = 125*(1-1.68)。 注意这里的b与亮度没有任何关系,仅仅用于对比度调整

效果图如下


4 实现代码

得到a、b值后,直接用convertTo即可。其中s_mean[0]即代表(125,125)调整中心,可以根据需要自行更改。src、src2为输入图像。

void ApplyContrast()
{
	Mat dst;
	Mat dst2;
	
	if(slider_a < 25)
	{
		a = (double)slider_a/25;//(0~24)/25
	}
	else
	{
		a = (double)slider_a/25;// (25~50)/5
	}
	//get b
	b = (1-a)*s_mean[0];

	//change contrast
	src.convertTo(dst,src.type(),a,b);
	imshow(WIN_NAME_DST,dst);
	src2.convertTo(dst2,src2.type(),a,b);
	imshow(WIN_NAME_DST2,dst2);
}

5 与直方图均衡化的关系

通过这种单一直线能完成简单的固定的对比度调整。但最好的方式是根据目标物体设计映射曲线,提高目标区域的映射曲线斜率,可参考下图做法

(a)图是直方图,也可以看成根据bin值自动设定的对比度,像素个数多的bin对比度设定高;(b)图是人为设定的对比度;(c)图中manual映射曲线是(b)图积分、归一化得到的,(c)图中from histogram是(a)图积分、归一化得到。

(b)图中225-250区域之所以设定高对比度,是为了提高grill这个目标物体成像效果。与直方图均衡化有所区别,因为后者不会去关心grill,它只保证图像entropy最大化。

直方图均衡化的缺点:不会区分目标物体,只会按灰度像素分布设计对比度。比如上述图像中,human body和grill才是我们关注的目标,但直方图均衡化后这两个区域的对比度被设置为非常低的值(human body和grill像素区域小,对应的bin值非常低),导致前景对比度差,效果没有手动设定对比度好。






你可能感兴趣的:(opencv,Tips)