Camshift跟踪(下)

想通过camShift中的RotatedRect成员center来勾勒出目标的运动轨迹。

即将质心存入vector中,在需要显示时,用line来展现出来。

以下为代码:

// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//


#include "stdafx.h"
#include <iostream>
#include <OpenCV245.h>


using namespace std;
using namespace cv;


Mat image;

bool backprojMode = false;  //表示是否要进入反向投影模式,ture表示准备进入反向投影模式
bool selectObject = false;  //用来判断是否选中,当鼠标左键按下时为ture,左键松开时为false

int trackObject = 0;        //代表跟踪目标数目

bool showHist = true;       //是否显示直方图

Point origin;               //选中的起点
Rect selection;             //选中的区域

Point centroid;             //质心
Mat   trackPic;            //轨迹图
Point startP;               //前点
Point endP;                 //后点
bool mark = false;


vector<Point> trackPointVec;

int vmin = 10, vmax = 256, smin = 30;


//鼠标事件响应函数,这个函数从按下左键时开始响应直到左键释放
static void onMouse(int event, int x, int y, int, void* )
{
	if( selectObject )
	{
		selection.x = MIN(x, origin.x);
		selection.y = MIN(y, origin.y);

		selection.width = abs(x - origin.x);
		selection.height = abs(y - origin.y);
	}


	switch (event)
	{
	case CV_EVENT_LBUTTONDOWN:  //按下鼠标时,捕获点origin

		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;
	}
}


//const char* keys = 
//{
//	"{1|  | 0 | camera number}"
//};


//const char* keys = { "{1| | 0 | camera number}" };

int _tmain(int argc, _TCHAR* argv[])
{


	const string strFilePath = "C:\\Users\\sony\\Desktop\\k\\video\\停车场出入口.flv";

	

	VideoCapture cap;
	Rect trackWindow; //跟踪的窗口
	int hsize = 16; //创建直方图时要用的常量
	float hranges[] = {0, 180};
	const float* phranges = hranges;

	

	cap.open(strFilePath);  
	if (!cap.isOpened())  
	{  
		cout << "fail to open the video"<<endl;  
		return -1;  
	} 

	

	//关于显示窗口的一些设置
	namedWindow("Histogram", 0);
	namedWindow("CamShift Demo", 0);

	//设置鼠标事件,把鼠标响应与onMouse函数关联起来
	setMouseCallback("CamShift Demo", onMouse, 0);

	//创建三个滑块条,特定条件用滑块条选择不同参数能获得较好的跟踪效果  
	createTrackbar( "Vmin", "CamShift Demo", &vmin, 256, 0 );  
	createTrackbar( "Vmax", "CamShift Demo", &vmax, 256, 0 );  
	createTrackbar( "Smin", "CamShift Demo", &smin, 256, 0 );  

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


	for(;;)
	{
		if ( !paused ) //没有暂停
		{
			cap >> frame; //从摄像头输入frame
			if(frame.empty())
				break;
		}

		frame.copyTo(image);

		

		if( !paused )
		{
			cvtColor(image, hsv, CV_BGR2HSV);

			if( trackObject )   //松开鼠标左键时,trackObject为-1,执行核心部分
			{
				int _vmin = vmin, _vmax = vmax;  //int vmin = 10, vmax = 256, smin = 30;

				//inRange用来检查元素的取值范围是否在另两个矩阵的元素取值之间,返回验证矩阵mask(0-1矩阵)  
				//这里用于制作掩膜板,只处理像素值为H:0~180,S:smin~256, V:vmin~vmax之间的部分。mask是要求的,单通道  

				inRange(hsv, Scalar(0, smin, MIN(_vmin, _vmax)),
					Scalar(180, 256, MAX(_vmin, _vmax)), mask);

				int ch[] = {0, 0};

				hue.create(hsv.size(), hsv.depth());
				mixChannels(&hsv, 1, &hue, 1, ch, 1);//将H分量拷贝到hue中,其他分量不拷贝

				if ( trackObject < 0 )
				{
					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);
					normalize(hist, hist, 0, 255, CV_MINMAX);


					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);

					for( int i = 0; i < hsize; i++ )
						buf.at<Vec3b>(i) = Vec3b(saturate_cast<uchar>(i*180/hsize), 255, 255);

					cvtColor(buf, buf, CV_HSV2BGR);

					for( int i = 0; i < hsize; i++ )
					{
						int val = saturate_cast<int>(hist.at<float>(i)*histimg.rows/255);

						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);

				//计算两个矩阵backproj、mask的每个元素的按位与,返回backproj
				backproj &= mask;

				RotatedRect trackBox = CamShift(backproj, trackWindow, TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1));

				if( trackWindow.area() <= 1 )
				{
					int cols = backproj.cols, rows = backproj.rows, r = (MIN(cols, rows) + 5)/6;

					trackWindow = Rect(trackWindow.x - r, trackWindow.y - r, trackWindow.x + r, trackWindow.y + r) &
						Rect(0, 0, cols, rows);
				}

				if (backprojMode)
					cvtColor( backproj, image, CV_GRAY2BGR);

				ellipse(image, trackBox, Scalar(0, 0, 255), 3, CV_AA);

				trackPointVec.push_back(trackBox.center);

				/*trackPic = Mat::zeros(backproj.size(), CV_8UC3);*/

				//让if中的内容只执行一次
				/*if ( mark )
				{
				startP = Point(0,0);
				startP = trackBox.center;
				mark = !mark;
				}
				*/

				/*line(trackPic, startP, trackBox.center, Scalar(255, 0, 0), 3);

				startP = trackBox.center;

				imshow( "trackpicture",trackPic);*/
			}
		}

		else if( trackObject < 0 )
			paused = false;

		if( selectObject && selection.width > 0 && selection.height > 0 )  
		{  
			Mat roi(image, selection);  
			bitwise_not(roi, roi);  
		}  

		if(mark)
		{
			imshow("trackpicture",trackPic);
			mark != mark; 
		}

		imshow( "CamShift Demo", image );  
		imshow( "Histogram", histimg );  

		//显示轨迹

		

		
		
		

		//每轮都要等待用户的按键控制  
		char c = (char)waitKey(300);  
		if( c == 27 )//"Esc"键,直接退出  
			break;  
		switch(c)  
		{  
		case 'b'://转换显示方式  
			backprojMode = !backprojMode;  
			break;  
		case 'c'://停止追踪  
			trackObject = 0;  
			histimg = Scalar::all(0);
			mark = !mark;
			break;  
		case 'h'://隐藏或显示直方图  
			showHist = !showHist;  
			if( !showHist )  
				destroyWindow( "Histogram" );  
			else  
				namedWindow( "Histogram", 1 );  
			break;  
		case 'p'://暂停  
			paused = !paused;//frame停止从摄像头获取图像,只显示旧的图像  
			break;  
		case  't':

			trackPic =Mat::zeros(backproj.size(), CV_8UC3);
			for (vector<Point>::iterator it = trackPointVec.begin(); it != trackPointVec.end(); it++)
			{
				if ( (it+1) != trackPointVec.end() )
				{
					line(trackPic, *it, *(it+1), Scalar(255, 0, 0), 2);
				}
				
			}
			mark = !mark;
		default:  
			;  
		}  
	}

	return 0;
}

效果图如下:

轨迹图:

Camshift跟踪(下)_第1张图片


直方图:

Camshift跟踪(下)_第2张图片


原图:

Camshift跟踪(下)_第3张图片

你可能感兴趣的:(Camshift跟踪(下))