【opencv】Camshift目标跟踪

41 篇文章 1 订阅
Camshift原理

CamShift算法的全称是"Continuously Adaptive Mean-SHIFT",即:连续自适应的MeanShift算法。其基本思想是对视频序列的所有图像帧都作MeanShift运算,并将上一帧的结果(即搜索窗口的中心位置和窗口大小)作为下一帧MeanShift算法的搜索窗口的初始值,如此迭代下去。简单点说,meanShift是针对单张图片寻找最优迭代结果,而camShift则是针对视频序列来处理,并对该序列中的每一帧图片都调用meanShift来寻找最优迭代结果。正是由于camShift针对一个视频序列进行处理,从而保证其可以不断调整窗口的大小,如此一来,当目标的大小发生变化的时候,该算法就可以自适应地调整目标区域继续跟踪。

OpenCV自带的camShift的例子当中,是通过计算目标在HSV空间下的H分量直方图,通过直方图反向投影得到目标像素的概率分布,然后通过调用OpenCV的CAMSHIFT算法,自动跟踪并调整目标窗口的中心位置与大小。该算法对于简单背景下的单目标跟踪效果较好,但如果被跟踪目标与背景颜色或周围其它目标颜色比较接近,则跟踪效果较差。另外,由于采用颜色特征,所以它对被跟踪目标的形状变化有一定的抵抗能力。

http://blog.csdn.net/carson2005/article/details/7439125

 分为三个部分:
1--色彩投影图(反向投影):
(1).RGB颜色空间对光照亮度变化较为敏感,为了减少此变化对跟踪效果的影响,首先将图像从RGB空间转换到HSV空间。(2).然后对其中的H分量(色调)作直方图,在直方图中代表了不同H分量值出现的概率或者像素个数,就是说可以查找出H分量大小为h的概率或者像素个数,即得到了颜色概率查找表。(3).将图像中每个像素的值用其颜色出现的概率对替换,就得到了颜色概率分布图。这个过程就叫反向投影,颜色概率分布图是一个灰度图像。


2--meanshift
meanshift算法是一种密度函数梯度估计的非参数方法,通过迭代寻优找到概率分布的极值来定位目标。
算法过程为:
(1).在颜色概率分布图中选取搜索窗W
(2).计算零阶距:

计算一阶距:

计算搜索窗的质心:

(3).调整搜索窗大小
宽度为;长度为1.2s;
(4).移动搜索窗的中心到质心,如果移动距离大于预设的固定阈值,则重复2)3)4),直到搜索窗的中心与质心间的移动距离小于预设的固定阈值,或者循环运算的次数达到某一最大值,停止计算。关于meanshift的收敛性证明可以google相关文献。

3--camshift
将meanshift算法扩展到连续图像序列,就是camshift算法。它将视频的所有帧做meanshift运算,并将上一帧的结果,即搜索窗的大小和中心,作为下一帧meanshift算法搜索窗的初始值。如此迭代下去,就可以实现对目标的跟踪。
算法过程为:
(1).初始化搜索窗
(2).计算搜索窗的颜色概率分布(反向投影)
(3).运行meanshift算法,获得搜索窗新的大小和位置。
(4).在下一帧视频图像中用(3)中的值重新初始化搜索窗的大小和位置,再跳转到(2)继续进行。

camshift能有效解决目标变形和遮挡的问题,对系统资源要求不高,时间复杂度低,在简单背景下能够取得良好的跟踪效果。但当背景较为复杂,或者有许多与目标颜色相似像素干扰的情况下,会导致跟踪失败。因为它单纯的考虑颜色直方图,忽略了目标的空间分布特性,所以这种情况下需加入对跟踪目标的预测算法。

__________________________________________________________________________________________________________________________________________

半自动跟踪思路:输入视频,用画笔圈出要跟踪的目标,然后对物体跟踪。

  用过opencv的都知道,这其实是camshiftdemo的工作过程。

    第一步:选中物体,记录你输入的方框和物体。

    第二步:求出视频中有关物体的反向投影图。

    第三步:根据反向投影图和输入的方框进行meanshift迭代,由于它是向重心移动,即向反向投影图中概率大的地方移动,所以始终会移动到目标上。

    第四步:然后下一帧图像时用上一帧输出的方框来迭代即可。

  全自动跟踪思路:输入视频,对运动物体进行跟踪。

    第一步:运用运动检测算法将运动的物体与背景分割开来。

    第二步:提取运动物体的轮廓,并从原图中获取运动图像的信息。

    第三步:对这个信息进行反向投影,获取反向投影图。

    第四步:根据反向投影图和物体的轮廓(也就是输入的方框)进行meanshift迭代,由于它是向重心移动,即向反向投影图中概率大的地方移动,所以始终会移动到物体上。

    第五步:然后下一帧图像时用上一帧输出的方框来迭代即可。

http://www.cnblogs.com/cfantaisie/archive/2011/06/10/2077190.html

 

下面是一个全自动跟踪的例子

代码是copy来的,从哪来的忘了……

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

//对轮廓按面积降序排列
bool biggerSort(vector<Point> v1, vector<Point> v2)
{
	return contourArea(v1)>contourArea(v2);
}

int main()
{
	//视频不存在,就返回
	VideoCapture cap("3.AVI");
	if(cap.isOpened()==false)
		return 0;

	//定义变量
	int i;

	Mat frame;			//当前帧
	Mat foreground;		//前景
	Mat bw;				//中间二值变量
	Mat se;				//形态学结构元素

	//用混合高斯模型训练背景图像
	BackgroundSubtractorMOG mog;	
	for(i=0;i<10;++i)
	{
		cout<<"正在训练背景:"<<i<<endl;
		cap>>frame;
		if(frame.empty()==true)
		{
			cout<<"视频帧太少,无法训练背景"<<endl;
			getchar();
			return 0;
		}
		mog(frame,foreground,0.01);	
	}
	
	//目标外接框、生成结构元素(用于连接断开的小目标)
	Rect rt;
	se=getStructuringElement(MORPH_RECT,Size(5,5));

	//统计目标直方图时使用到的变量
	vector<Mat> vecImg;
	vector<int> vecChannel;
	vector<int> vecHistSize;
	vector<float> vecRange;
	Mat mask(frame.rows,frame.cols,DataType<uchar>::type);
	//变量初始化
	vecChannel.push_back(0);
	vecHistSize.push_back(32);
	vecRange.push_back(0);
	vecRange.push_back(180);
		
	Mat hsv;		//HSV颜色空间,在色调H上跟踪目标(camshift是基于颜色直方图的算法)
	MatND hist;		//直方图数组
	double maxVal;		//直方图最大值,为了便于投影图显示,需要将直方图规一化到[0 255]区间上
	Mat backP;		//反射投影图
	Mat result;		//跟踪结果
	
	//视频处理流程
	while(1)
	{
		//读视频
		cap>>frame;
		if(frame.empty()==true)
			break;		
	
		//生成结果图
		frame.copyTo(result);

		//检测目标(其实是边训练边检测)
		mog(frame,foreground,0.01);
		imshow("混合高斯检测前景",foreground);
		moveWindow("混合高斯检测前景",400,0);
		//对前景进行中值滤波、形态学膨胀操作,以去除伪目标和接连断开的小目标		
		medianBlur(foreground,foreground,5);
		imshow("中值滤波",foreground);
		moveWindow("中值滤波",800,0);
		morphologyEx(foreground,foreground,MORPH_DILATE,se);

		//检索前景中各个连通分量的轮廓
		foreground.copyTo(bw);
		vector<vector<Point>> contours;
		findContours(bw,contours,RETR_EXTERNAL,CHAIN_APPROX_NONE);
		if(contours.size()<1)
			continue;
		//对连通分量进行排序
		std::sort(contours.begin(),contours.end(),biggerSort);

		//结合camshift更新跟踪位置(由于camshift算法在单一背景下,跟踪效果非常好;
		//但是在监控视频中,由于分辨率太低、视频质量太差、目标太大、目标颜色不够显著
		//等各种因素,导致跟踪效果非常差。  因此,需要边跟踪、边检测,如果跟踪不够好,
		//就用检测位置修改
		cvtColor(frame,hsv,COLOR_BGR2HSV);
		vecImg.clear();
		vecImg.push_back(hsv);
		for(int k=0;k<contours.size();++k)
		{
			//第k个连通分量的外接矩形框
			if(contourArea(contours[k])<contourArea(contours[0])/5)
				break;
			rt=boundingRect(contours[k]);				
			mask=0;
			mask(rt)=255;

			//统计直方图
			calcHist(vecImg,vecChannel,mask,hist,vecHistSize,vecRange);				
			minMaxLoc(hist,0,&maxVal);
			hist=hist*255/maxVal;
			//计算反向投影图
			calcBackProject(vecImg,vecChannel,hist,backP,vecRange,1);
			//camshift跟踪位置
			Rect search=rt;
			RotatedRect rrt=CamShift(backP,search,TermCriteria(TermCriteria::COUNT+TermCriteria::EPS,10,1));
			Rect rt2=rrt.boundingRect();
			rt&=rt2;

			//跟踪框画到视频上
			rectangle(result,rt,Scalar(0,255,0),2);			
		}

		//结果显示
		imshow("原图",frame);
		moveWindow("原图",0,0);

		imshow("膨胀运算",foreground);
		moveWindow("膨胀运算",0,350);

		imshow("反向投影",backP);
		moveWindow("反向投影",400,350);

		imshow("跟踪效果",result);
		moveWindow("跟踪效果",800,350);
		waitKey(30);	
	}
		
	getchar();
	return 0;
}

3.avi是我写的一个目标运动仿真,用来做这个实验

BackgroundSubtractorMOG 

http://blog.csdn.net/xiaowei_cqu/article/details/23689189

int main()
{  
    VideoCapture video("3.avi");  
    Mat frame,mask,thresholdImage, output;  
	BackgroundSubtractorMOG bgSubtractor;  
    while(true)
	{ 
		video>>frame;  
		if (frame.empty())
			break;
        bgSubtractor(frame,mask,0.1);  
        imshow("mask",mask);  
        waitKey(10);  
    }  
    return 0;  
}  



 

 

评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值