在这里将要学习Meanshift算法,这个算法主要在视频里寻找指定目标区域对象。Meanshift算法的原理在直觉上是很很简单的,假设有一张很点做成的图,如下图:
然后给你一个小的窗口,可以是圆形,也可以是方形,接着不断地移动这个窗口,尽量让这个窗口里的元素最多,也就是密度最大。在这里认为初始化的窗口为C1,蓝色那个圆,圆心是C1_O,蓝色那个方块表示。当你想找这个圆的质心时,你会发现它并不是在圆心位置,而是在C1_r位置,用蓝色圆表示。显而易见,圆心与质心并不一致,那么接着下来就是把这个圆的圆心移动到质心的位置,这时再去寻找新的质心,然后又发现它们并不匹配,又继续移动新的质心上。这样不断地迭代下去,发现总会有一个地方,圆心与质心是一致的。最后得到这个圆窗口,就是最像素分布密度最大的窗口。接着把密度最大的窗口标记为C2,从上图看到确实如此。
从上面分析可知道,meanshift是根据像素分布来跟踪对象,因此需要指定跟踪物体的窗口,就可以根据反向投影的图片来寻找密度大的地方。当目标对象移动时,反映在反向投影图上,就是像素密度在改变,所以meanshift就会移动窗口过去,达到跟踪物体的目的。
在OpenCV里要使用cv.meanShift函数,第一步先要设置寻找的目标,第二步计算创建目标的直方图,第三步计算反向投影图,最后一步使用meanShift函数。
演示的例子如下:
#python 3.7.4,opencv4.1
#蔡军生 https://blog.csdn.net/caimouse/article/details/51749579
#
import numpy as np
import cv2
from matplotlib import pyplot as plt
capture = cv2.VideoCapture(1)
if not capture.isOpened:
print('Unable to open: ')
exit(0)
#获取第一帧图片
ret,frame = capture.read()
#设置目标窗口
x, y, w, h = 200, 150, 100, 100 # 可以根据需要设置窗口位置,这里随便定义
track_window = (x, y, w, h)
#跟踪目标
roi = frame[y:y+h, x:x+w]
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.)))
roi_hist = cv2.calcHist([hsv_roi],[0],mask,[180],[0,180]) #计算直方图
cv2.normalize(roi_hist,roi_hist,0,255,cv2.NORM_MINMAX)
#设置迭代条件,每10移动一点
term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 )
while(1):
ret, frame = capture.read()
if ret == True:
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
dst = cv2.calcBackProject([hsv],[0],roi_hist,[0,180],1)#反向投影
#使用 meanshift获得新位置
ret, track_window = cv2.meanShift(dst, track_window, term_crit)
#显示标记
x,y,w,h = track_window
img2 = cv2.rectangle(frame, (x,y), (x+w,y+h), 255,2)
cv2.imshow('img2',img2)
keyboard = cv2.waitKey(30)
if keyboard == ord('q') or keyboard == ord('Q'):
break
else:
break
capture.release()
cv2.destroyAllWindows()
结果输出如下:
结果里可以看到,蓝色的方框跟着物体在移动。
https://blog.csdn.net/caimouse/article/details/51749579