一、學習目標
- 了解了直方圖反向投影的一般流程
- 了解2D直方圖的使用
如有錯誤歡迎指出~
二、了解直方圖反向投影
2.1 了解2D直方圖
需要對直方圖進行反向投影,需要使用2D直方圖。2D直方圖需要使用calcHist方法。calcHist方法在前兩節中已經有了解,現在再來復習一下。首先我們查看calcHist方法的原型。
calcHist(images; channels; mask; histSize; ranges[; hist[; accumulate]])
calcHist方法中images參數為所需要傳入的圖像,接受類型為uint8以及float32,參入參數時可以使用[]對參數進行標記;
channels為傳入的通道數;
mask為一個遮罩,如果為None則表示對全圖進行操作,若選擇其中一個部分就需要制作一個遮罩對局部進行操作;
histSize為一個范圍,或者說是BIN的數目;
ranges表示像素值范圍。
我們要繪制一個顏色直方圖的話,需要對BGR色彩空間進行轉換,轉換為HSV:
import cv2
import numpy as np
from matplotlib import pyplot as pltimg = cv2.imread(r'C:\Users\mx\Desktop\1.jpg')hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
隨后我們使用calcHist方法傳入數值,這個時候channels應該為[0,1],mask我們依舊為None,因為我們需要處理全圖;而histSize則表示了兩個通道,H以及S,所以應該寫成[180,256],即H通道為180,S通道為256,最后一個range則為[0,180,0,256],表示H取值范圍在和S的取值范圍。那么整體的代碼如下:
import cv2
import numpy as np
from matplotlib import pyplot as pltimg = cv2.imread(r'C:\Users\mx\Desktop\1.jpg')hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)hist = cv2.calcHist([hsv], [0,1], None, [180,256], [0,180,0,256])plt.imshow(hist, interpolation='nearest')
plt.show()
結果如下:
2.2 了解直方圖反向投影
直方圖反向投影可以在圖像中找到我們感應區的部分,直方圖反向投影將會輸出模板圖像中類似的部分,越亮的的部分則表示得越白。我們需要完成這個操作首先得有一張需要查找的對象,隨后需要一張圖為查找區域。我們可以先對需要查找目標的圖像創建一個直方圖,隨后進行歸一化處理。歸一化處理使用normalize方法。
首先我們進行讀取圖片與轉換HSV色彩空間圖,也順帶一起讀取目標掃描的圖片,原圖和目標圖、代碼如下:
原圖:
目標圖:
roi = cv2.imread(r'C:\Users\mx\Desktop\gz\roi.png')
hsv_roi = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)
target = cv2.imread(r'C:\Users\mx\Desktop\gz\4.png')
hsv_target = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)
隨后對hsv_roi 感興趣的部分進行2D直方圖處理:
roihist = cv2.calcHist([hsv_roi],[0, 1], None, [180, 256], [0, 180, 0, 256] )
接下來使用normalize方法進行歸一化;歸一化是將數據達到一種可進行對比的標準,但是保持了原有數據間的關系。代碼為:
cv2.normalize(roihist,roihist,0,255,cv2.NORM_MINMAX)
其中roihist為輸入數據,roihist為與src大小相同的輸出數據,0為一個范圍低邊界,255為范圍的上限,cv2.NORM_MINMAX是一個歸一化的方法,表示對數組的所有值進行轉化,使值的映射在最小值和最大值之間。這樣歸一化后他們的值就在0到255之間了。接著我們使用calcBackProject方法,calcBackProject方法與calcHist的參數類似。 cvCalcBackProject 用于計算直方圖的反向投影,得到的結果是數組在某個分布下的概率。
dst = cv2.calcBackProject([hsv_target],[0,1],roihist,[0,180,0,256],1)
隨后使用getStructuringElement方法進行卷積,把分散點連接:
gSEE = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
dst=cv2.filter2D(dst,-1,gSEE)
接著使用閥值方法:
ret,thresh = cv2.threshold(dst,50,255,0)
最后進行合并:
trh = cv2.merge((trh,trh,trh))
完整代碼如下:
import cv2
import numpy as np
from matplotlib import pyplot as pltroi = cv2.imread(r'C:\Users\mx\Desktop\gz\roi.png')
hsv_roi = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)
target = cv2.imread(r'C:\Users\mx\Desktop\gz\4.png')
hsv_target = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)roihist = cv2.calcHist([hsv_roi],[0, 1], None, [180, 256], [0, 180, 0, 256] )
cv2.normalize(roihist,roihist,0,255,cv2.NORM_MINMAX)
dst = cv2.calcBackProject([hsv_target],[0,1],roihist,[0,180,0,256],1)
gSEE = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
dst=cv2.filter2D(dst,-1,gSEE)
ret,trh = cv2.threshold(dst,50,255,0)
trh = cv2.merge((trh,trh,trh))
cv2.imshow('trh',trh)
cv2.waitKey(0)
cv2.destroyAllWindows()
結果如下:
當然我們也可以進行位運算,這樣我們就可以取出顏色部分了,所有完整代碼如下:
import cv2
import numpy as np
from matplotlib import pyplot as pltroi = cv2.imread(r'C:\Users\mx\Desktop\gz\roi.png')
hsv_roi = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)
target = cv2.imread(r'C:\Users\mx\Desktop\gz\4.png')
hsv_target = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)roihist = cv2.calcHist([hsv_roi],[0, 1], None, [180, 256], [0, 180, 0, 256] )
cv2.normalize(roihist,roihist,0,255,cv2.NORM_MINMAX)
dst = cv2.calcBackProject([hsv_target],[0,1],roihist,[0,180,0,256],1)
gSEE = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
dst=cv2.filter2D(dst,-1,gSEE)ret,trh = cv2.threshold(dst,50,255,0)
trh = cv2.merge((trh,trh,trh))
cv2.imshow('trh',trh)
res = cv2.bitwise_and(target,trh)
cv2.imwrite('res.jpg',res)
cv2.imshow('res',res)
cv2.waitKey(0)
cv2.destroyAllWindows()
結果如下:
我們也可以換一下圖:
roi:
目標:
結果:
該系列首發于ebaina