在Opencv中直方圖的繪制

直方圖

什么是直方圖呢?

直方圖是對數(shù)據(jù)集合統(tǒng)計,并將統(tǒng)計結(jié)果分布于一系列定義的bins中。這里的數(shù)據(jù)不僅僅是灰度值,統(tǒng)計數(shù)據(jù)可能是任何能夠有效描述圖像的特征,例如顏色、梯度/邊緣、形狀、紋理、局部特征點、視覺詞匯等。

灰度直方圖

通過直方圖你可以對整幅圖像的灰度分布有一個整體的了解。直方圖的 x 軸是灰度值(0 到 255),y 軸是圖片中具有同一個灰度值的點的數(shù)目。
灰度直方圖其實就是對圖像的另一種解釋。通過直方圖我們可以對圖像的對比度,亮度,灰度分布等有一個直觀的認(rèn)識。幾乎所有的圖像處理軟件都提供了直方圖分析功能。在這里,直方圖是根據(jù)灰度圖像繪制的,而不是彩色圖像。直方圖的左邊區(qū)域像是了暗一點的像素數(shù)量,右側(cè)顯示了亮一點的像素的數(shù)量。

灰度直方圖.png

使用OpenCV 統(tǒng)計直方圖函數(shù) cv2.calcHist 可以幫助我們統(tǒng)計一幅圖像的直方圖。

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

參數(shù)意義如下:

  • images: 原圖像(圖像格式為 uint8 或 ?oat32)。當(dāng)傳入函數(shù)時應(yīng)該用中括號 [] 括起來,例如:[img]。

  • channels: 同樣需要用中括號括起來,它會告訴函數(shù)我們要統(tǒng)計那幅圖像的直方圖。如果輸入圖像是灰度圖,它的值就是 [0];如果是彩色圖像的話,傳入的參數(shù)可以是 [0],[1],[2] 它們分別對應(yīng)著通道 B,G,R。

  • mask: 掩模圖像。要統(tǒng)計整幅圖像的直方圖就把它設(shè)為 None。但是如果你想統(tǒng)計圖像某一部分的直方圖的話,你就需要制作一個掩模圖像,并使用它。(后邊有例子)

  • histSize:BIN 的數(shù)目。也應(yīng)該用中括號括起來,例如:[256]。

  • ranges: 像素值范圍,通常為 [0,256]

例子:以灰度格式加載一幅圖像并統(tǒng)計圖像的直方圖

import cv2
import matplotlib.pyplot as plt
import numpy as np

def img_show(name,img):
    """matplotlib圖像顯示函數(shù)
    name:字符串,圖像標(biāo)題
    img:numpy.ndarray,圖像
    """
    if len(img.shape) == 3:
        img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    plt.imshow(img,'gray')
    #plt.xticks([])
    #plt.yticks([])
    plt.xlabel(name,fontproperties='FangSong',fontsize=12)
    

if __name__=="__main__":

    img1 = cv2.imread("cute-dog.jpg",0)
    #別忘了中括號[img1],[0],None,[256],[0,256],只有mask沒有中括號
    hist = cv2.calcHist([img1],[0],None,[256],[0,256])
      
    plt.figure(figsize=(12,8),dpi=80)
    plt.subplot(121)
    img_show('原圖',img1)
    plt.subplot(122)
    plt.plot(hist)
    plt.xlim([0,256])
    plt.ylim([0,800000])
    plt.xlabel('直方圖',fontproperties='FangSong',fontsize=12)
直方圖1.png

使用 Matplotlib Matplotlib 中有直方圖繪制函數(shù):matplotlib.pyplot.hist()它可以直接統(tǒng)計并繪制直方圖。

img1 = cv2.imread("cute-dog.jpg",0)

plt.figure(figsize=(12,8),dpi=80)
plt.subplot(121)
img_show('原圖',img1)
plt.subplot(122)
plt.hist(img1.ravel(),256,[0,256])
plt.xlim([0,256])
plt.xlabel('直方圖',fontproperties='FangSong',fontsize=12)
直方圖2.png

例子:繪制BGR通道直方圖

img1 = cv2.imread("cute-dog.jpg")
color = ('b','g','r')
# 對一個列表或數(shù)組既要遍歷索引又要遍歷元素時
# 使用內(nèi)置enumerrate函數(shù)會有更加直接,優(yōu)美的做法
# enumerate會將數(shù)組或列表組成一個索引序列。
# 使我們再獲取索引和索引內(nèi)容的時候更加方便
for i,col in enumerate(color):
    print(i)
    print(col)
    hist = cv2.calcHist([img1],[i],None,[256],[0,256])
    plt.plot(hist,color=col)
    plt.xlim([0,256])
    plt.ylim([0,800000])
plt.show()
直方圖3.png
img1 = cv2.imread("cute-dog.jpg")
color = ('b','g','r')

for i,col in enumerate(color):
    
    plt.hist(img1[:,:,i].ravel(),256,[0,256],color=col,alpha=1)
    plt.xlim([0,256])
    plt.ylim([0,800000])
plt.show()
直方圖4.png

使用掩模
要統(tǒng)計圖像某個局部區(qū)域的直方圖只需要構(gòu)建一副掩模圖像。將要統(tǒng)計的部分設(shè)置成白色,其余部分為黑色,就構(gòu)成了一副掩模圖像。然后把這個掩模圖像傳給函數(shù)就可以了。

例子:統(tǒng)計圖像某個局部區(qū)域的直方圖

img1 = cv2.imread("cute-dog.jpg")
img = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)

# 創(chuàng)建掩膜
mask = np.zeros(img.shape[:2],np.uint8)
mask[1000:4000,100:3200] = 255
img_mask = cv2.bitwise_and(img,img,mask =mask)

# 創(chuàng)建一個掩膜和一個無掩膜的直方圖
hist_full = cv2.calcHist([img],[0],None,[256],[0,256])
hist_mask = cv2.calcHist([img_mask],[0],mask,[256],[0,256])

plt.figure(figsize=(10,8),dpi=80)
plt.subplot(221)
plt.imshow(img,'gray')
plt.subplot(222)
plt.imshow(mask,'gray')
plt.subplot(223)
plt.imshow(img_mask,'gray')
plt.subplot(224)
plt.plot(hist_full,label='original')
plt.plot(hist_mask,label='img_mask')
plt.legend()
plt.xlim([0,256])
plt.ylim([0,800000])
局部直方圖.png

例子

img1 = cv2.imread("empire.jpg")
chans = cv2.split(img1)
colors = ('b','g','r')

plt.figure(figsize=(15,5),dpi=150)
plt.subplot(121)
img_show('原圖',img1)
plt.subplot(122)
for (chan,color) in zip (chans,colors):
    hist = cv2.calcHist([chan],[0],None,[256],[0,256])
    plt.plot(hist,color=color)
    plt.xlim([0,256])
plt.xlabel('彩色直方圖',fontproperties='FangSong',fontsize=12)
彩色直方圖.png
img1 = cv2.imread("empire.jpg")
chans = cv2.split(img1)
colors = ('b','g','r')

plt.figure(figsize=(18,5),dpi=80)
plt.subplot(131)
hist =cv2.calcHist([chans[1],chans[0]],[0,1],None,[32,32],[0,256,0,256])

plt.title('G和B的二維彩色直方圖',fontproperties='FangSong',fontsize=12)
plt.colorbar(plt.imshow(hist,interpolation= 'nearest'))

plt.subplot(132)
hist =cv2.calcHist([chans[1],chans[2]],[0,1],None,[32,32],[0,256,0,256])
plt.title('G和R的二維彩色直方圖',fontproperties='FangSong',fontsize=12)
plt.colorbar(plt.imshow(hist,interpolation= 'nearest'))

plt.subplot(133)
hist =cv2.calcHist([chans[0],chans[2]],[0,1],None,[32,32],[0,256,0,256])
plt.title('B和R的二維彩色直方圖',fontproperties='FangSong',fontsize=12)
plt.colorbar(plt.imshow(hist,interpolation= 'nearest'))

print('二維直方圖形狀:%s,和%s'%(hist.shape,hist.flatten().shape[0]))

二維彩色直方圖.png

第一個是綠色和藍(lán)色通道的二維顏色直方圖,第二個是綠色和紅色,第三個是藍(lán)色和紅色。
藍(lán)色陰影表示低像素計數(shù),而黃色陰影表示高像素計數(shù)(即2D直方圖中的峰值)。

參考資料:
網(wǎng)址:Matplotlib基礎(chǔ)教程
書籍:《數(shù)字圖像處理》《OpenCV-Python-Toturial-中文版》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容