opencv關於對比度和亮度的誤解

NO IMAGE

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值非常低),導致前景對比度差,效果沒有手動設定對比度好。