opencv:CAMShift对象跟踪

1060 篇文章 303 订阅

当前使用版本opencv4.3

  • CAMShift(ContinuouslyAdaptive Mean-Shift)持续自适应均值位移
  • Mean-Shift分割算法:找到空间上颜色分布的峰值
  • 选择特征模型 - 选择转换为特征空间(直方图量化特征) - 特征空间PDF模型数据
  • CAMShift(窗口尺寸自动变化、适合变形目标检测)
  • 流程:第一帧、读取第一帧、选择ROI区域、HSV空间H通道直方图表达、直方图反向投影、CAMShift、绘制位置更新显示
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;
//HSV
int smin = 30;
int smax = 255;
int vmin = 40;
int vmax = 255;
//calcHist参数
int histSize = 16;//区间的个数
float hue_ranges[] = { 0,180 };
const float* ranges = hue_ranges;

//https://blog.csdn.net/kilotwo/article/details/89053311
int main(int argc, char** argv)
{
	VideoCapture capture;
	//capture.open(0);
	capture.open("../path.mp4");
	if (!capture.isOpened())
	{
		cout << "could not load video..." << endl;
		return -1;
	}

	bool firstRead = true;//用于判断是否第一次读取视频
	Rect selection;//selectROI用鼠标选择的ROI区域
	Mat frame,hsv,mask,hue, temp_histogram, backprojection;
	Mat Histogram = Mat::zeros(300,300,CV_8UC3);
	namedWindow("CAMShift Tracking", WINDOW_AUTOSIZE);
	while (capture.read(frame))
	{
		if (firstRead)
		{
			//获取第一帧的ROI区域
			Rect2d first_img = selectROI("CAMShift Tracking", frame);//在"CAMShift Tracking"窗口的frame图像上用鼠标选择ROI区域
			selection.x = first_img.x;
			selection.y = first_img.y;
			selection.width = first_img.width;
			selection.height = first_img.height;
			cout << "ROI的x值为:		" << selection.x << endl;
			cout << "ROI的y值为:		" << selection.y << endl;
			cout << "ROI的width值为:		" << selection.width << endl;
			cout << "ROI的height值为:	" << selection.height << endl;
		}

		//转换到HSV空间
		cvtColor(frame, hsv, COLOR_BGR2HSV);
		//测试矩阵frame的元素是否在其他两个矩阵的值之间//提取黄色
		inRange(hsv, Scalar(0, smin, vmin), Scalar(180, smax, vmax), mask);

		hue = Mat(hsv.size(), hsv.depth());
		int channels[] = { 0,0 };//fromto映射//指定被复制通道与要复制到的位置组成的索引对
		size_t npairs = 1;指定被复制通道与要复制到的位置channels[]组成的索引对
		mixChannels(&hsv, 1, &hue, 1, channels, npairs);	//输入矩阵通道 重新排列到 输出矩阵通道(HSV中的H值)

		if (firstRead)
		{
		//计算ROI直方图
		Mat ROI(hue, selection);//Mat& image , Rect& roi
		Mat MaskROI(mask, selection);
		calcHist(&ROI, 1, 0, MaskROI, temp_histogram, 1, &histSize, &ranges);//计算直方图
		normalize(temp_histogram, temp_histogram, 0, 255, NORM_MINMAX);//归一化

		//显示直方图图像
		int bins = Histogram.cols / histSize; //300/16 = 18.5 单个区间宽度
		//定义一个缓冲单bins矩阵,1行16列,用于存放颜色数据,用于直方图histSize个bin的“染色”
		Mat ColorIndex = Mat(1, histSize, CV_8UC3);//1行histSize=16列
		for (int i = 0; i < histSize; i++)
		{
			ColorIndex.at<Vec3b>(0, i) = Vec3b(saturate_cast<uchar>(i * 180 / histSize), 255, 255);//只是为了好看
		}
		cvtColor(ColorIndex, ColorIndex, COLOR_HSV2BGR);
		for (int j = 0; j < histSize; j++)
		{
			//value是直方图temp_histogram的相对Histogram的高度
			//temp_histogram.at(i)获取了第i个bin直方图数据,除以255后得到百分比
			//再乘以Histogram的行数就得到了相对高度,最后进行int的强制类型转换,转换为整数。
			int  value = saturate_cast<int>(temp_histogram.at<float>(j)*Histogram.rows / 255);
			//之后使用rectangle()函数进行16个bin的绘制
			//值得注意的是矩阵的坐标系以左上角为原点,y轴是向下的
			//而需要展示给人看的直方图图案是左下角为原点,y轴向上的
			//因此rectangle的两个标定点的纵坐标是Histogram.rows和(Histogram.rows - val)而不是0和val
			rectangle(Histogram,
				Point( j*bins,	    Histogram.rows), //矩阵对角点:左下角
				Point((j + 1)*bins, Histogram.rows - value), //矩阵对角点:右上角
				Scalar(ColorIndex.at<Vec3b>(0, j)), -1, 8, 0);
		}
		firstRead = false;//需要绘制第一帧的直方图
		}

		//直方图反向投影
		/*void calcBackProject(
			const Mat* images,  //输入的数组
			int nimages,        //输入数组的个数
			const int* channels,    //需要统计的通道索引
			InputArray hist,    //输入的直方图
			OutputArray backProject,//目标的反向投影
			const float** ranges,   //每一位数值的取值范围
			double scale=1,     //输出方向投影的缩放因子
			bool uniform=true   //指示直方图是否均匀的标识符
			)
		*/
		//用来计算像素和直方图模型中像素吻合度的方法
		calcBackProject(&hue, 1, 0, temp_histogram, backprojection, &ranges);
		backprojection &= mask;//a&=b 即 a=a&b  其中&为位与运算//给b取了一个别名叫a,所有对b的操作都是直接作用于a

		//CAMShift
		RotatedRect trackBox = CamShift(
			backprojection, //反向投影
			selection,//矩形搜索框
			TermCriteria((TermCriteria::COUNT | TermCriteria::EPS),10,1));//迭代中止条件
		
		//绘制位置更新显示在frame上
		//获取CamShift的返回值,是一个旋转矩形,根据旋转矩形绘制一个椭圆形显示在图像上作为追踪结果。
		ellipse(frame, trackBox, Scalar(255, 0, 255), 3, 8);

		if (firstRead) 
		{
			firstRead = false;
		}
		imshow("CAMShift Tracking", frame);
		imshow("Histogram", Histogram);

		char c = waitKey(100);
		if (c == 27)
		{
			break;
		}
	}

	capture.release();
	waitKey(0);
	return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值