meanshift追踪手动选框(python-opencv)

来源:互联网 发布:淘宝店铺处罚规则 编辑:程序博客网 时间:2024/05/29 16:30

在这篇文章里,我将会用python-opencv实现Meanshift,我将给出用鼠标框出追踪目标,实现追踪。
基于MeanShift的Camshift算法原理详解(整理)
meanshift算法思想其实很简单:利用概率密度的梯度爬升来寻找局部最优。它要做的就是输入一个在图像的范围,然后一直迭代(朝着重心迭代)直到满足你的要求为止。但是他是怎么用于做图像跟踪的呢?这是我自从学习meanshift以来,一直的困惑。而且网上也没有合理的解释。经过这几天的思考,和对反向投影的理解使得我对它的原理有了大致的认识。
在opencv中,进行meanshift其实很简单,输入一张图像(imgProb),再输入一个开始迭代的方框(windowIn)和一个迭代条件(criteria),输出的是迭代完成的位置(comp )。
这是函数原型:
int cvMeanShift( const void* imgProb, CvRect windowIn,
CvTermCriteria criteria, CvConnectedComp* comp )
但是当它用于跟踪时,这张输入的图像就必须是反向投影图了。
为什么必须是反向投影图呢?首先我们要理解什么是反向投影图。
简单理解它其实实际上是一张概率密度图。经过反向投影时的输入是一个目标图像的直方图(也可以认为是目标图像),还一个输入是当前图像就是你要跟踪的全图,输出大小与全图一样大,它上像素点表征着一种概率,就是全图上这个点是目标图像一部分的概率。如果这个点越亮,就说明这个点属于物体的概率越大。现在我们明白了这原来是一张概率图了。当用meanshift跟踪时,输入的原来是这样一幅图像,那也不难怪它可以进行跟踪了。
半自动跟踪思路:输入视频,用画笔圈出要跟踪的目标,然后对物体跟踪。
用过opencv的都知道,这其实是camshiftdemo的工作过程。
第一步:选中物体,记录你输入的方框和物体。
第二步:求出视频中有关物体的反向投影图。
第三步:根据反向投影图和输入的方框进行meanshift迭代,由于它是向重心移动,即向反向投影图中概率大的地方移动,所以始终会移动到目标上。
第四步:然后下一帧图像时用上一帧输出的方框来迭代即可。
全自动跟踪思路:输入视频,对运动物体进行跟踪。
第一步:运用运动检测算法将运动的物体与背景分割开来。
第二步:提取运动物体的轮廓,并从原图中获取运动图像的信息。
第三步:对这个信息进行反向投影,获取反向投影图。
第四步:根据反向投影图和物体的轮廓(也就是输入的方框)进行meanshift迭代,由于它是向重心移 动,即向反向投影图中概率大的地方移动,所以始终会移动到物体上。
第五步:然后下一帧图像时用上一帧输出的方框来迭代即可。
总结:用meanshift进行跟踪最重要的一点是输入图像的把握,也就是要让它的迭代能越来越迭代到目标上。这种图像也不一定就是反向投影图,只要是一幅反映当前图像中每个像素点含有目标概率图就可以了,其实反向投影图就是这样的一幅图而已。
meanShift算法用于视频目标跟踪时,采用目标的颜色直方图作为搜索特征,通过不断迭代meanShift向量使得算法收敛于目标的真实位置,从而达到跟踪的目的。

传统的meanShift算法在跟踪中有几个优势:

(1)算法计算量不大,在目标区域已知的情况下完全可以做到实时跟踪;

(2)采用核函数直方图模型,对边缘遮挡、目标旋转、变形和背景运动不敏感。

同时,meanShift算法也存在着以下一些缺点:

(1)缺乏必要的模板更新;

(2)跟踪过程中由于窗口宽度大小保持不变,当目标尺度有所变化时,跟踪就会失败;

(3)当目标速度较快时,跟踪效果不好;

(4)直方图特征在目标颜色特征描述方面略显匮乏,缺少空间信息;

由于其计算速度快,对目标变形和遮挡有一定的鲁棒性,所以,在目标跟踪领域,meanShift算法目前依然受到大家的重视。但考虑到其缺点,在工程实际中也可以对其作出一些改进和调整;例如:

(1)引入一定的目标位置变化的预测机制,从而更进一步减少meanShift跟踪的搜索时间,降低计算量;

(2)可以采用一定的方式来增加用于目标匹配的“特征”;

(3)将传统meanShift算法中的核函数固定带宽改为动态变化的带宽;

(4)采用一定的方式对整体模板进行学习和更新;

# -*- coding: utf-8 -*-import numpy as npimport cv2current_pos = Nonetl = Nonebr = None#鼠标事件def get_rect(im, title='get_rect'):    mouse_params = {'tl': None, 'br': None, 'current_pos': None,'released_once': False}    cv2.namedWindow(title)    cv2.moveWindow(title, 100, 100)    def onMouse(event, x, y, flags, param):        param['current_pos'] = (x, y)        if param['tl'] is not None and not (flags & cv2.EVENT_FLAG_LBUTTON):            param['released_once'] = True        if flags & cv2.EVENT_FLAG_LBUTTON:            if param['tl'] is None:                param['tl'] = param['current_pos']            elif param['released_once']:                param['br'] = param['current_pos']    cv2.setMouseCallback(title, onMouse, mouse_params)    cv2.imshow(title, im)    while mouse_params['br'] is None:        im_draw = np.copy(im)        if mouse_params['tl'] is not None:            cv2.rectangle(im_draw, mouse_params['tl'],                mouse_params['current_pos'], (255, 0, 0))        cv2.imshow(title, im_draw)        _ = cv2.waitKey(10)    cv2.destroyWindow(title)    tl = (min(mouse_params['tl'][0], mouse_params['br'][0]),        min(mouse_params['tl'][1], mouse_params['br'][1]))    br = (max(mouse_params['tl'][0], mouse_params['br'][0]),        max(mouse_params['tl'][1], mouse_params['br'][1]))    return (tl, br)cap = cv2.VideoCapture('Bolt.mp4')# 读取摄像头第一帧图像ret, frame = cap.read()while True:    ret, frame = cap.read()    if ret == True:        break# 初始化位置窗口#r,h,c,w = 250,90,400,125  # simply hardcoded the valuesr,h,c,w=15,370,319,87   #初始位置#a1,a2 = get_rect(frame, title='get_rect') 手动选框#r,h,c,w = a1[1],a2[1]-a1[1],a1[0],a2[0]-a1[0] 手动选框track_window = (c,r,w,h)# 设置所要跟踪的ROIroi = frame[r:r+h, c:c+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)# 设置终止条件term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 )while(1):    ret ,frame = cap.read()    if ret == True:        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)        dst = cv2.calcBackProject([hsv],[0],roi_hist,[0,180],1)        # apply meanshift to get the new location        ret, track_window = cv2.meanShift(dst, track_window, term_crit)        # Draw it on image        x,y,w,h = track_window        cv2.rectangle(frame, (x,y), (x+w,y+h), 255,2)        cv2.imshow('img2',frame)        k = cv2.waitKey(10) & 0xff        if k == 27:            break        #else:           # cv2.imwrite(chr(k)+".jpg",img2)    else:        breakcv2.destroyAllWindows()cap.release()
原创粉丝点击