直方圖是我們在數據分析時常使用的表示方式,但在影像處理時又能擦出如何的火花呢?透過像素點的資訊統計,我們不僅能洞察影像的亮度、對比度等基本特性,更能進一步探索影像增強、色彩調整、影像分割等進階應用。就讓我們一起踏上這趟影像處理的探索之旅,揭開直方圖在影像世界中的奧秘。
素材取用
圖片:<雲端下載> | 清明 by DaylightAllure
實作過程
除了用於分析之外,我們也能夠透過修改直方圖來重新組合圖片,因此除了單純的圖表繪製外,我們也來探討均衡化所能帶來的效果吧。
圖形繪製
在實作過程中發現到最為困難的便是,這類的方法主要都是接收二維陣列,我們必須先把圖層分出,分開處理再合併。畢竟我們在觀察上勢必要用上色彩,因此我設計出一套複雜的方式,用來應對灰階與 RGB 圖片。
def getHistogram(img, srcTitle='原始圖像'):
dim = len(img.shape)
# 灰階
if dim == 2:
histSize = 256
histRange = (0, 256)
hist = cv2.calcHist([img], [0], None, [histSize], histRange)
hist_norm = cv2.normalize(hist, None, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX)
# 繪圖
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.imshow(img, cmap="gray")
plt.title(srcTitle)
plt.axis('off')
plt.subplot(1, 2, 2)
plt.plot(hist_norm, color='gray', label='Grayscale')
# 其他
elif dim == 3:
# 頻道切分
bgr_planes = cv2.split(img.copy())
# 數值篩選條件
histSize = 256
histRange = (0, 256) # the upper boundary is exclusive
accumulate = False
# 計算各頻道曝光直方圖
b_hist = cv2.calcHist(bgr_planes, [0], None, [histSize], histRange, accumulate=accumulate)
g_hist = cv2.calcHist(bgr_planes, [1], None, [histSize], histRange, accumulate=accumulate)
r_hist = cv2.calcHist(bgr_planes, [2], None, [histSize], histRange, accumulate=accumulate)
# 標準化來方便檢視
b_hist_norm = cv2.normalize(b_hist, None, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX)
g_hist_norm = cv2.normalize(g_hist, None, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX)
r_hist_norm = cv2.normalize(r_hist, None, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX)
# 繪圖
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.imshow(img)
plt.title(srcTitle)
plt.axis('off')
plt.subplot(1, 2, 2)
plt.plot(b_hist_norm, color='blue', label='Blue Channel')
plt.plot(g_hist_norm, color='green', label='Green Channel')
plt.plot(r_hist_norm, color='red', label='Red Channel')
plt.title('色彩直方')
plt.xlabel('Pixel Value')
plt.ylabel('Normalized Frequency')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()

我們知道 255 則代表最亮的情況,在範例中可以看到三個頻道事實上用量都非常多,由此可以率先看出色彩的鮮豔度與亮度,看出圖片是否過度或切缺曝光。而區間之間的差異則代表著對比度,最後還能從三種顏色的比例看出色調與色溫。只能說曝光直方圖是個超級實用的特徵判斷工具。
至於為何過程中我們特定標準化呢?因為比起像素點的統計總數,標準化後我們可以藉由 0~1 的分布快速看出比例,而不用額外去做換算的工作。
均衡化
色彩均衡化的概念,是透過拉伸與重新分配顏色的分布,以改善曝光不足或背光等問題。那我們的工具包中則存在著兩種實用的工具,同樣各有其優缺點,如何選擇,取決於您對影像處理的需求和偏好。
全局直方圖均衡化
第一想法肯定是直接對整張圖片進行全局性的色彩均衡化,卻可能會產生意想不到的結果。當我們調整影像的亮度分布時,最高亮度值和最低亮度值會被重新映射。原本過暗的區域變亮這很正常,但原本明亮的區域卻容易被視作過曝,但這種方式可以確保顏色的使用量較為平均。

限制對比度自適應直方圖均衡化 CLAHE
所以後來我們推出自適應直方圖均衡化 (Adaptive Histogram Equalization) 的概念,簡稱就是 AHE,透過計算圖像每個顯著區域,也就是把整個圖像切分許多小塊,局部化地重新分佈亮度值。但是這種技術有個明顯的問題,就是會放大區塊內的噪音。
於是乎我們追加對比度的限制,形成 Contrast Limited 的 AHE,也就是 CLAHE 這個更為常使用的技術。使用過程間除了設定區域大小外,還會再設定對比度的閥值。而完成處理後,觀察圖形能發現大體走勢變得相對順暢,在轉捩點變成平滑的走勢,但在每個小區則通常會有一個醒目的尖峰。

後話
我們深入了解了直方圖在影像處理中的強大功能。從基本的亮度、對比度分析,到進階的色彩均衡化和影像增強,直方圖都扮演著不可或缺的角色。它不僅是一個視覺化的工具,更是一個強大的分析利器。
透過深入理解直方圖的原理和應用,我們可以更好地處理影像,提升影像品質,並在影像分析、識別等領域取得更好的成果,熟悉這項技術也將大幅幫助特徵的捕捉工作。
參考
[1] Histograms in OpenCV — OpenCV
https://docs.opencv.org/4.x/de/db2/tutorial_py_table_of_contents_histograms.html
[2] 淺談直方圖均衡化 — Medium by Cindy Lin
https://medium.com/@cindylin_1410/%E6%B7%BA%E8%AB%87-opencv-%E7%9B%B4%E6%96%B9%E5%9C%96%E5%9D%87%E8%A1%A1%E5%8C%96-ahe%E5%9D%87%E8%A1%A1-clahe%E5%9D%87%E8%A1%A1-ebc9c14a8f96
[3] OpenCV – Histograms直方圖 — CH.Tseng 的 WordPress
https://chtseng.wordpress.com/2016/12/05/opencv-histograms%E7%9B%B4%E6%96%B9%E5%9C%96/
額外讀物
[4] CLAHE — OpenCV
https://docs.opencv.org/3.4/d6/db6/classcv_1_1CLAHE.html