OpenCV-Python——第32章:Meanshift 和 Camshift目标跟踪算法

翻译自:https://docs.opencv.org/master/db/df8/tutorial_py_meanshift.html

目录

1 Meanshift

1.1 原理

1.2 OpenCV中的Meashift

2 CAMSHIFT

2.1 原理

2.2 OpenCV 中的 Camshift


1 Meanshift

1.1 原理

Meanshift 算法的基本原理是和很简单的。假设我们有一堆点(比如直方 图反向投影得到的点),和一个小的圆形窗口,我们要完成的任务就是将这个窗 口移动到最大灰度密度处(或者是点最多的地方)。如下图所示:

OpenCV-Python——第32章:Meanshift 和 Camshift目标跟踪算法_第1张图片

初始窗口是蓝色的“C1”,它的圆心为蓝色方框“C1_o”,而窗口中所有点质心却是“C1_r”(小的蓝色圆圈),很明显圆心和点的质心没有重合。所以移动圆 心 C1_o 到质心 C1_r,这样我们就得到了一个新的窗口。这时又可以找到新 窗口内所有点的质心,大多数情况下还是不重合的,所以重复上面的操作:将 新窗口的中心移动到新的质心。就这样不停的迭代操作直到窗口的中心和其所 包含点的质心重合为止(或者有一点小误差)。按照这样的操作我们的窗口最终 会落在像素值(和)最大的地方。如上图所示“C2”是窗口的最后位址,我们可 以看出来这个窗口中的像素点最多。整个过程如下图所示:

OpenCV-Python——第32章:Meanshift 和 Camshift目标跟踪算法_第2张图片

通常情况下我们要使用直方图方向投影得到的图像和目标对象的起始位置。当目标对象的移动会反映到直方图反向投影图中。就这样,meanshift 算法就 把我们的窗口移动到图像中灰度密度最大的区域了。

1.2 OpenCV中的Meashift

要在 OpenCV 中使用 Meanshift 算法首先我们要对目标对象进行设置,计算目标对象的直方图,这样在执行 meanshift 算法时我们就可以将目标对 象反向投影到每一帧中去了。另外我们还需要提供窗口的起始位置。在这里我 们值计算 H(Hue)通道的直方图,同样为了避免低亮度造成的影响,我们使用函数 cv2.inRange() 将低亮度的值忽略掉。

获取掩膜将低亮度的值忽略掉

dst=cv2.inRange(src, lowerb, upperb)

  • dst:目标图像,检查数组元素是否在指定范围内,在取1,否则取0

对于单通道:

                                                                 dst(I)=lowerb(I)_0\leqslant src(I)_0\leqslant upperb(I)_0

  • src:原图像
  • lowerb:下边界数组或标量
  • upperb:下边界数组或标量

CamShift算法:

retval, window=cv2.meanShift(probImage, window, criteria)

  • probImage:直方图的反投影,由calcBackProject获得
  • window:搜索窗口的位置与长宽
  • criteria:停止准则的迭代搜索算法。返回:CAMSHIFT收敛所需的迭代次数。该函数实现了迭代对象搜索算法。它获取一个对象的输入反投影和初始位置。计算了反投影图像窗口的质心,并将搜索窗口的质心移动到窗口的质心。此过程将重复,直到指定迭代次数的条件为止。maxCount已经完成,或者直到窗口中心移动小于critia .epsilon。该算法在CamShift中使用,与CamShift不同的是,搜索窗口大小或方向在搜索过程中不会改变。您可以简单地将calcBackProject的输出传递给这个函数。但是,如果对反投影进行预滤波并去除噪声,可以得到更好的结果。例如,您可以使用findContours索连接的组件,丢弃小区域的轮廓(contourArea),并使用 drawContours绘制剩余的轮廓。
  • retval:函数返回旋转后的矩形结构,其中包括对象位置、大小和方向。

获得矩形顶点

points = cv2.boxPoints(box)

  • 查找旋转的rect的四个顶点。用于绘制旋转的矩形。
import numpy as np
import cv2 as cv
cap = cv.VideoCapture('slow.flv')
# take first frame of the video
ret,frame = cap.read()
# setup initial location of window
r,h,c,w = 250,90,400,125  # simply hardcoded the values
track_window = (c,r,w,h)
# set up the ROI for tracking
roi = frame[r:r+h, c:c+w]
hsv_roi =  cv.cvtColor(roi, cv.COLOR_BGR2HSV)
mask = cv.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.)))
roi_hist = cv.calcHist([hsv_roi],[0],mask,[180],[0,180])
cv.normalize(roi_hist,roi_hist,0,255,cv.NORM_MINMAX)
# Setup the termination criteria, either 10 iteration or move by atleast 1 pt
term_crit = ( 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],roi_hist,[0,180],1)
        # apply meanshift to get the new location
        ret, track_window = cv.meanShift(dst, track_window, term_crit)
        # Draw it on image
        x,y,w,h = track_window
        img2 = cv.rectangle(frame, (x,y), (x+w,y+h), 255,2)
        cv.imshow('img2',img2)
        k = cv.waitKey(60) & 0xff
        if k == 27:
            break
        else:
            cv.imwrite(chr(k)+".jpg",img2)
    else:
        break
cv.destroyAllWindows()
cap.release()

下面是我使用 meanshift 算法对一个视频前三帧分析的结果:

OpenCV-Python——第32章:Meanshift 和 Camshift目标跟踪算法_第3张图片

CAMSHIFT

2.1 原理

 你认真看上面的结果了吗?这里面还有一个问题。我们的窗口的大小是固定的,而汽车由远及近(在视觉上)是一个逐渐变大的过程,固定的窗口是不 合适的。所以我们需要根据目标的大小和角度来对窗口的大小和角度进行修订。 OpenCVLabs 为我们带来的解决方案(1988 年):一个被叫做 CAMshift 的 算法。 这个算法首先要使用 meanshift,meanshift 找到(并覆盖)目标之后,再去调整窗口的大小,s = 2x\sqrt{\frac{M_{00}}{256}}。它还会计算目标对象的最佳外接椭圆的角度,并以此调节窗口角度。然后使用更新后的窗口大小和角度来在原来的位 置继续进行 meanshift。重复这个过程知道达到需要的精度。

OpenCV-Python——第32章:Meanshift 和 Camshift目标跟踪算法_第4张图片

 

2.2 OpenCV 中的 Camshift

与 Meanshift 基本一样,但是返回的结果是一个带旋转角度的矩形(这是我们的结果),以及这个矩形的参数(被用到下一次迭代过程中)。

用到的函数;

获取掩膜

dst=cv2.inRange(src, lowerb, upperb)

  • dst:目标图像,检查数组元素是否在指定范围内,在取1,否则取0

对于单通道:

                                                                 dst(I)=lowerb(I)_0\leqslant src(I)_0\leqslant upperb(I)_0

  • src:原图像
  • lowerb:下边界数组或标量
  • upperb:下边界数组或标量

CamShift算法:

retval, window=cv2.CamShift(probImage, window, criteria)

  • probImage:直方图的反投影,由calcBackProject获得
  • window:初始搜索窗口
  • criteria:停止潜在meanShift的标准。返回(在旧接口中)CAMSHIFT用于收敛函数的迭代次数,该函数实现CAMSHIFT对象跟踪算法[26]。首先,它使用meanShift找到一个对象中心,然后调整窗口大小,找到最优的旋转。retval:函数返回旋转后的矩形结构,其中包括对象位置、大小和方向。使用RotatedRect::boundingRect()可以获得搜索窗口的下一个位置。

 

获得矩形顶点

points = cv2.boxPoints(box)

  • 查找旋转的rect的四个顶点。用于绘制旋转的矩形。

下面是代码:

import numpy as np
import cv2 as cv
cap = cv.VideoCapture('slow.flv')
# take first frame of the video
ret,frame = cap.read()
# setup initial location of window
r,h,c,w = 250,90,400,125  # simply hardcoded the values
track_window = (c,r,w,h)
# set up the ROI for tracking
roi = frame[r:r+h, c:c+w]
hsv_roi =  cv.cvtColor(roi, cv.COLOR_BGR2HSV)
mask = cv.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.)))
roi_hist = cv.calcHist([hsv_roi],[0],mask,[180],[0,180])
cv.normalize(roi_hist,roi_hist,0,255,cv.NORM_MINMAX)
# Setup the termination criteria, either 10 iteration or move by atleast 1 pt
term_crit = ( 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],roi_hist,[0,180],1)
        # apply meanshift to get the new location
        ret, track_window = cv.CamShift(dst, track_window, term_crit)
        # Draw it on image
        pts = cv.boxPoints(ret)
        pts = np.int0(pts)
        img2 = cv.polylines(frame,[pts],True, 255,2)
        cv.imshow('img2',img2)
        k = cv.waitKey(60) & 0xff
        if k == 27:
            break
        else:
            cv.imwrite(chr(k)+".jpg",img2)
    else:
        break
cv.destroyAllWindows()
cap.release()

对三帧图像分析的结果如下:

OpenCV-Python——第32章:Meanshift 和 Camshift目标跟踪算法_第5张图片

你可能感兴趣的:(—OpenCV,opencv,目标跟踪,python,OpenCV-Python,Tutorials,视频分析)