本次試驗(yàn)可以分成兩個(gè)步驟完成。
- 利用顏色閾值取出跟蹤目標(biāo)。
- 使用均移(Meanshift and Camshift)算法進(jìn)行目標(biāo)跟蹤耸黑。
首先,什么是均移(Meanshift and Camshift)算法篮幢?
均移首先是建立一個(gè)窗口(window)大刊,然后不斷地將目標(biāo)在窗口內(nèi)移動搜索,并計(jì)算相關(guān)位置的最大值(也可以說是窗口內(nèi)概率密度)三椿。如圖缺菌,實(shí)正方形是窗口的中心曲尸,實(shí)圓形是目標(biāo)的質(zhì)心。目標(biāo)移動男翰,其質(zhì)心也會移動另患,我們的目的就是計(jì)算出目標(biāo)的質(zhì)心然后將窗口中心移動到質(zhì)心位置這樣就完成了對目標(biāo)的跟蹤。opencv的給的例子meanshif窗口大小固定蛾绎,camshift窗口實(shí)自適應(yīng)的昆箕。
詳細(xì)請查看python-opencv手冊
https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_video/py_meanshift/py_meanshift.html#meanshift
其次,什么是顏色閾值分割租冠?
目標(biāo)的顏色是目標(biāo)的一個(gè)非常明顯的特征鹏倘,也是比較容易察覺,彩色圖像的三基色是紅(RED)顽爹,綠(GREEN)纤泵,藍(lán)(BLUE),在此基礎(chǔ)上建立的模型是RGB模型镜粤,然而我們常常將RGB模型 轉(zhuǎn)換成HSV模型捏题,H(明色調(diào)),S(飽和度)肉渴,V(明度)公荧。色度決定圖像色彩,飽和度是顏色的深淺同规,明度是圖像的明亮程度循狰。圖像閾值分割就是利用HSV這三個(gè)特性,設(shè)置一個(gè)范圍將我們所需要(區(qū)別于背景)的目標(biāo)顏色提取出來券勺⌒髟浚基于顏色閾值分割的優(yōu)點(diǎn)在于易于理解,很直觀关炼。缺點(diǎn)在于閾值的選取比較麻煩程腹,且容易受到背景顏色的干擾。
python+opencv的方式給圖像處理帶來的極大的簡易性盗扒,python是腳本語言所以在圖像處理操作時(shí)可將代碼寫成腳本方便理解跪楞。
接下來開始進(jìn)行試驗(yàn)缀去。
import numpy as np#導(dǎo)入numpy庫
import cv2#導(dǎo)入opencv庫
cap = cv2.VideoCapture(0)#開啟攝像頭
ret,frame = cap.read()#讀取第一幀視頻
# take first frame of the video
lower_blue = np.array([20,0,0]) #設(shè)置顏色閾值下限
upper_blue = np.array([50,200,200])#設(shè)置顏色閾值上限
在這段代碼中讀取攝像頭捕捉的第一幀作為預(yù)處理圖像侣灶。并設(shè)置我們所需要捕捉目標(biāo)顏色的范圍,這里我捕捉的是黃色缕碎,范圍大概是(20-50)褥影。根據(jù)HSV模型,彩色圖像的色調(diào)(H)在8bit下是(0-180)三基色的值大概是紅(0)咏雌,黃(30)凡怎,綠(60)校焦,青(90),藍(lán)(120)统倒。飽和度(H)的范圍是(0-255)寨典,明度(V)的范圍是(0-255)。所以我給定的黃色杯蓋的HSV范圍如下H(20-50),S(0-200),V(0-200)房匆。具體的opencv顏色閾值選取詳細(xì)內(nèi)容參見
https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html#converting-colorspaces
mask = cv2.inRange(frame, lower_blue, upper_blue)#建立一個(gè)遮掩mask
kernel = np.ones((5,5),np.uint8)#建立一個(gè)核心
opening = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)#開啟
dilation = cv2.dilate(opening,kernel,iterations = 1)#膨脹
在這段代碼中主要是對我們攝像頭獲取的第一幀圖像進(jìn)行了取遮掩耸成,取遮掩的目的是提取出第一幀圖像中的目標(biāo)。opening(開啟)和dilation(膨脹)都是形態(tài)學(xué)處理浴鸿,開啟用于把結(jié)構(gòu)元素(可以理解為每個(gè)像素)小的突刺濾掉井氢,切斷細(xì)長的搭接而起到分離作用。膨脹用于擴(kuò)張比背景亮的區(qū)域岳链,壓縮比背景暗的區(qū)域花竞。其中kernel創(chuàng)建的就是大小為5 * 5的結(jié)構(gòu)元素。關(guān)于形態(tài)學(xué)的知識詳見
https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_morphological_ops/py_morphological_ops.html
image, contours, hierarchy = cv2.findContours(dilation,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)#取輪廓
cnt = contours[1]#輪廓集合中第二個(gè)輪廓
M = cv2.moments(cnt)#圖像矩
#重心
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
這段代碼目的是對開啟和膨脹后的目標(biāo)圖像進(jìn)行取輪廓操作掸哑,并對取到的輪廓取圖像矩取重心和取中心點(diǎn)坐標(biāo)约急。輪廓contours是包含著目標(biāo)的輪廓點(diǎn)。因?yàn)楂@得的目標(biāo)圖像可能會有空洞所以因該會有很多的輪廓點(diǎn)集苗分,這里cnt = contours[1]取的是取第二個(gè)點(diǎn)集烤宙。圖像中計(jì)算出來的矩通常描述了圖像不同種類的幾何特征如:大小、灰度俭嘁、方向躺枕、形狀、重心等特征供填。這里cx和cy是輪廓的重心拐云。關(guān)于opencv提取輪廓參見[findContours]https://docs.opencv.org/3.0-last-rst/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=cv2.findcontour#cv2.findContours 關(guān)于輪廓特性如圖像矩參見[CONTOUR_FEATURES]https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.html
r,h,c,w = np.int(np.abs(cy-250)),250,np.int(np.abs(cx-250)),250# 根據(jù)獲得的重心建立一個(gè)窗口(window)
track_window = (c,r,w,h)
roi = frame[r:r+h, c:c+w]#取出圖像中的目標(biāo)圖像
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)#RGB模型轉(zhuǎn)換成HSV模型
mask = cv2.inRange(hsv_roi, lower_blue, upper_blue)#創(chuàng)建遮掩mask
roi_hist = cv2.calcHist([hsv_roi],[0],mask,[30],[0,30])#獲取灰度直方圖
cv2.normalize(roi_hist,roi_hist,0,30,cv2.NORM_MINMAX)#歸一化處理
# Setup the termination criteria, either 10 iteration or move by atleast 1 pt
term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 )#設(shè)置起始條件
這段代碼主要就是以獲取到的輪廓重心為中心建立一個(gè)矩形窗口,并對這個(gè)窗口取灰度直方圖近她,進(jìn)行歸一化處理叉瘩,以及設(shè)置起始條件為直方圖反向映射做準(zhǔn)備。直方圖反向映射是什么粘捎?它用于圖像分割或在圖像中查找感興趣的對象薇缅。簡單地說,它創(chuàng)建的圖像大小(但單通道)與我們的輸入圖像攒磨,其中每個(gè)像素對應(yīng)的概率泳桦,該像素屬于我們的對象。在更簡單的世界中娩缰,與其余部分相比灸撰,輸出圖像將使我們感興趣的對象更白。關(guān)于直方圖反向映射的原理參見
https://blog.csdn.net/michaelhan3/article/details/73550643
while(1):
ret ,frame = cap.read()#讀取圖片
if ret == True:
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
dst = cv2.calcBackProject([hsv],[0],roi_hist,[0,30],1)#直方圖反向映射
# apply meanshift to get the new location
ret, track_window = cv2.CamShift(dst, track_window, term_crit)#自適應(yīng)均移算法
# Draw it on image
pts = cv2.boxPoints(ret)
pts = np.int0(pts)
img2 = cv2.polylines(frame, [pts], True, 255, 2)#繪制跟蹤窗口
cv2.imshow('img2', img2)#顯示圖像
k = cv2.waitKey(60) & 0xff#設(shè)置按下esc退出程序
if k == 27:
break
cv2.destroyAllWindows()#摧毀窗口
cap.release()#卸載攝像頭
以上實(shí)現(xiàn)了一個(gè)獲取黃色的目標(biāo)并進(jìn)行跟蹤的程序。結(jié)果如下gif圖浮毯。
代碼托管在碼云https://gitee.com/capone/testt/attach_files