码迷,mamicode.com
首页 > 其他好文 > 详细

meanShift跟踪

时间:2016-05-12 21:13:22      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:

这种跟踪和我之前想的一样,应该是首先鼠标选中要跟踪的目标,然后计算其直方图。接下来就根据这个原始直方图计算每一帧的反向投影。(反向投影: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;
}


meanShift跟踪

标签:

原文地址:http://blog.csdn.net/yang332233/article/details/51350647

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!