理論
什么是histogram讹躯?它可以給出圖像的密度分布的總體概念顶考,它的x軸是像素值(0到255)y軸是對(duì)應(yīng)的像素在圖像里的數(shù)量。
看histogram你可以得到對(duì)比度并齐,亮度漏麦,密度分布等直觀信息客税。今天的所有圖像處理工具都提供了histogram屬性,
你可以看到圖像和他的histogram(記住這里的histogram是對(duì)于灰度圖的撕贞,不是彩色圖)更耻,histogram左邊的區(qū)域顯示出暗的像素的數(shù)量,右邊的區(qū)域顯示了亮的像素的數(shù)量捏膨,從這里可以得出暗的區(qū)域比亮區(qū)多秧均,而中間亮度的很少。
找到Histogram
現(xiàn)在我們知道了什么是histogram号涯,我們來(lái)看看怎么得到它目胡,OpenCV和Numpy都內(nèi)嵌了函數(shù)來(lái)干這個(gè)。在用之前我們需要知道一些相關(guān)術(shù)語(yǔ)链快。
BINS:上面的histogram顯示了每個(gè)像素值的數(shù)量誉己,比如從0到255,你需要256個(gè)值來(lái)顯示上面的histogram域蜗。如果你不需要找各個(gè)像素的數(shù)量巨双,而是需要某個(gè)間隔內(nèi)的像素值得數(shù)量。比如你需要找到0到15之間的像素的數(shù)量霉祸,然后16到31的,...筑累,240到255,你值需要16個(gè)值來(lái)表示histogram脉执。
所以你需要做的只是把整個(gè)histogram分割成16個(gè)子部分疼阔,統(tǒng)計(jì)每個(gè)子部分內(nèi)的所有像素的數(shù)量。每個(gè)子部分被叫做"BIN"半夷。在第一個(gè)例子里,bins的數(shù)量是256迅细。第二個(gè)例子里巫橄,BINS是16個(gè)。BINS由histSize來(lái)表示茵典。
DIMS:這是我們手機(jī)的數(shù)據(jù)的參數(shù)的數(shù)量湘换,在這個(gè)例子里,我們收集的數(shù)據(jù)只有一個(gè)屬性:亮度统阿。所以這里是1.
RANGE:這是你要統(tǒng)計(jì)的亮度值得范圍彩倚,一般是[0,256], 所有值。
1.OpenCV Histogram 計(jì)算
所以現(xiàn)在我們使用cv2.calcHist()函數(shù)來(lái)找histogram扶平。
cv2.calcHist(images, channels, mask, histSize, ranges[,hist[,accumulate]])
1.images:這是uint8或者float32的原圖帆离。應(yīng)該是方括號(hào)方式傳入:“[img]”
2.channels:也是用方括號(hào)給出的,我們計(jì)算histogram的channel的索引结澄,比如哥谷,如果輸入時(shí)灰度圖岸夯,值就是[0],對(duì)于彩色圖片们妥,你可以傳[0],[1]和[2]來(lái)分別計(jì)算藍(lán)色猜扮,綠色和紅色通道的histogram。
3.mask:掩圖监婶,要找到整個(gè)圖像的histogram旅赢,這里傳入"None"。但是如果你想找到特定區(qū)域圖片的histogram惑惶,就得創(chuàng)建一個(gè)掩圖
4.histSize:BIN數(shù)量鲜漩,需要用戶方括號(hào)傳入,對(duì)于全刻度集惋,我們傳入[256].
5.ranges:RANGE孕似,一般來(lái)說(shuō)是[0,256].
來(lái)一個(gè)例子,簡(jiǎn)單的用灰度模式加載一個(gè)圖像然后找他的histogram刮刑。
img=cv2.imread('home.jpg',0)
hist=cv2.calcHist([img],[0],None,[256],[0,256])
hist是256x1數(shù)組喉祭,每個(gè)值對(duì)應(yīng)圖像里的像素?cái)?shù)量。
2.Numpy里的Histogram計(jì)算
Numpy也提供了函數(shù)np.histogram()雷绢。
hist,bins=np.histogram(img.ravel(),256,[0,256])
hist和我們前面計(jì)算的一樣泛烙,但是bins有257個(gè)元素,因?yàn)镹umpy計(jì)算bins是0-0.99,1-1.99,2-2.99翘紊,所以最后的范圍是255-255.99.要表示這個(gè)蔽氨,最后還加了256.但是我們不需要256.
Numpy還有另一個(gè)函數(shù)np.bincount(),比np.histogram()要快很多(10倍)帆疟。所以對(duì)于一個(gè)維度的Histogram鹉究,你可以試試,不要在np.bincount里忘記設(shè)置minlength=256踪宠。比如 hist = np.bincount(img.ravel(), minlength=256)
注意:
OpenCV函數(shù)要比np.histogram()要快很多(40x)自赔。所以還是用OpenCV函數(shù)。
繪制Histograms
有兩個(gè)方法:
1.短方法:使用Matplotlib繪制函數(shù)
2.長(zhǎng)方法:使用OpenCV繪制函數(shù)
1.使用Matplotlib
Matplotlib有一個(gè)繪制histogram函數(shù):matplotlib.pyplot.hist()
它直接找到histogram然后繪制柳琢。你不需要用calcHist()或者np.histogram()函數(shù)來(lái)找histogram绍妨。
import cv2
import numpy as np
from matplotlib import pyplot as pltimg = cv2.imread('home.jpg',0)
plt.hist(img.ravel(),256,[0,256]); plt.show()
或者你可以使用matplotlib的普通繪圖,對(duì)于BGR繪圖不錯(cuò)柬脸,但你需要先找到histogram他去。
import cv2
import numpy as np
from matplotlib import pyplot as pltimg = cv2.imread('home.jpg')
color = ('b','g','r')
for i,col in enumerate(color):
? ? histr = cv2.calcHist([img],[i],None,[256],[0,256])
? ? plt.plot(histr,color = col)
? ? plt.xlim([0,256])
plt.show()
你可以從上面的圖看出,藍(lán)色在圖像里值很高倒堕。
2.使用OpenCV
你調(diào)整了histogram的值灾测,你可以用cv2.line()或者cv2.polyline()函數(shù)來(lái)生成
使用Mask
我們使用cv2.calcHist()來(lái)找整個(gè)圖的histogram。如果你想找某個(gè)區(qū)域的histogram涩馆,就創(chuàng)建一個(gè)你想要的區(qū)域是白色而其他地方是黑色的mask圖像行施。
img = cv2.imread('home.jpg',0)
# create a mask
mask = np.zeros(img.shape[:2], np.uint8)
mask[100:300, 100:400] = 255
masked_img = cv2.bitwise_and(img,img,mask = mask)# Calculate histogram with mask and without mask
# Check third argument for mask
hist_full = cv2.calcHist([img],[0],None,[256],[0,256])
hist_mask = cv2.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()
下面的結(jié)果里允坚,在histogram圖上,藍(lán)線顯示了全圖的histogram蛾号,綠色線顯示了mask區(qū)域的histogram.
END