程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

【OpenCV-Python-課程學習(賈)】OpenCV3.3課程學習筆記:圖像直方圖的計算、圖像直方圖特征的應用、直方圖反向投影、matplotlib繪制圖像直方圖

編輯:Python

圖像直方圖,本質上就是對圖像的所有像素點的取值進行統計,在不同的橫軸子區間內各有的像素點的數量作為縱軸取值。                                   

一、利用Matplotlib繪制圖像直方圖

在Matplotlib模塊中,有一個pyplot.hist函數,可以統計數組的取值在不同區間上的發生頻率,也即計算直方圖。

語法格式如下,參考官方API文檔:  

matplotlib.pyplot.hist(x, bins=None, range=None, density=False, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, stacked=False, *, data=None, **kwargs)

因為涉及到的參數很多,我們就挑重點講。

  • x是一維數組或者多個一維數組構成的序列;可以是二維數組,但不能是二維以上的數組。
  • bins是橫軸劃分參數;如果bins是一個整數,代表橫軸劃分的份數,默認取10;如果bins是一個數值序列,序列中的各個數值表示橫軸分隔點。
  • range是橫軸有效顯示范圍(計數范圍),只顯示這個范圍之內的數據。
  • density是概率密度直方圖標志,默認為False,表示縱軸的取值是子區間內數值點的數量;如果設置為True,表示直方圖和橫軸圍成的區域面積應該為1,因此需要對每個子區間的計數進行歸一化。
  • 函數返回結果是一維數組或者包括多個一維數組的序列(取決於x的類型),因為bins默認是10,所以默認每一個一維數組的長度就是10;一維數組的每一個元素取值代表在對應子區間內的次數。

下面分享一個案例。

import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread('images/lena.png')
plt.figure()
plt.subplot(1,2,1)
arr = plt.hist(img.ravel())
plt.subplot(1,2,2)
plt.imshow(img[:, :, ::-1])
plt.show()
print(img.ravel())
print(arr)
cv.waitKey()
cv.destroyAllWindows()

 

二、 利用OpenCV中的calcHist繪制

OpenCV中的calcHist函數只能用來計算圖像直方圖對應的數字信息,而無法像matplotlib.pyplot的hist函數一樣直接在執行完後還能將直方圖繪制出來。

OpenCV中的calcHist函數的語法格式如下。

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

  • images應是位深度為8位無符號整型或32位浮點型的圖像多維數組;書寫形式上應該在圖像多維數組變量兩邊加方括號,比如[img]。
  • channels是通道索引號,索引用方括號包裹;對於灰度圖,只能用[0];對於BGR三通道圖像多維數組,可以用[0]、[1]、[2],表示分別計算藍色、綠色、紅色通道上的直方圖。一次只能用一個通道進行計算,這一點與本文的第一部分不同,第一部分用的plt.hist函數允許對彩色圖進行多通道的直方圖並行計算,但是這樣的計算方式也肯定會降低直方圖特征精度。
  • mask是遮罩控制參數,如果傳入None,則不進行遮罩控制,直接對全圖進行計算;而如果需要對圖像的特定子區域進行計算,那麼可以在運行函數前構建一個遮罩層。
  • histSize代表了bin的數目,也需要用方括號包裹;比如對於uint8圖像,histSize=[255]時就對全部像素值進行單獨計數。
  • ranges是計數范圍,只有在計數范圍內的像素值才會被計入;一般來說是[0, 255]。
  • hist是一個histSize*1的數組,每一個元素代表對應的bin范圍內的像素數目(明顯是整數)。

計算得到hist後,如果想要繪制折線型直方圖,可以用plt.plot(hist)——並未涉及顏色和線型等格式的設置,只是想在這裡簡略提到,給讀者一個思路。

三、利用numpy中的histogram函數繪制

numpy中的histogram函數與OpenCV中的calcHist函數一樣,都不能直接繪直方圖,都只能得到各bin內的像素計數。

但是!!!OpenCV中的calcHist函數以及matplotlib的hist函數的bins劃分方式都是左閉右開,只有最右邊的一個區間才是全閉,比如[0, 1),[1, 0),...,[244, 255];而numpy中的histogram函數是xxx(下圖由官網截得——OpenCV: Histograms - 1 : Find, Plot, Analyze !!!)

剛開始我以為numpy的這個函數確實如官網所述,但是後來我發現完全不用將bins=256,將range=[0, 256] 。詳見下面的代碼,雖然最後的點是10,在第10個bin中還是包括了像素點10,說明最後一個bin的區間范圍是[9, 10],而不是[9, 9.99]。

import numpy as np
print(np.histogram([[1, 2, 5, 10], [1, 0, 3, 10]], bins=10, range=[0, 10]))
# (array([1, 2, 1, 1, 0, 1, 0, 0, 0, 2], dtype=int64), array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.]))

說明!!!numpy的histogram函數的bins分配機制和其他兩者相同。

下面是numpy的histogram函數的語法格式,源於numpy.histogram — NumPy v1.23 Manual

numpy.histogram(a, bins=10, range=None, normed=None, weights=None, density=None)

  • a是n維數組,注意這裡不跟matplotlib.pyplot.hist函數和cv.calcHist函數一樣,它對數組的維數沒有限制;因為在計算直方圖特性前,會對a直接進行鋪平。
  • bins是直方圖x軸子區間劃定參數;跟matplotlib.pyplot.hist函數的幾乎一樣。
  • range是計數范圍,只有在計數范圍內的像素值才會被計入;一般來說是[0, 255]。
  • normed參數已經在numpy 1.6.0被遺棄,不再建議使用。
  • weights是一個與a形狀相同的n維數組;a中的每個值僅將其關聯權重貢獻給bin計數(而不是1;意思是說如果對應的權重是2,那麼這個像素點所處的bin計數加的是2而不是1)。如果density為True,則對權重進行歸一化,以便密度在該范圍內的求和保持為1。
  • density參數跟matplotlib.pyplot.hist函數的意義一樣。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved