【翻译:OpenCV-Python教程】光流

⚠️这篇是按4.1.0翻译的,你懂得。

⚠️除了版本之外,其他还是照旧,Optical Flow,原文

目标

在本章,

  • 我们会学到均值漂移和连续自适应均值漂移算法来找出并追踪视频中的物体。

均值漂移

均值漂移背后的灵感很简单。假设即有一组点。(它可以是一个好像直方图反向投射出来的像素分布)。而你有一个小窗口(也许是个圆形的)然后你得移动那个窗口到最大点密度(或者窗口框住说最多点数量)的区域。如下图所示:

meanshift_basics.jpg

初始化的窗口由蓝色的圆"C1"来表示。它最初的圆心用蓝色的正方形"C1_o"标记出来了。但如果你找出这个圆形窗口中所有点的质心,你就会得到"C1_r"点(用蓝色小圆圈标出了),它是这个圆实际的质心。很明显它们(质心和圆心)并不匹配,所以,移动窗口,使新窗口的圆圈与先前的质心相匹配。然后再次找到新的质心。很可能,它们还是不匹配。然后再继续递归移动这个圆圈,直到圆的中心和质心落在同一点(或者有一个小的期望误差)。最后得到的是一个具有最大像素分布的窗口。它用绿色的圆"C2"标记出来了。如图所示,它框住了最多的点。下面在一张静态图像上演示整个过程:

meanshift_face.gif

所以我们通常传入直方图的反向投影图像以及一个初始对象的位置。当这个对象移动的时候,移动明显会反映到直方图的反向投影图上。因此,均值漂移算法将窗口移动到具有最大的密度的新位置。

OpenCV里的均值漂移

要使用OpenCV里的均值漂移,首先我们需要设置目标对象,找出它的直方图,这样我们才能在每一帧上来进行反向映射,然后使用均值漂移算法。我们还需要提供窗口的初始位置。对于直方图,这里只考虑色调。此外,为了避免由于低光而产生的错误值,使用cv.inRange()函数丢弃低光值。

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_result.jpg

(译者附,该例中的使用的文件已经在git上被删除,我翻墙找到了。盘1nwTS8L3k-2sG0ry5bbrXYQ码7gi4)

连续自适应的均值漂移

你是否靠近去看了刚才那个结果呢?这里有个问题。我们的窗口在汽车处于远处和靠近摄像头的近处总是保持一个固定的大小。这不太好。我们得使窗口适应目标对象的大小和旋转角度。这个解决方案又一次来自"OpenCV Labs",它被叫做CAMshift (连续自适应均值漂移) 由Gary Bradsky在他1998年的论文"Computer Vision Face Tracking for Use in a Perceptual User Interface"中发布。

它首先应用meanshift算法。一旦meanshift收敛,它就按公式s = 2 \times \sqrt{\frac{M_{00}}{256}}来更新窗口的大小,同时还计算了最佳拟合椭圆的方向。它通过新的放缩搜索窗口和以前的窗口位置再次应用了均值漂移。此过程将继续迭代,直到达到所需的精度为止。

camshift_face.gif

OpenCV里的Camshift

它也和均值漂移一样,但它返回了一个旋转之后的矩形(那就是我们需要的结果),当然还有这个矩形的参数(用来传入下次迭代中的搜索窗口)。看下面的代码:

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()

结果的其中三帧显示如下:

camshift_result.jpg

额外资源

  1. 法语维基百科页面 Camshift。(本文中两个动图就是从这偷的。)
  2. Bradski, G.R., "Real time face and object tracking as a component of a perceptual user interface," Applications of Computer Vision, 1998. WACV '98. Proceedings., Fourth IEEE Workshop on , vol., no., pp.214,219, 19-21 Oct 1998

练习

  1. OpenCV 有一个 camshift 的 Python 例子在交互式示例上,使用它、破解它、理解它。

上篇:【翻译:OpenCV-Python教程】均值漂移和连续自适应均值漂移

下篇:【翻译:OpenCV-Python教程】图像金字塔

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章