opencv camshift学习

https://blog.csdn.net/qq_37775990/article/details/82558110

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

https://blog.csdn.net/google19890102/article/details/51030884 

 https://blog.csdn.net/tiandijun/article/details/32176199

 

 

#include "core/core.hpp" 

#include "highgui/highgui.hpp" 

#include "imgproc/imgproc.hpp"

#include "video/tracking.hpp"

opencv_core模块,包含核心功能,尤其是底层数据结构与算法函数。
opencv_imgproc模块,包含图像处理函数。
opencv_highgui模块,包含读写图像及视频的函数,以及操作图形用户界面函数
opencv_features2d模块,包含兴趣点检测子,描述子以及兴趣点匹配框架。
opencv_calib3d模块,包含运动估算,特征跟踪以及前景提取函数与类。
opencv_video模块,包含运动估算,双目集合估算以及前景提取函数与类。
opencv_objdetect模块,包含物体检测函数,如脸部与行人检测。
 

http://www.cnblogs.com/tornadomeet/archive/2012/03/15/2398769.html

https://www.cnblogs.com/yutingliuyl/p/7238037.html

https://www.cnblogs.com/leixiaohua1020/p/3902149.html

对比下面

 

https://blog.csdn.net/qq_15947787/article/details/53161768

https://www.jb51.net/article/132479.htm


#include <iostream>

#include "opencv2/opencv.hpp"

#include <opencv2/imgproc/imgproc.hpp>

#include <opencv2/core/core.hpp>

 

using namespace cv;

using namespace std;

 

Mat image;

bool selectObject = false;   //代表是否在选要跟踪的初始目标,true表示正在用鼠标选择

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

Point origin;   //用于保存鼠标选择第一次单击时点的位置

Rect selection;   //用于保存鼠标选择的矩形框

 

//鼠标选择函数

static void onMouse(int event, int x, int y, int, void*)

{

	if (selectObject)//只有当鼠标左键按下去时才有效,然后通过if里面代码就可以确定所选择的矩形区域selection了

	{

		selection.x = MIN(x, origin.x);//选择区域的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 EVENT_LBUTTONDOWN:	//按下鼠标左键,进行赋初值

		origin = Point(x, y);  //鼠标选择第一次单击时点的位置

		selection = Rect(x, y, 0, 0); //鼠标刚按下去时初始化了一个矩形区域

		selectObject = true;//代表是否在选要跟踪的初始目标,true表示正在用鼠标选择

		break;

	case EVENT_LBUTTONUP:	//鼠标左键抬起

		selectObject = false;

		if (selection.width > 0 && selection.height > 0)

			trackObject = -1;   // 置-1,主程序开始进行meanshift

		break;

	}

}

 

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

	VideoCapture cap(0);  //定义一个摄像头捕捉的类对象

	Rect trackWindow;

	int hsize = 16;		//直方图特征子区间bin的数目,分成16个区间

	float hranges[] = { 0,180 };//色度 hue 范围

	const float* phranges = hranges;

 

 

	//摄像头未打开的处理方式

	if (!cap.isOpened())

	{

		cout << "***Could not initialize capturing...***\n";

		

	}

 

	namedWindow("meanShift", 0);

	namedWindow("Histogram", 0);

	setMouseCallback("meanShift", onMouse, 0);

	

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

	bool paused = false;

	while (true)

	{

		if (!paused) )//没有暂停

		{

			cap >> frame;//从摄像头抓取一帧图像并输出到frame中

			frame.copyTo(image);

			cvtColor(image, hsv, COLOR_BGR2HSV);

			if (trackObject)//trackObject初始化为0,当鼠标单击松开后为-1

			{

				int from_to[] = { 0, 0 };

				hue.create(hsv.size(), hsv.depth());//hue初始化为与hsv大小深度一样的矩阵,色调的度量是用角度表示的,红绿蓝之间相差120度,反色相差180度

				mixChannels(&hsv, 1, &hue, 1, from_to, 1);//提取h分量

 

				//画直方图

				if (trackObject < 0)//鼠标选择区域松开后,该函数内部又将其赋值1

				{
                                    //此处的构造函数roi用的是Mat hue的矩阵头,且roi的数据指针指向hue,即共用相同的数据,select为其感兴趣的区域

					Mat roi(hue, selection);

					calcHist(&roi, 1, 0, Mat(), hist, 1, &hsize, &phranges);//hist保存的hsv的最小值

					normalize(hist, hist, 0, 255, NORM_MINMAX);			//直方图归一化到0-255	

					trackWindow = selection;

					trackObject = 1;									//置1,除非重新框选目标,否则只执行一次

 

					histimg = Scalar::all(0);//这里的all(0)表示的是标量全部清0

					int binW = histimg.cols / hsize;//320/16;每个区间可以占用histimg20个列(column)

					Mat buf(1, hsize, CV_8UC3);//定义一个缓冲单bin矩阵,1行16列

					for (int i = 0; i < hsize; i++)

						buf.at<Vec3b>(i) = Vec3b(saturate_cast<uchar>(i*180. / hsize), 255, 255);//Vec3b为3个char值的向量,存放颜色数据

					cvtColor(buf, buf, COLOR_HSV2BGR);

 

					for (int i = 0; i < hsize; i++)

					{

						int val = saturate_cast<int>(hist.at<float>(i)*histimg.rows / 255);//获取直方图高度,根据histimg图像的高换算成0到histimg.rows的值

						rectangle(histimg, Point(i*binW, histimg.rows),//画出直方图,左上角坐标,右下角坐标,高度,颜色,大小,线型

							Point((i + 1)*binW, histimg.rows - val),//rows-va1是因为矩阵是左上角开始数的,y轴向下,而要画的图是y轴向上

							Scalar(buf.at<Vec3b>(i)), -1, 8);

					}

				}

				//进行meanshift

				calcBackProject(&hue, 1, 0, hist, backproj, &phranges);

				TermCriteria criteria(TermCriteria::EPS | TermCriteria::COUNT, 10, 1);

				meanShift(backproj, trackWindow, criteria);

				rectangle(image, trackWindow, Scalar(255, 0, 0), 3);

			}

 

 

		}

		if (selectObject && selection.width>0 && selection.height > 0)

 

		{

 

			Mat roi(image, selection);

 

			bitwise_not(roi, roi);

 

		}

		imshow("meanShift", image);

		imshow("Histogram", histimg);

 

		char c = (char)waitKey(10);//等待用户按键

		if (c == 27)

			break;

 

 

 

	

	}

return 0;

}

 

 

 

 

 

 

 

 

 

 

 

 


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

}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值