在OpenCV里使用Meanshift算法

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/caimouse/article/details/102718481

在这里将要学习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

猜你喜欢

转载自blog.csdn.net/caimouse/article/details/102718481