opencv-python 繪製圖像直方圖及直方圖均衡化
1. 繪製圖像的直方圖
下面的程式給出瞭如何繪製一幅影象整體的直方圖和每個通道的直方圖
#-*- coding:utf-8 -*-
import cv2
from matplotlib import pyplot as plt
def whole_hist(image):
'''
繪製整幅影象的直方圖
'''
plt.hist(image.ravel(), 256, [0, 256]) #numpy的ravel函式功能是將多維陣列降為一維陣列
plt.show()
def channel_hist(image):
'''
畫三通道影象的直方圖
'''
color = ('b', 'g', 'r') #這裡畫筆顏色的值可以為大寫或小寫或只寫首字母或大小寫混合
for i , color in enumerate(color):
hist = cv2.calcHist([image], [i], None, [256], [0, 256]) #計算直方圖
plt.plot(hist, color)
plt.xlim([0, 256])
plt.show()
image = cv2.imread('/home/liubo/tmp/sample/00001.jpg')
cv2.imshow('image', image)
cv2.waitKey( 0)
whole_hist(image)
channel_hist(image)
執行可以得到如下的結果
整幅影象的直方圖如下所示
每個通道的直方圖如下所示
可以明顯看到這是一個直方圖分佈不是很均衡的影象,所以我們將嘗試在下面進行直方圖均衡化。
2. 利用直方圖判斷影象是否曝光過度
如果影象曝光過度或者曝光不足會導致計算機視覺相關演算法表現的不夠穩定,比如說一幅曝光過度的影象很有可能導致人臉識別演算法的置信度降低甚至錯誤識別。直方圖對於我們理解曝光有很大的幫助,以下三幅圖在同一時間段拍攝於同一地方,分別是欠曝、準確曝光和過曝的效果,右下角為其對應的直方圖[1][2]
直方圖不管是向右“撞牆”還是向左“爬牆”了,只能說明高光畫素量大,可能是過曝了,僅可用作參考,不能100%確定就是過曝。況且有時為了創意刻意而為之,這時的過曝是一種拍攝技法,可以起到烘托照片的氣氛,或者起到純化背景的作用,比如說下面這張影象
3. 直方圖均衡化
針對曝光過度或者曝光欠缺可以使用 gamma 變化的方法,具體可以參考文章《opencv-python 影象灰度變換》。除了這種方法還可以使用直方圖均衡化的方法。
在現實的拍攝過程中,比如說視訊監控領域,由於其影象的灰度分佈集中在較窄的範圍內,這就導致了影象的細節不夠清晰。為什麼不清晰呢,因為灰度分佈較窄時,那麼,在計算對比度的時候,對比度就很小,所以就不清晰。為了使得影象變得清晰,那麼就需要使得灰度值的差別變大,為了使得灰度值的差別變大,就意味著灰度分佈就變的較寬,使得灰度值分佈變得均勻,在某個灰度級區間內,畫素的個數分佈大致相同,這樣才能使得影象的對比度增強,細節變得清晰可見[3]。
在opencv 3 中的函式 cv2.equalizeHist(img)
可以將輸入影象進行影象均衡化處理,但是需要注意的是輸入影象必須是 8 位的單通道影象,返回影象也是一個 8 位的單通道影象,對於彩色影象必須逐一通道處理,如下所示
# 直方圖均衡化
(b, g, r) = cv2.split(frame)
bH = cv2.equalizeHist(b)
gH = cv2.equalizeHist(g)
rH = cv2.equalizeHist(r)
frameH = cv2.merge((bH, gH, rH))
但是在實踐中,對RGB 影象中的每個通道的影象單獨應用直方圖均衡不太可能給出美觀的效果。一種可能比較好的方法是,將影象轉換到 LAB 顏色空間,然後再將直方圖均衡應用於亮度通道。
參考
[1] 葉明 蜂鳥網 《教你如何判斷一張照片的曝光是否完全準確》
[2] brucebruce 豆瓣 判定照片曝光過度的4個竅門!
[3]菲爾因惹火 CSDN 《直方圖均衡化(Histogram equalization)與直方圖規定化》