前言
本小節(jié)我們要學(xué)習(xí)直方圖均衡化的概念,以及如何使用它來(lái)改善圖片的對(duì)比。
一、原理
想象一下如果一副圖像中的大多是像素點(diǎn)的像素值都集中在一個(gè)像素值范圍之內(nèi)會(huì)怎樣呢?例如,如果一幅圖片整體很亮,那所有的像素值應(yīng)該都會(huì)很高。但是一副高質(zhì)量的圖像的像素值分布應(yīng)該很廣泛。所以你應(yīng)該把它的直方圖做一個(gè)橫向拉伸(如下圖),這就是直方圖均衡化要做的事情。通常情況下這種操作會(huì)改善圖像的對(duì)比度。
推薦你去讀讀維基百科中關(guān)于直方圖均衡化的條目。其中的解釋非常給力,讀完之后相信你就會(huì)對(duì)整個(gè)過(guò)程有一個(gè)詳細(xì)的了解了。我們先看看怎樣使用Numpy 來(lái)進(jìn)行直方圖均衡化,然后再學(xué)習(xí)使用 OpenCV 進(jìn)行直方圖均衡化。
# -*- coding: utf-8 -*-
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('wiki.png', 0)
# flatten() 將數(shù)組變成一維
hist, bins = np.histogram(img.flatten(), 256, [0, 256])
# 計(jì)算累積分布圖
plt.figure()
plt.subplot(1,2,1)
plt.imshow(img, cmap = 'gray', interpolation = 'bicubic')
plt.xticks([]), plt.yticks([]) # to hide tick values on X and Y axis
plt.tight_layout()
plt.subplot(1,2,2)
cdf = hist.cumsum()
cdf_normalized = cdf * hist.max() / cdf.max()
plt.plot(cdf_normalized, color='b')
plt.hist(img.flatten(), 256, [0, 256], color='r')
plt.xlim([0, 256])
plt.legend(('cdf', 'histogram'), loc='upper left')
plt.tight_layout()
plt.show()
我們可以看出來(lái)直方圖大部分在灰度值較高的部分,而且分布很集中。而我們希望直方圖的分布比較分散,能夠涵蓋整個(gè) x 軸。所以,我們就需要一個(gè)變換函數(shù)幫助我們把現(xiàn)在的直方圖映射到一個(gè)廣泛分布的直方圖中。這就是直方圖均衡化要做的事情。
圖均衡化要做的事情。我們現(xiàn)在要找到直方圖中的最小值(除了 0),并把它用于 wiki 中的直方圖均衡化公式。但是我在這里使用了 Numpy 的掩模數(shù)組。對(duì)于掩模數(shù)組的所有操作都只對(duì) non-masked 元素有效。你可以到 Numpy 文檔中獲取更多掩模數(shù)組的信息。
# 構(gòu)建 Numpy 掩模數(shù)組,cdf 為原數(shù)組,當(dāng)數(shù)組元素為 0 時(shí),掩蓋(計(jì)算時(shí)被忽略)。
cdf_m = np.ma.masked_equal(cdf,0)
cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
# 對(duì)被掩蓋的元素賦值,這里賦值為 0
cdf = np.ma.filled(cdf_m,0).astype('uint8')
現(xiàn)在就獲得了一個(gè)表,我們可以通過(guò)查表得知與輸入像素對(duì)應(yīng)的輸出像素的值。我們只需要把這種變換應(yīng)用到圖像上就可以了。
img2 = cdf[img]
我們?cè)俑鶕?jù)前面的方法繪制直方圖和累積分布圖,結(jié)果如下:
另一個(gè)重要的特點(diǎn)是,即使我們的輸入圖片是一個(gè)比較暗的圖片(不象上邊我們用到到的整體都很亮的圖片),在經(jīng)過(guò)直方圖均衡化之后也能得到相同的結(jié)果。因此,直方圖均衡化經(jīng)常用來(lái)使所有的圖片具有相同的亮度條件的參考工具。這在很多情況下都很有用。例如,臉部識(shí)別,在訓(xùn)練分類(lèi)器前,訓(xùn)練集的所有圖片都要先進(jìn)行直方圖均衡化從而使它們達(dá)到相同的亮度條件。
二、 OpenCV 中的直方圖均衡化
OpenCV 中的直方圖均衡化函數(shù)為 cv2.equalizeHist()。這個(gè)函數(shù)的輸入圖片僅僅是一副灰度圖像,輸出結(jié)果是直方圖均衡化之后的圖像。
下邊的代碼還是對(duì)上邊的那幅圖像進(jìn)行直方圖均衡化:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('wiki.png', 0)
equ = cv2.equalizeHist(img)
res = np.hstack((img, equ))
plt.figure()
plt.imshow(res, cmap='gray', interpolation='bicubic')
plt.xticks([]), plt.yticks([]) # to hide tick values on X and Y axis
plt.show()
現(xiàn)在你可以拿一些不同亮度的照片自己來(lái)試一下了。
當(dāng)直方圖中的數(shù)據(jù)集中在某一個(gè)灰度值范圍內(nèi)時(shí),直方圖均衡化很有用。但是如果像素的變化很大,而且占據(jù)的灰度范圍非常廣時(shí),例如:既有很亮的像素點(diǎn)又有很暗的像素點(diǎn)時(shí)。
三、 CLAHE 有限對(duì)比適應(yīng)性直方圖均衡化
我們?cè)谏线呑龅闹狈綀D均衡化會(huì)改變整個(gè)圖像的對(duì)比度,但是在很多情況下,這樣做的效果并不好。例如,下圖分別是輸入圖像和進(jìn)行直方圖均衡化之后的輸出圖像。
的確在進(jìn)行完直方圖均衡化之后,圖片背景的對(duì)比度被改變了。但是你再對(duì)比一下兩幅圖像中雕像的面圖,由于太亮我們丟失了很多信息。造成這種結(jié)果的根本原因在于這幅圖像的直方圖并不是集中在某一個(gè)區(qū)域(試著畫(huà)出它的直方圖,你就明白了)。
為了解決這個(gè)問(wèn)題,我們需要使用自適應(yīng)的直方圖均衡化。這種情況下,整幅圖像會(huì)被分成很多小塊,這些小塊被稱為“tiles”(在 OpenCV 中 tiles 的大小默認(rèn)是 8x8),然后再對(duì)每一個(gè)小塊分別進(jìn)行直方圖均衡化(跟前面類(lèi)似)。所以在每一個(gè)的區(qū)域中,直方圖會(huì)集中在某一個(gè)小的區(qū)域中(除非有噪聲干擾)。如果有噪聲的話,噪聲會(huì)被放大。為了避免這種情況的出現(xiàn)要使用對(duì)比度限制。對(duì)于每個(gè)小塊來(lái)說(shuō),如果直方圖中的 bin 超過(guò)對(duì)比度的上限的話,就把其中的像素點(diǎn)均勻分散到其他 bins 中,然后在進(jìn)行直方圖均衡化。最后,為了去除每一個(gè)小塊之間“人造的”(由于算法造成)邊界,再使用雙線性差值,對(duì)小塊進(jìn)行縫合。
下面的代碼顯示了如何使用 OpenCV 中的 CLAHE。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-741971.html
# -*- coding: utf-8 -*-
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('tsukuba_l.png', 0)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(img)
res = np.hstack((img, cl1))
plt.figure()
plt.imshow(res, cmap='gray', interpolation='bicubic')
plt.xticks([]), plt.yticks([]) # to hide tick values on X and Y axis
plt.show()
下面就是結(jié)果了,與前面的結(jié)果對(duì)比一下,尤其是雕像區(qū)域:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-741971.html
到了這里,關(guān)于OpenCV官方教程中文版 —— 直方圖均衡化的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!