Python OpenCV 直方圖的計(jì)算與顯示的方法示例
本篇文章介紹如何用OpenCV Python來計(jì)算直方圖,并簡(jiǎn)略介紹用NumPy和Matplotlib計(jì)算和繪制直方圖
直方圖的背景知識(shí)、用途什么的就直接略過去了。這里直接介紹方法。
計(jì)算并顯示直方圖
與C++中一樣,在Python中調(diào)用的OpenCV直方圖計(jì)算函數(shù)為cv2.calcHist。
cv2.calcHist的原型為:
cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate ]]) #返回hist
通過一個(gè)例子來了解其中的各個(gè)參數(shù):
#coding=utf-8 import cv2 import numpy as np image = cv2.imread("D:/histTest.jpg", 0) hist = cv2.calcHist([image], [0], #使用的通道 None, #沒有使用mask [256], #HistSize [0.0,255.0]) #直方圖柱的范圍
其中第一個(gè)參數(shù)必須用方括號(hào)括起來。
第二個(gè)參數(shù)是用于計(jì)算直方圖的通道,這里使用灰度圖計(jì)算直方圖,所以就直接使用第一個(gè)通道;
第三個(gè)參數(shù)是Mask,這里沒有使用,所以用None。
第四個(gè)參數(shù)是histSize,表示這個(gè)直方圖分成多少份(即多少個(gè)直方柱)。第二個(gè)例子將繪出直方圖,到時(shí)候會(huì)清楚一點(diǎn)。
第五個(gè)參數(shù)是表示直方圖中各個(gè)像素的值,[0.0, 256.0]表示直方圖能表示像素值從0.0到256的像素。
最后是兩個(gè)可選參數(shù),由于直方圖作為函數(shù)結(jié)果返回了,所以第六個(gè)hist就沒有意義了(待確定)
最后一個(gè)accumulate是一個(gè)布爾值,用來表示直方圖是否疊加。
彩色圖像不同通道的直方圖
下面來看下彩色圖像的直方圖處理。以最著名的lena.jpg為例,首先讀取并分離各通道:
import cv2 import numpy as np img = cv2.imread("D:/lena.jpg") b, g, r = cv2.split(img)
接著計(jì)算每個(gè)通道的直方圖,這里將其封裝成一個(gè)函數(shù):
def calcAndDrawHist(image, color): hist= cv2.calcHist([image], [0], None, [256], [0.0,255.0]) minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(hist) histImg = np.zeros([256,256,3], np.uint8) hpt = int(0.9* 256); for h in range(256): intensity = int(hist[h]*hpt/maxVal) cv2.line(histImg,(h,256), (h,256-intensity), color) return histImg;
這里只是之前代碼的簡(jiǎn)單封裝,所以注釋就省掉了。
接著在主函數(shù)中使用:
if __name__ == '__main__': img = cv2.imread("D:/lena.jpg") b, g, r = cv2.split(img) histImgB = calcAndDrawHist(b, [255, 0, 0]) histImgG = calcAndDrawHist(g, [0, 255, 0]) histImgR = calcAndDrawHist(r, [0, 0, 255]) cv2.imshow("histImgB", histImgB) cv2.imshow("histImgG", histImgG) cv2.imshow("histImgR", histImgR) cv2.imshow("Img", img) cv2.waitKey(0) cv2.destroyAllWindows()
這樣就能得到三個(gè)通道的直方圖了,如下:
更進(jìn)一步
這樣做有點(diǎn)繁瑣,參考abid rahman的做法,無(wú)需分離通道,用折線來描繪直方圖的邊界可在一副圖中同時(shí)繪制三個(gè)通道的直方圖。方法如下:
#coding=utf-8 import cv2 import numpy as np img = cv2.imread('D:/lena.jpg') h = np.zeros((256,256,3)) #創(chuàng)建用于繪制直方圖的全0圖像 bins = np.arange(256).reshape(256,1) #直方圖中各bin的頂點(diǎn)位置 color = [ (255,0,0),(0,255,0),(0,0,255) ] #BGR三種顏色 for ch, col in enumerate(color): originHist = cv2.calcHist([img],[ch],None,[256],[0,256]) cv2.normalize(originHist, originHist,0,255*0.9,cv2.NORM_MINMAX) hist=np.int32(np.around(originHist)) pts = np.column_stack((bins,hist)) cv2.polylines(h,[pts],False,col) h=np.flipud(h) cv2.imshow('colorhist',h) cv2.waitKey(0)
結(jié)果如下圖所示:
代碼說明:
這里的for循環(huán)是對(duì)三個(gè)通道遍歷一次,每次繪制相應(yīng)通道的直方圖的折線。for循環(huán)的第一行是計(jì)算對(duì)應(yīng)通道的直方圖,經(jīng)過上面的介紹,應(yīng)該很容易就能明白。
這里所不同的是沒有手動(dòng)的計(jì)算直方圖的最大值再乘以一個(gè)系數(shù),而是直接調(diào)用了OpenCV的歸一化函數(shù)。該函數(shù)將直方圖的范圍限定在0-255×0.9之間,與之前的一樣。下面的hist= np.int32(np.around(originHist))先將生成的原始直方圖中的每個(gè)元素四舍六入五湊偶取整(cv2.calcHist函數(shù)得到的是float32類型的數(shù)組),接著將整數(shù)部分轉(zhuǎn)成np.int32類型。即61.123先轉(zhuǎn)成61.0,再轉(zhuǎn)成61。注意,這里必須使用np.int32(...)進(jìn)行轉(zhuǎn)換,numpy的轉(zhuǎn)換函數(shù)可以對(duì)數(shù)組中的每個(gè)元素都進(jìn)行轉(zhuǎn)換,而Python的int(...)只能轉(zhuǎn)換一個(gè)元素,如果使用int(...),將導(dǎo)致only length-1 arrays can be converted to Python scalars錯(cuò)誤。
下面的pts = np.column_stack((bins,hist))是將直方圖中每個(gè)bin的值轉(zhuǎn)成相應(yīng)的坐標(biāo)。比如hist[0] =3,...,hist[126] = 178,...,hist[255] = 5;而bins的值為[[0],[1],[2]...,[255]]。使用np.column_stack將其組合成[0, 3]、[126, 178]、[255, 5]這樣的坐標(biāo)作為元素組成的數(shù)組。
最后使用cv2.polylines函數(shù)根據(jù)這些點(diǎn)繪制出折線,第三個(gè)False參數(shù)指出這個(gè)折線不需要閉合。第四個(gè)參數(shù)指定了折線的顏色。
當(dāng)所有完成后,別忘了用h = np.flipud(h)反轉(zhuǎn)繪制好的直方圖,因?yàn)槔L制時(shí),[0,0]在圖像的左上角。這在直方圖可視化一節(jié)中有說明。
NumPy版的直方圖計(jì)算
在查閱abid rahman的資料時(shí),發(fā)現(xiàn)他用NumPy的直方圖計(jì)算函數(shù)np.histogram也實(shí)現(xiàn)了相同的效果。如下:
#coding=utf-8 import cv2 import numpy as np img = cv2.imread('D:/lena.jpg') h = np.zeros((300,256,3)) bins = np.arange(257) bin = bins[0:-1] color = [ (255,0,0),(0,255,0),(0,0,255) ] for ch,col in enumerate(color): item = img[:,:,ch] N,bins = np.histogram(item,bins) v=N.max() N = np.int32(np.around((N*255)/v)) N=N.reshape(256,1) pts = np.column_stack((bin,N)) cv2.polylines(h,[pts],False,col) h=np.flipud(h) cv2.imshow('img',h) cv2.waitKey(0)
效果圖和上面的一個(gè)相同。NumPy的histogram函數(shù)將在NumPy通用函數(shù)這篇博文中介紹,這里就不詳細(xì)解釋了。這里采用的是與一開始相同的比例系數(shù)的方法,參考本文的第二節(jié)。
另外,通過NumPy和matplotlib可以更方便的繪制出直方圖,下面的代碼供大家參考,如果有機(jī)會(huì),再寫的專門介紹matplotlib的文章。
import matplotlib.pyplot as plt import numpy as np import cv2 img = cv2.imread('D:/lena.jpg') bins = np.arange(257) item = img[:,:,1] hist,bins = np.histogram(item,bins) width = 0.7*(bins[1]-bins[0]) center = (bins[:-1]+bins[1:])/2 plt.bar(center, hist, align = 'center', width = width) plt.show()
這里顯示的是綠色通道的直方圖。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 教你利用Python玩轉(zhuǎn)histogram直方圖的五種方法
- Python繪制頻率分布直方圖的示例
- 詳解用Python為直方圖繪制擬合曲線的兩種方法
- 詳解python OpenCV學(xué)習(xí)筆記之直方圖均衡化
- python數(shù)字圖像處理實(shí)現(xiàn)直方圖與均衡化
- python繪制直方圖和密度圖的實(shí)例
- python matplotlib庫(kù)直方圖繪制詳解
- Python Opencv中用compareHist函數(shù)進(jìn)行直方圖比較對(duì)比圖片
- opencv python統(tǒng)計(jì)及繪制直方圖的方法
- python繪制簡(jiǎn)單直方圖的方法
相關(guān)文章
python使用xlrd實(shí)現(xiàn)檢索excel中某列含有指定字符串記錄的方法
這篇文章主要介紹了python使用xlrd實(shí)現(xiàn)檢索excel中某列含有指定字符串記錄的方法,涉及Python使用xlrd模塊檢索Excel的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-05-05wxpython 最小化到托盤與歡迎圖片的實(shí)現(xiàn)方法
這篇文章主要分享一個(gè)python實(shí)例代碼,使用wxpython實(shí)現(xiàn)最小化到托盤與歡迎圖片,需要的朋友可以參考下2014-06-06詳解基于Transformer實(shí)現(xiàn)電影評(píng)論星級(jí)分類任務(wù)
這篇文章主要為大家介紹了詳解基于Transformer實(shí)現(xiàn)電影評(píng)論星級(jí)分類任務(wù)過程解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04Django 權(quán)限認(rèn)證(根據(jù)不同的用戶,設(shè)置不同的顯示和訪問權(quán)限)
這篇文章主要介紹了Django 權(quán)限認(rèn)證(根據(jù)不同的用戶,設(shè)置不同的顯示和訪問權(quán)限),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07python進(jìn)行二次方程式計(jì)算的實(shí)例講解
在本篇內(nèi)容里小編給大家整理了一篇關(guān)于python進(jìn)行二次方程式計(jì)算的實(shí)例講解內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。2020-12-12Python?Asyncio?庫(kù)之同步原語(yǔ)常用函數(shù)詳解
這篇文章主要為大家介紹了Python?Asyncio?庫(kù)之同步原語(yǔ)常用函數(shù)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03