直方圖均衡化
想象一下,如果一副圖像中的大多是像素點(diǎn)的像素值都集中在一個(gè)像素值范圍之內(nèi)會(huì)怎樣呢?例如,如果一幅圖片整體很亮,那所有的像素值應(yīng)該都會(huì)很高。但是一副高質(zhì)量的圖像的像素值分布應(yīng)該很廣泛。所以你應(yīng)該把它的直方圖做一個(gè)橫向拉伸(如下圖),這就是直方圖均衡化要做的事情。通常情況下,這種操作會(huì)改善圖像的對比度。
這種方法通常用來增加許多圖像的全局對比度,尤其是當(dāng)圖像的有用數(shù)據(jù)的對比度相當(dāng)接近的時(shí)候。通過這種方法,亮度可以更好地在直方圖上分布。這樣就可以用于增強(qiáng)局部的對比度而不影響整體的對比度,直方圖均衡化通過有效地?cái)U(kuò)展常用的亮度來實(shí)現(xiàn)這種功能。
這種方法對于背景和前景都太亮或者太暗的圖像非常有用,這種方法尤其是可以帶來X光圖像中更好的骨骼結(jié)構(gòu)顯示以及曝光過度或者曝光不足照片中更好的細(xì)節(jié)。這種方法的一個(gè)主要優(yōu)勢是它是一個(gè)相當(dāng)直觀的技術(shù)并且是可逆操作,如果已知均衡化函數(shù),那么就可以恢復(fù)原始的直方圖,并且計(jì)算量也不大。這種方法的一個(gè)缺點(diǎn)是它對處理的數(shù)據(jù)不加選擇,它可能會(huì)增加背景噪聲的對比度并且降低有用信號(hào)的對比度。
我們先來看看相應(yīng)的直方圖和累積直方圖,然后使用 OpenCV 進(jìn)行直方圖均衡化。
def img_show(name,image):
"""matplotlib圖像顯示函數(shù)
name:字符串,圖像標(biāo)題
img:numpy.ndarray,圖像
"""
if len(image.shape) == 3:
image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
plt.imshow(image,'gray')
plt.xticks([])
plt.yticks([])
plt.xlabel(name,fontproperties='FangSong',fontsize=12)
if __name__=="__main__":
img = cv2.imread("data/Unequalized.jpg",0)
hist,bins = np.histogram(img.flatten(),256,[0,256])
#print(hist)
#查看累積直方圖
cdf = hist.cumsum()
cdf_normalized = cdf*hist.max() / cdf.max()
#print(cdf_normalized)
#均衡化
equ = cv2.equalizeHist(img)
hist1,bins1 = np.histogram(equ.flatten(),256,[0,256])
#print(hist)
#查看均衡化后的累積直方圖
cdf1 = hist1.cumsum()
cdf_normalized1 = cdf1*hist1.max() / cdf1.max()
#顯示圖像結(jié)果
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(221)
img_show('原圖',img)
plt.subplot(222)
img_show('均衡化后',equ)
plt.subplot(223)
plt.plot(cdf_normalized,color='b')
plt.hist(img.flatten(),256,[0,256],color='r')
plt.xlabel('相應(yīng)的直方圖(紅)和累積直方圖(藍(lán))',fontproperties='FangSong',fontsize=15)
plt.xlim([0,256])
plt.legend(('cdf','historgram'),loc = 'upper left')
plt.subplot(224)
plt.plot(cdf_normalized1,color='b')
plt.hist(equ.flatten(),256,[0,256],color='r')
plt.xlabel('均衡化相應(yīng)的直方圖(紅)和累積直方圖(藍(lán))',fontproperties='FangSong',fontsize=15)
plt.xlim([0,256])
plt.legend(('cdf','historgram'),loc = 'upper left')
plt.show()
我們可以看出來直方圖大部分在灰度值較高的部分,而且分布很集中。而我們希望直方圖的分布比較分散,能夠涵蓋整個(gè) x 軸。所以,我們就需要一個(gè)變換函數(shù)幫助我們把現(xiàn)在的直方圖映射到一個(gè)廣泛分布的直方圖中,這就是直方圖均衡化。
**限制對比度自適應(yīng)性直方圖均衡化 CLAHE **
在上邊做的直方圖均衡化會(huì)改變整個(gè)圖像的對比度,但是在很多情況下,這樣做的效果并不好。的確在進(jìn)行完直方圖均衡化之后,圖片背景的對比度被改變了。但是你再對比一下兩幅圖像中雕像的面圖,由于太亮我們丟失了很多信息。
原理:
為了解決這個(gè)問題,我們需要使用自適應(yīng)的直方圖均衡化CLAHE (Contrast Limited Adaptive Histogram Equalization)。這種情況下,整幅圖像會(huì)被分成很多小塊,這些小塊被稱為“tiles”(在 OpenCV 中 tileGridSize默認(rèn)是 8x8),然后再對每一個(gè)小塊分別進(jìn)行直方圖均衡化(跟前面類似)。所以在每一個(gè)的區(qū)域中,直方圖會(huì)集中在某一個(gè)小的區(qū)域中(除非有噪聲干擾)。如果有噪聲的話,噪聲會(huì)被放大。為了避免這種情況的出現(xiàn),要使用對比度限制。
CLAHE中,每一個(gè)像素鄰域都要進(jìn)行對比度限制,從而得到對應(yīng)的變換函數(shù),被用來降低AHE中噪聲的增強(qiáng),這主要是通過限制AHE中的對比度增強(qiáng)來實(shí)現(xiàn)的。像素周圍鄰域噪聲的增強(qiáng)主要是由變換函數(shù)的斜率造成的,由于像素鄰域的噪聲與鄰域的CDF成正比,因此也與鄰域直方圖在該中心像素位置的值成正比,CLAHE之所以能夠限制對比度,是因?yàn)樗谟?jì)算鄰域的CDF之前在指定閾值處對直方圖進(jìn)行了修剪,如下圖所示,這一做法不僅限制了CDF的斜率,也限制了變換函數(shù)的斜率,其中對直方圖進(jìn)行切割所使用的閾值,被稱作修剪限制度(clip limit),這個(gè)參數(shù)不僅依賴于直方圖的歸一化,而且依賴于像素鄰域的size大小,通常設(shè)為3到4之間。
對于每個(gè)小塊來說,如果直方圖中的 bin 超過對比度的上限的話,就把其中的像素點(diǎn)均勻分散到其他 bins 中,然后在進(jìn)行直方圖均衡化。最后,為了去除每一個(gè)小塊之間“人造的”(由于算法造成)邊界,再使用雙線性差值,與原圖做圖層濾色混合操作(可選)。
實(shí)現(xiàn):
def img_show(name,image):
"""matplotlib圖像顯示函數(shù)
name:字符串,圖像標(biāo)題
img:numpy.ndarray,圖像
"""
if len(image.shape) == 3:
image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
plt.imshow(image,'gray')
plt.xticks([])
plt.yticks([])
plt.xlabel(name,fontproperties='FangSong',fontsize=12)
if __name__=="__main__":
img = cv2.imread("data/tsukuba_l.jpg",0)
hist,bins = np.histogram(img.flatten(),256,[0,256])
#print(hist)
#查看累積直方圖
cdf = hist.cumsum()
cdf_normalized = cdf*hist.max() / cdf.max()
#print(cdf_normalized)
#均衡化
clahe = cv2.createCLAHE(clipLimit =2.0,tileGridSize=(8,8))
equ = clahe.apply(img)
hist1,bins1 = np.histogram(equ.flatten(),256,[0,256])
#print(hist)
#查看均衡化后的累積直方圖
cdf1 = hist1.cumsum()
cdf_normalized1 = cdf1*hist1.max() / cdf1.max()
#顯示圖像結(jié)果
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(221)
img_show('原圖',img)
plt.subplot(222)
img_show('自適應(yīng)均衡化',equ)
plt.subplot(223)
plt.plot(cdf_normalized,color='b')
plt.hist(img.flatten(),256,[0,256],color='r')
plt.xlabel('相應(yīng)的直方圖(紅)和累積直方圖(藍(lán))',fontproperties='FangSong',fontsize=15)
plt.xlim([0,256])
plt.legend(('cdf','historgram'),loc = 'upper left')
plt.subplot(224)
plt.plot(cdf_normalized1,color='b')
plt.hist(equ.flatten(),256,[0,256],color='r')
plt.xlabel('自適應(yīng)均衡化直方圖',fontproperties='FangSong',fontsize=15)
plt.xlim([0,256])
plt.legend(('cdf','historgram'),loc = 'upper left')
plt.show()
參考文獻(xiàn):
網(wǎng)址:直方圖均衡化
Adaptive_histogram_equalization
書籍:《數(shù)字圖像處理》《OpenCV-Python 中文教程》