这两天主要在学习目标跟踪的典型算法-camshift算法,在讨论和介绍camshift算法之前,我们先来讨论下meanshift算法。
(1)meanshift算法
meanshift算法是一种在一组数据的密度分布中寻找局部极值稳定的方法。具体的数学原理主要是基于概率统计的思想,略有点复杂,下面给出一篇博文链接,感兴趣的话可以去研究下meanshift算法背后的概率统计原理。
http://blog.csdn.net/jinshengtao/article/details/30258833
meanshift算法的主要步骤是:
a.选择搜索窗口
- 窗口的初始位置;
- 窗口的类型(均匀、多项式、指数或者高斯类型);
- 窗口的形状(对称的或歪斜的,可能旋转的,圆形或矩形);
- 窗口的大小(超出窗口大小则被截去)。
b.计算窗口(可能是带权重的)的重心。
c.将窗口的中心设置在计算出的重心处。
d.返回到b步,直到窗口的位置不再变化。
上述算法步骤中的窗口,实则就是上文中博文链接的数学原理中的核函数,meanshift算法与核密度估计的规则有关。如果在足够的点处有足够合适的带权重和尺度的核,数据分布便可以完全根据这些核来表示。而基于meanshift算法的目标跟踪,通过分别计算目标区域和候选区域内像素的特征值概率得到关于目标模型和候选模型的描述,然后利用相似函数度量初始帧目标模型和当前帧的候选模版的相似性,选择使相似函数最大的候选模型并得到关于目标模型的Meanshift向量,这个向量正是目标由初始位置向正确位置移动的向量。由于均值漂移算法的快速收敛性,通过不断迭代计算Meanshift向量,算法最终将收敛到目标的真实位置,达到跟踪的目的。
下面给出个直观的图描述这个跟踪的过程:
在OpenCV中有函数cvMeanShift(),下面简要介绍下这个函数中的参数。
int cvMeanShift(
const CvArr* prob_image,//单通道图像
CvRect window,//指定初始位置,大小为核窗口的大小
CvTermCriteria criteria,//迭代终止条件
CvConnectedComp *comp//连接部件,comp->rect中包含了收敛后搜索窗口的位置等信息
);
(2)camshift算法
camshift是“continuously adaptive mean-shift”的缩写,顾名思义,camshift算法是基于meanshift算法的,与meanshift算法不同之处在于camshift搜索窗口会进行自我调整,更有利于对目标的跟踪,因此在OpenCV中cvCamShift()函数中的参数列表中相应的给出了box参数,在跟踪的应用中,会把由前一帧计算出的新尺寸box作为下一帧的window。
int cvCamShift(
const CvArr* prob_img,
CvRect window,
CvTermCriteria criteria,
CvConnectedComp* comp,
CvBox2D* box=NULL
);
下面给出OpenCV中自带的工程示例程序camshiftdemo程序,这个程序的大致思路是这样的:通过计算目标HSV空间下的HUE分量直方图,通过直方图反向投影得到目标像素的概率分布,然后调用CV库中的camshift算法,自动跟踪并调整目标窗口的中心位置与大小。下面给出这个demo的完整程序段和注释:
/*
OpenCV中自带的Camshiftdemo,程序的思想是通过计算目标HSV空间下的HUE分量直方图,通过直方图反向投影
得到目标像素的概率分布,然后通过调用CV库中的Camshift算法,自动跟踪并调整目标窗口的中心位置和大小。
*/
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <ctype.h>
using namespace cv;
using namespace std;
Mat image;
bool backprojMode = false;//表示是否要进入反向投影模式,true则表示要进入反向投影模式
bool selectObject = false;//表是否在选中要跟踪的初始目标,true表示正在用鼠标选择要跟踪的目标
int trackObject = 0;//跟踪目标的数目
bool showHist = true;//是否显示HUE分量直方图
Point origin;//用于保存鼠标选择第一次单击时点的位置