「眼前的黑不是黑,你說的白是什麼白」-- 你是我的眼(蕭煌奇)
沒錯,並非所有圖片都是在理想的環境下拍攝的,
光線不足(太黑)或是過曝(太白)問題都會讓圖片中的訊息丟失,
造成人們看不清楚照片中的物品。
好在我們可以統計各個像素值的數量,得知這張圖片灰度的分布。
然後使用數學來解決它!
什麼是灰度直方圖(Histogram):
X軸為像素值(0 ~ 255),Y軸為該值的數量。
灰度直方圖的特性:
若圖片全黑(像素為0),則直方會集中在圖的左側,代表圖片太暗了。
觀察照片(angry):
因為下圖(MDFK)較上圖暗,所以直方圖的bin偏向左邊。
觀察照片(neutral):
因為上圖(女人)各個灰度值發生較平均,所以直方圖的bin呈現平均分散的狀態,
而下圖(嬰兒)黑白分明,少有中間灰色,所以直方圖的bin集中在兩側,中間只有零星幾個bin。
我們挑選一張可愛的嬰兒表情圖片進行解說,
由於原圖片太小,我將它放大至(600,600)。
idx = 12
gray_img = X_train[idx][:, :, 0].astype("uint8")
gray_img = cv2.resize(gray_img, (600, 600))
plt.figure(figsize=(5, 5))
plt.imshow(gray_img, cmap='gray')
之所以挑選這張照片,
是因為它黑白分明,有利於說明。
在opencv中,有提供equalizeHist函數,將圖片進行均衡化(Equalization)。
均衡化:透過拉伸的像素值(對比度拉伸),使得像素分布較均勻,提高對比度。
原理:透過調整累積分布函數(CDF),把像素值高的區域分散給周圍區域,使CDF呈現斜直線。
equalized_img = cv2.equalizeHist(gray_img)
cv2.imshow("equal_image", equalized_img)
來看看調整後的圖片:
好像有點恐怖...
這時,我們就可以透過灰度直方圖的比較來看看發生什麼事:
看起來是因為原本超級白的臉蛋在邊緣位置上被黑色汙染了,如果這張圖是彩色的,那我可以合理推測嬰兒是掉進泥巴坑了。
不~~~~~~~把我可愛的寶寶還來!
有沒有更好的均衡化方法呢?有的!
那就是自適應直方圖均衡化,
它的改良處在於將圖片分成多個區域(如8x8),
每個區域各自做直方圖均衡化,所以AHE比HE更適合增強局部對比度。
但直方圖均衡化的缺點「放大暗處的雜訊」在AHE中並沒有獲得改善。
好在有人提出限制對比度自適應直方圖均衡化(Contrast Limited Adaptive Histogram Equalization),
限制對比度的核心概念是控制CDF斜率,將突然長太高(超過某閾值)的bin砍掉頭,拿去補低的像素值。
clahe = cv2.createCLAHE(clipLimit=2)
clahe_img = clahe.apply(gray_img)
cv2.imshow("clahe_img", clahe_img)
經由CLAHE處理過後圖片的對比增加了,
連嬰兒的眼睛鼻子嘴巴都看得非常清楚呢!
再來比較CLAHE處理前後的直方圖,
灰度分布比只用HE還要更均勻了。
這篇講到影像處理中常用的圖像增強技巧,
目的是讓大家認識這個技巧,
我沒有深入到講解演算法的部分,
如果有興趣知道背後數學的話,
網路上有許多資源可以學習。