OpenCV Python - Meanshift 和 Camshift
在本章中,让我们了解 OpenCV-Python 中的 meanshift 和 camshift。 首先,让我们了解一下什么是均值偏移。
Meanshift
均值偏移算法识别数据集中数据点或集群高度集中的位置。 该算法在每个数据点放置一个内核,并将它们相加以进行内核密度估计 (KDE)。
KDE 会有数据点密度高和低的地方。 Meanshift 是一种非常有用的方法,可以跟踪视频中的特定对象。
视频的每个实例都以该帧中的像素分布形式进行检查。 作为兴趣区域(ROI) 的初始窗口通常是正方形或圆形。 为此,通过硬编码指定位置,并确定最大像素分布区域。
随着视频的运行,ROI 窗口向最大像素分布区域移动。 移动方向取决于我们跟踪窗口的中心与该窗口内所有 k 像素的质心之间的差异。
为了在OpenCV中使用Meanshift,首先,找到我们目标的直方图(其中只考虑了Hue)并且可以将其目标反投影到每一帧上来计算Meanshift。 我们还需要提供 ROI 窗口的初始位置。
我们反复计算直方图的反投影,计算Meanshift,得到轨迹窗口的新位置。 稍后,我们使用框架上的尺寸绘制一个矩形。
函数
程序中使用的openCV函数有 −
cv.calcBackProject() − 计算直方图的反投影。
cv.meanShift() − 使用迭代搜索算法的初始搜索窗口和停止标准反投影对象直方图。
示例
这里是Meanshift的示例程序 −
import numpy as np import cv2 as cv cap = cv.VideoCapture('traffic.mp4') ret,frame = cap.read() # dimensions of initial location of window x, y, w, h = 300, 200, 100, 50 tracker = (x, y, w, h) region = frame[y:y+h, x:x+w] hsv_reg = cv.cvtColor(region, cv.COLOR_BGR2HSV) mask = cv.inRange(hsv_reg, np.array((0., 60.,32.)), np.array((180.,255.,255.))) reg_hist = cv.calcHist([hsv_reg],[0],mask,[180],[0,180]) cv.normalize(reg_hist,reg_hist,0,255,cv.NORM_MINMAX) # Setup the termination criteria criteria = ( cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 1 ) while(1): ret, frame = cap.read() if ret == True: hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV) dst = cv.calcBackProject([hsv],[0],reg_hist,[0,180],1) # apply meanshift ret, tracker = cv.meanShift(dst, tracker, criteria) # Draw it on image x,y,w,h = tracker img = cv.rectangle(frame, (x,y), (x+w,y+h), 255,2) cv.imshow('img',img) k = cv.waitKey(30) & 0xff if k==115: cv.imwrite('capture.png', img) if k == 27: break
随着程序的运行,Meanshift 算法将我们的窗口移动到具有最大密度的新位置。
输出
这是移动窗口的快照 −
Camshift
Meanshift 算法的缺点之一是跟踪窗口的大小保持不变,无论对象与相机的距离如何。 此外,只有当对象位于该对象的区域时,窗口才会跟踪该对象。 因此,我们必须对窗口进行手动硬编码,而且要小心谨慎。
这些问题的解决方案由 CAMshift(代表 Continuously Adaptive Meanshift)给出。 一旦 meanshift 收敛,Camshift 算法就会更新窗口的大小,这样跟踪窗口的大小可能会发生变化,甚至会旋转以更好地与被跟踪对象的运动相关联。
在下面的代码中,使用了 camshift() 函数而不是 meanshift() 函数。
首先,它使用 meanShift 找到一个对象中心,然后调整窗口大小并找到最佳旋转。 该函数返回对象的位置、大小和方向。 使用 polylines() 绘制函数在框架上绘制位置。
示例
使用下面的 CamShift() 函数代替早期程序中的 Meanshift() 函数 −
# apply camshift ret, tracker = cv.CamShift(dst, tracker, criteria) pts = cv.boxPoints(ret) pts = np.int0(pts) img = cv.polylines(frame,[pts],True, 255,2) cv.imshow('img',img)
输出
显示跟踪窗口旋转矩形的修改程序结果快照如下 −