OpenCV-Python 直方圖-1:查找、繪製和分析

目標

學會

  • 使用OpenCV和Numpy函數查找直方圖
  • 使用OpenCV和Matplotlib函數繪製直方圖
  • 你將看到以下函數:cv.calcHist(),np.histogram()等。

理論

那麼直方圖是什麼?您可以將直方圖視為圖形或繪圖,從而可以總體瞭解圖像的強度分佈。它是在X軸上具有像素值(不總是從0到255的範圍),在Y軸上具有圖像中相應像素數的圖。

這只是理解圖像的另一種方式。通過查看圖像的直方圖,您可以直觀地瞭解該圖像的對比度,亮度,強度分佈等。當今幾乎所有圖像處理工具都提供直方圖功能。以下是劍橋彩色網站的圖片,我建議您訪問該網站以獲取更多詳細信息。

OpenCV-Python 直方圖-1:查找、繪製和分析 | 二十六

您可以看到圖像及其直方圖。(請記住,此直方圖是針對灰度圖像而非彩色圖像繪製的)。直方圖的左側區域顯示圖像中較暗像素的數量,而右側區域則顯示明亮像素的數量。從直方圖中,您可以看到暗區域多於亮區域,而中間調的數量(中間值的像素值,例如127附近)則非常少。

尋找直方圖

現在我們有了一個關於直方圖的想法,我們可以研究如何找到它。OpenCV和Numpy都為此內置了功能。在使用這些功能之前,我們需要了解一些與直方圖有關的術語。

BINS:上面的直方圖顯示每個像素值的像素數,即從0到255。即,您需要256個值來顯示上面的直方圖。但是考慮一下,如果您不需要分別找到所有像素值的像素數,而是找到像素值間隔中的像素數怎麼辦?例如,您需要找到介於0到15之間的像素數,然後找到16到31之間,...,240到255之間的像素數。只需要16個值即可表示直方圖。這就是在OpenCV教程中有關直方圖的示例中顯示的內容。

因此,您要做的就是將整個直方圖分成16個子部分,每個子部分的值就是其中所有像素數的總和。每個子部分都稱為“ BIN”。在第一種情況下,bin的數量為256個(每個像素一個),而在第二種情況下,bin的數量僅為16個。BINS由OpenCV文檔中的

histSize術語表示。

DIMS:這是我們為其收集數據的參數的數量。在這種情況下,我們僅收集關於強度值的一件事的數據。所以這裡是1。

RANGE:這是您要測量的強度值的範圍。通常,它是[0,256],即所有強度值。

1. OpenCV中的直方圖計算

因此,現在我們使用cv.calcHist()函數查找直方圖。讓我們熟悉一下該函數及其參數:

cv.calcHist(images,channels,mask,histSize,ranges [,hist [,accumulate]])

  1. images:它是uint8或float32類型的源圖像。它應該放在方括號中,即“ [img]”。
  2. channels:也以方括號給出。它是我們計算直方圖的通道的索引。例如,如果輸入為灰度圖像,則其值為[0]。對於彩色圖像,您可以傳遞[0],[1]或[2]分別計算藍色,綠色或紅色通道的直方圖。
  3. mask:圖像掩碼。為了找到完整圖像的直方圖,將其指定為“無”。但是,如果要查找圖像特定區域的直方圖,則必須為此創建一個掩碼圖像並將其作為掩碼。(我將在後面顯示一個示例。)
  4. histSize:這表示我們的BIN計數。需要放在方括號中。對於全尺寸,我們通過[256]。
  5. ranges:這是我們的RANGE。通常為[0,256]。

因此,讓我們從示例圖像開始。只需以灰度模式加載圖像並找到其完整直方圖即可。

img = cv.imread('home.jpg',0)hist = cv.calcHist([img],[0],None,[256],[0,256])

hist是256x1的數組,每個值對應於該圖像中具有相應像素值的像素數。

2. numpy的直方圖計算

Numpy還為您提供了一個函數np.histogram()。因此,除了calcHist()函數外,您可以嘗試下面的代碼:

hist,bins = np.histogram(img.ravel(),256,[0,256])

hist與我們之前計算的相同。但是bin將具有257個元素,因為Numpy計算出bin的範圍為0-0.99、1-1.99、2-2.99等。因此最終範圍為255-255.99。為了表示這一點,他們還在最後添加了256。但是我們不需要256。最多255就足夠了。

  • 另外
    Numpy還有另一個函數np.bincount(),它比np.histogram()快10倍左右。因此,對於一維直方圖,您可以更好地嘗試一下。不要忘記在np.bincount中設置minlength = 256。例如,hist = np.bincount(img.ravel(),minlength = 256)

注意
OpenCV函數比np.histogram()快大約40倍。因此,儘可能使用OpenCV函數。

現在我們應該繪製直方圖,但是怎麼繪製?

繪製直方圖

有兩種方法,

  1. 簡短的方法:使用Matplotlib繪圖功能
  2. 稍長的方法:使用OpenCV繪圖功能

1. 使用Matplotlib

Matplotlib帶有直方圖繪圖功能:matplotlib.pyplot.hist()它直接找到直方圖並將其繪製。您無需使用calcHist()或np.histogram()函數來查找直方圖。請參見下面的代碼:

import numpy as npimport cv2 as cvfrom matplotlib import pyplot as pltimg = cv.imread('home.jpg',0)plt.hist(img.ravel(),256,[0,256]); plt.show()

你將得到如下的結果:

OpenCV-Python 直方圖-1:查找、繪製和分析 | 二十六

或者,您可以使用matplotlib的法線圖,這對於BGR圖是很好的。為此,您需要首先找到直方圖數據。試試下面的代碼:

import numpy as npimport cv2 as cvfrom matplotlib import pyplot as pltimg = cv.imread('home.jpg')color = ('b','g','r')for i,col in enumerate(color):    histr = cv.calcHist([img],[i],None,[256],[0,256])    plt.plot(histr,color = col)    plt.xlim([0,256])plt.show()

結果:

OpenCV-Python 直方圖-1:查找、繪製和分析 | 二十六

您可以從上圖中得出,藍色在圖像中具有一些高值域(顯然這應該是由於天空)

2. 使用 OpenCV

好吧,在這裡您可以調整直方圖的值及其bin值,使其看起來像x,y座標,以便您可以使用cv.line()或cv.polyline()函數繪製它以生成與上述相同的圖像。OpenCV-Python2官方示例已經提供了此功能。檢查示例/python/hist.py中的代碼。

掩碼的應用

我們使用了cv.calcHist()來查找整個圖像的直方圖。如果你想找到圖像某些區域的直方圖呢?只需創建一個掩碼圖像,在你要找到直方圖為白色,否則黑色。然後把這個作為掩碼傳遞。

img = cv.imread('home.jpg',0)# create a maskmask = np.zeros(img.shape[:2], np.uint8)mask[100:300, 100:400] = 255masked_img = cv.bitwise_and(img,img,mask = mask)# 計算掩碼區域和非掩碼區域的直方圖# 檢查作為掩碼的第三個參數hist_full = cv.calcHist([img],[0],None,[256],[0,256])hist_mask = cv.calcHist([img],[0],mask,[256],[0,256])plt.subplot(221), plt.imshow(img, 'gray')plt.subplot(222), plt.imshow(mask,'gray')plt.subplot(223), plt.imshow(masked_img, 'gray')plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask)plt.xlim([0,256])plt.show()

查看結果。在直方圖中,藍線表示完整圖像的直方圖,綠線表示掩碼區域的直方圖。

OpenCV-Python 直方圖-1:查找、繪製和分析 | 二十六

附加資源

  1. Cambridge in Color website:http://www.cambridgeincolour.com/tutorials/histograms1.htm


分享到:


相關文章: