meanShift跟踪

这种跟踪和我之前想的一样,应该是首先鼠标选中要跟踪的目标,然后计算其直方图。接下来就根据这个原始直方图计算每一帧的反向投影。(反向投影:opencv docs给出的概念是“一种记录给定图像中的像素点如何适应直方图模型像素分布的方式。简单的讲, 所谓反向投影就是首先计算某一特征的直方图模型,然后使用模型去寻找图像中存在的该特征。) 然后根据反向投影用meanshift跟踪  meanShift(backproj, trackWindow,TermCriteria(CV_TERMCRIT_EPS
| CV_TERMCRIT_ITER, 10, 1));

//#include "StdAfx.h"

#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; //表示是否要进入反向投影模式,ture表示准备进入反向投影模式
bool selectObject = false;//代表是否在选要跟踪的初始目标,true表示正在用鼠标选择
int trackObject = 0; //目标跟踪状态标记
bool showHist = true;//是否显示直方图
Point origin;//用于保存鼠标选择第一次单击时点的位置
Rect selection;//用于保存鼠标选择的矩形框

void onMouse( int event, int x, int y, int, void* )
{
	if(selectObject)//只有当鼠标左键按下去时才有效,然后通过if里面代码就可以确定所选择的矩形区域selection了
	{
		selection.x = MIN(x, origin.x);//矩形左上角顶点坐标
		selection.y = MIN(y, origin.y);
		selection.width = std::abs(x - origin.x);//矩形宽
		selection.height = std::abs(y - origin.y);//矩形高

		selection &= Rect(0, 0, image.cols, image.rows);//用于确保所选的矩形区域在图片范围内
	}

	switch(event)
	{
	case CV_EVENT_LBUTTONDOWN:
		origin = Point(x,y);
		selection = Rect(x,y,0,0);//鼠标刚按下去时初始化了一个矩形区域
		selectObject = true;
		break;
	case CV_EVENT_LBUTTONUP:
		selectObject = false;
		if(selection.width > 0 && selection.height > 0)
			trackObject = -1;
		break;
	}
}

void help()
{
	cout << "\nThis is a demo that shows mean-shift based tracking\n"
		"You select a color objects such as your face and it tracks it.\n"
		"This reads from video camera (0 by default, or the camera number the user enters\n"
		"Usage: \n"
		"    ./camshiftdemo [camera number]\n";

	cout << "\n\nHot keys: \n"
		"\tESC - quit the program\n"
		"\tc - stop the tracking\n"
		"\tb - switch to/from backprojection view\n"
		"\th - show/hide object histogram\n"
		"\tp - pause video\n"
		"To initialize tracking, select the object with mouse\n";
}

int main( int argc, const char** argv )
{
	help();

	VideoCapture cap;   //定义一个摄像头捕捉的类对象
	Rect trackWindow;
	int hsize = 16;
	float hranges[] = {0,180};//hranges在后面的计算直方图函数中要用到
	const float* phranges = hranges;
	char filename[50];
	int count = 0;

	cap.open("C:\\Users\\Administrator\\Desktop\\工作\\testv\\a (6).avi");
	if( !cap.isOpened() )
	{
		help();
		cout << "***Could not initialize capturing...***\n";
		cout << "Current parameter's value: \n";
		cout << "D:\\Vedio_Example\\768x576.avi";
		return -1;
	}

	namedWindow("Histogram", 0);
	namedWindow("CamShift Demo");
	setMouseCallback("CamShift Demo", onMouse, 0);		//鼠标消息响应机制

	Mat frame, hsv, hue, mask, hist, histimg = Mat::zeros(200, 320, CV_8UC3), backproj;
	bool paused = false;

	for(;;)
	{
		if(!paused)//没有暂停
		{
			cap >> frame;//从摄像头抓取一帧图像并输出到frame中
			count++;
			cout<<"帧序数"<<count<<endl;
			if( frame.empty() )
				break;
		}

		frame.copyTo(image);

		if(!paused)//没有按暂停键
		{
			cvtColor(image, hsv, CV_BGR2HSV);//将rgb摄像头帧转化成hsv空间的

			if(trackObject)//trackObject初始化为0,按完键盘的'c'键后也为0,只有在跟踪区域选定的情况下才符合条件,进入跟踪
			{
				//构建掩膜mask
				inRange(hsv, Scalar(0, 30, 10),Scalar(180, 256, 256), mask);

				int ch[] = {0, 0};
				hue.create(hsv.size(), hsv.depth());//hue初始化为与hsv大小深度一样的矩阵,色调的度量是用角度表示的,红绿蓝之间相差120度,反色相差180度
				mixChannels(&hsv, 1, &hue, 1, ch, 1);//将hsv第一个通道(色调,索引为0)的数复制到hue的第一个通道(索引为0)中,最后一个参数代表只是一组通道间的数据复制

				if(trackObject < 0)//鼠标选择区域松开后,该函数内部又将其赋值1
				{
					//分别设置色调图hue及掩码图中的selection部分为其感兴趣区域
					Mat roi(hue, selection), maskroi(mask, selection);

					//calcHist()函数第一个参数为输入矩阵序列,第2个参数表示输入的矩阵数目,第3个参数表示将被计算直方图维数通道的列表,第4个参数表示可选的掩膜函数
					//第5个参数表示输出直方图,第6个参数表示直方图的维数,第7个参数为每一维直方图数组的大小,第8个参数为每一维直方图bin的边界
					calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);//将roi的0通道计算直方图并放入hist中,hsize为每一维直方图的大小
					normalize(hist, hist, 0, 255, CV_MINMAX);//将hist矩阵进行数组范围归一化,都归一化到0~255

					trackWindow = selection;
					trackObject = 1;//只要鼠标选完区域松开后,且没有按键盘清0键'c',则trackObject一直保持为1,因此该if函数只能执行一次,除非重新选择跟踪区域

					histimg = Scalar::all(0);//与按下'c'键是一样的,这里的all(0)表示的是标量全部清0
					int binW = histimg.cols / hsize;  //histing是一个200*300的矩阵,hsize应该是每一个bin的宽度,也就是histing矩阵能分出几个bin出来
					Mat buf(1, hsize, CV_8UC3);//定义一个缓冲单bin矩阵
					for(int i = 0; i < hsize; i++)//saturate_case函数为从一个初始类型准确变换到另一个初始类型
						buf.at<Vec3b>(i) = Vec3b(saturate_cast<uchar>(i*180./hsize), 255, 255);//Vec3b为3个char值的向量
					cvtColor(buf, buf, CV_HSV2BGR);//将hsv又转换成bgr

					for(int i = 0; i < hsize; i++)
					{
						int val = saturate_cast<int>(hist.at<float>(i)*histimg.rows/255);//at函数为返回一个指定数组元素的参考值
						rectangle( histimg, Point(i*binW,histimg.rows),    //在一幅输入图像上画一个简单抽的矩形,指定左上角和右下角,并定义颜色,大小,线型等
							Point((i+1)*binW,histimg.rows - val),
							Scalar(buf.at<Vec3b>(i)), -1, 8 );
					}
				}

				calcBackProject(&hue, 1, 0, hist, backproj, &phranges);//计算直方图的反向投影,计算hue图像0通道直方图hist的反向投影,并存入backproj中
				backproj &= mask;

				//meanShift迭代跟踪
				meanShift(backproj, trackWindow,               //trackWindow为鼠标选择的区域,TermCriteria为确定迭代终止的准则
					TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1));//CV_TERMCRIT_EPS是通过forest_accuracy,CV_TERMCRIT_ITER

				if(backprojMode)
					cvtColor(backproj, image, CV_GRAY2BGR);//因此投影模式下显示的也是rgb图?

				rectangle(image,Point(trackWindow.x,trackWindow.y),Point(trackWindow.x+trackWindow.width,trackWindow.y+trackWindow.height),Scalar(0,0,255),2,CV_AA);
			}
		}
		else if(trackObject < 0)//暂停键按了,另外还重新选定了矩形框,则继续开始执行跟踪
			paused = false;

		//后面的代码是不管pause为真还是为假都要执行的
		imshow("CamShift Demo", image);
	//	sprintf(filename,"%s%d%s","frame",count,".jpg");
	//	imwrite(filename,image);
		imshow("Histogram", histimg);

		char c = (char)waitKey(30);
		if( c == 27 )              //退出键
			break;
		switch(c)
		{
		case 'b':                 //反向投影模型交替
			backprojMode = !backprojMode;
			break;
		case 'c':                 //清零跟踪目标对象
			trackObject = 0;
			histimg = Scalar::all(0);
			break;
		case 'h':                 //显示直方图交替
			showHist = !showHist;
			if( !showHist )
				destroyWindow("Histogram");
			else
				namedWindow("Histogram", 1);
			break;
		case 'p':                 //暂停跟踪交替
			paused = !paused;
			break;
		default:
			;
		}
	}
	return 0;
}
时间: 2024-11-08 23:39:08

meanShift跟踪的相关文章

有关meanshift跟踪的理解(在opencv中实现)(转载)

meanshift算法思想其实很简单:利用概率密度的梯度爬升来寻找局部最优.它要做的就是输入一个在图像的范围,然后一直迭代(朝着重心迭代)直到满足你的要求为止.但是他是怎么用于做图像跟踪的呢?这是我自从学习meanshift以来,一直的困惑.而且网上也没有合理的解释.经过这几天的思考,和对反向投影的理解使得我对它的原理有了大致的认识. 在opencv中,进行meanshift其实很简单,输入一张图像(imgProb),再输入一个开始迭代的方框(windowIn)和一个迭代条件(criteria)

matlab工具箱之人眼检测+meanshift跟踪算法--人眼跟踪

Viola-Jones 人眼检测算法+meanshift跟踪算法 这次的代码是对视频中的人眼部分进行检测加跟踪,检测用的是matlab自带的人眼检测工具箱 下面是matlab官网介绍这个算法的一些东西: http://cn.mathworks.com/help/vision/examples/face-detection-and-tracking-using-camshift.html?searchHighlight=Viola-Jones http://cn.mathworks.com/hel

基于空间直方图meanshift跟踪

近期看了一篇文章<spatiograms versus histograms for region-based tracking>,在此把这篇文章的核心思想及算法推理进行整理. 空间直方图 传统直方图可视为零阶空间直方图,二阶空间直 方图包含直方图每一个bin的空间均值和协方差.这样的空间信息能获取目标更丰富的特征描写叙述.从而提高了跟踪的鲁棒性. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/

自适应尺寸变化的meanshift跟踪

近期在看meanshift方面的文章,看了一篇博文对这篇文章<Robust scale-adaptive meanshift for tracking>寄予非常高的评价,所以把这篇文章简要的读了一下.以下对这篇文章的核心思想和算法实现过程进行简要整理,由于这篇文章与我眼下项目的关系不是太大,所以就不正确这篇文章进行实现了.这篇文章就作为技术储备了. 文章在前面对meanshift的原理进行了整理和推倒.由于之前对meanshift已经有了初步了解.所以在这就不正确meanshift进行介绍了.

基于MeanShift的目标跟踪算法及实现

一.简介 首先扯扯无参密度估计理论,无参密度估计也叫做非参数估计,属于数理统计的一个分支,和参数密度估计共同构成了概率密度估计方法.参数密度估计方法要求特征空间服从一个已知的概率密度函数,在实际的应用中这个条件很难达到.而无参数密度估计方法对先验知识要求最少,完全依靠训练数据进行估计,并且可以用于任意形状的密度估计.所以依靠无参密度估计方法,即不事先规定概率密度函数的结构形式,在某一连续点处的密度函数值可由该点邻域中的若干样本点估计得出.常用的无参密度估计方法有:直方图法.最近邻域法和核密度估计

目标跟踪算法meanshift优缺点

原博主:http://blog.csdn.net/carson2005/article/details/7341051 meanShift算法用于视频目标跟踪时,采用目标的颜色直方图作为搜索特征,通过不断迭代meanShift向量使得算法收敛于目标的真实位置,从而达到跟踪的目的. 传统的meanShift算法在跟踪中有几个优势: (1)算法计算量不大,在目标区域已知的情况下完全可以做到实时跟踪: (2)采用核函数直方图模型,对边缘遮挡.目标旋转.变形和背景运动不敏感. 同时,meanShift算

深度学习与meanshift结合实现跟踪

深度学习一个重要的作用是实现目标的特征实现自动提取过程,传统的meanshift跟踪常用的有颜色直方图,HOG等边缘特征提取目标实现跟踪,则meanshift跟踪可实现的则是用深度学习自动学习的特征来完成跟踪.好处是对于复杂的情况也能很好的提取目标的特征,使得跟踪的鲁棒性和精度更高. 很多人担心的是实时性的问题,其实来说,深度学习完成的过程主要分成两部,预训练预测,预训练完全可以通过离线训练来完成,那么就可以不用考虑这部分时间.而预测部分消耗的时间相对HOG来说,稍微慢一点(实践).那么对于实际

基于meanshift的手势跟踪与电脑鼠标控制(手势交互系统)

转自网络:http://blog.csdn.net/zouxy09/article/details/17913745 基于meanshift的手势跟踪与电脑鼠标控制(手势交互系统) [email protected] http://blog.csdn.net/zouxy09 一年多前开始接触计算机视觉这个领域的时候,年幼无知,倍感吃力.当年惶恐,从而盲从.挣扎了不少时日,感觉自己好像还是处于领域的门外汉一样,在理论与实践的鸿沟中无法挣脱,心里空落落的.在这种挥之不去的烦忧中,某个时候豁然开朗,觉

目标跟踪之meanshift---meanshift2

均值漂移,可以对非刚性物理进行跟踪,是分参数估计,过程是迭代的过程,对光和形态不敏感,缺点是检测目标是固定的,特征不较少,模板背景没有实时更新,没有目标的位置精度预测只是梯度浓聚, 原理: 用文字标书就是在圆弧r范围内也就是划定的目标区域内,进行灰度像素直方图的相加取均值,这个均值就是目标中心的浓聚,借用公式如下 从每个像素开始,首先估计有相似颜色的邻近像素点的密度(局部密度)的梯度,而后利用迭代算法求出局部密度的峰值(即重心点),把能够聚类到同一个峰值点的所有像素点划分成一个区域. 以上为me