Opencv Python 简明教程

OpenCV Python - Meanshift and Camshift

在本章中,我们一起来了解一下 OpenCV-Python 中的均值漂移和 CAMShift。首先,我们来了解一下什么是均值漂移。

Meanshift

均值漂移算法可以识别数据集中数据点高度集中或集群的位置。该算法会在每个数据点放置一个内核并对它们求和,以做出一个 Kernel Density Estimation (KDE)。

KDE 会有高和低数据点密度的区域,具有相应的值。均值漂移是一种很有用的方法,可以用来跟踪视频中某个指定对象。

视频中的每个实例都会以该帧的像素分布形式被检查。初始窗口(即目标区域 (ROI) )通常是正方形或圆形。为此,会通过硬编码指定位置,并标识最高像素分布区域。

随着视频播放,ROI 窗口会向着最高像素分布区域移动。移动方向取决于我们的跟踪窗口中心与该窗口内所有 k 像素的质心之间的差值。

要在 OpenCV 中使用均值漂移,首先要查找我们目标的直方图(其中仅考虑色调),然后可以针对每个帧 反投影其目标,以计算均值漂移。我们还需要提供 ROI 窗口的初始位置。

我们反复计算直方图的反投影,并计算均值漂移以获得跟踪窗口的新位置。随后,我们会使用它的尺寸在帧上绘制一个矩形。

Functions

程序中使用的 OpenCV 函数包括:

  1. cv.calcBackProject() − 计算直方图的反投影。

  2. cv.meanShift() − 使用初始搜索窗口和迭代搜索算法的停止准则的反向投影对象直方图。

Example

以下是均值漂移的示例程序:

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

在运行程序时,均值漂移算法会将我们的窗口移动到密度最大的新位置。

Output

以下为移动窗口的快照:

meanshift

Camshift

Meanshift 算法的一个缺点是,跟踪窗口的大小保持不变,与对象到摄像机的距离无关。此外,只有当窗口处于该对象区域内时,窗口才会跟踪该对象。因此,我们必须手动对窗口进行硬编码,并且应该小心进行。

CAMshift(代表 Continuously Adaptive Meanshift )给出了这些问题的解决方案。一旦 meanshift 收敛,Camshift 算法就会更新窗口的大小,使得跟踪窗口的大小可能会改变,甚至旋转以更好地与跟踪对象的动作相关联。

在以下代码中,使用了 camshift() 函数,而不是 meanshift() 函数。

首先,它使用 meanShift 查找对象中心,然后调整窗口大小并找到最佳旋转。该函数返回对象的位置、大小和方向。使用 polylines() 绘制函数在帧上绘制位置。

Example

在较早程序中,使用 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)

Output

以下显示跟踪窗口旋转矩形的修改后的程序的结果快照:

camshift