亮度调整:图像像素强度整体变高/变低。
对比度调整:图像暗处像素强度变低,图像亮处像素强度变高,从而拉大中间某个区域范围的显示精度。
通过设计一个映射曲线就可完成对比度、亮度调整,具体过程如上图所示,(a)为原图;(b)把亮度调高,像素强度+固定值;(c)把亮度调低,像素强度-固定值;(d)增大像素强度75附近的对比度;(e)增大像素强度150附近的对比度;(f)增大像素强度75和225附近的对比度。
曲线斜率大于45度角的区域灰度拉伸、精度上升、对比度变高;小于45度角的区域灰度被压缩、精度下降、对比度变低。
目前,网络上大部分使用opencv调整图像对比度和亮度的文章,基本都是源于官网的示例
映射曲线公式为g(x) = a*f(x)+b
公式实际上是没错的,除了上述(f)图外,其他映射曲线都能构造出来。但大部分人却错误地认为a是控制对比度,b是控制亮度的。
对比度:需要通过a 、b 一起控制(仅调整a只能控制像素强度0附近的对比度,而这种做法只会导致像素强度大于0的部分更亮而已,根本看不到对比度提高的效果)
亮度:通过b控制
降低对比度: a = 0.6
调整中心:灰度125(即映射曲线经过(125,125)这个点)
可以计算出b = 125*(1-0.6)。 注意这里的b与亮度没有任何关系,仅仅用于对比度调整
效果图如下
提高对比度: a = 1.68
调整中心:灰度125(即映射曲线经过(125,125)这个点)
可以计算出b = 125*(1-1.68)。 注意这里的b与亮度没有任何关系,仅仅用于对比度调整
效果图如下
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); }
通过这种单一直线能完成简单的固定的对比度调整。但最好的方式是根据目标物体设计映射曲线,提高目标区域的映射曲线斜率,可参考下图做法
(a)图是直方图,也可以看成根据bin值自动设定的对比度,像素个数多的bin对比度设定高;(b)图是人为设定的对比度;(c)图中manual映射曲线是(b)图积分、归一化得到的,(c)图中from histogram是(a)图积分、归一化得到。
(b)图中225-250区域之所以设定高对比度,是为了提高grill这个目标物体成像效果。与直方图均衡化有所区别,因为后者不会去关心grill,它只保证图像entropy最大化。
直方图均衡化的缺点:不会区分目标物体,只会按灰度像素分布设计对比度。比如上述图像中,human body和grill才是我们关注的目标,但直方图均衡化后这两个区域的对比度被设置为非常低的值(human body和grill像素区域小,对应的bin值非常低),导致前景对比度差,效果没有手动设定对比度好。