目标跟踪之Camshift

基本概念

camshift("continuously adaptive mean-shift"的缩写),即连续自适应的 算法。其基本思想是对视频序列的所有图像帧都作MeanShift运算,并将上一帧的结果(即搜索窗口的中心位置和窗口大小)作为下一帧MeanShift算法的搜索窗口的初始值,如此迭代下去。简单点说,meanShift是针对单张图片寻找最优迭代结果,而camShift则是针对视频序列来处理,并对该序列中的每一帧图片都调用meanShift来寻找最优迭代结果。正是由于camShift针对一个视频序列进行处理,从而保证其可以不断调整窗口的大小,如此一来,当目标的大小发生变化的时候,该算法就可以自适应地调整目标区域继续跟踪。算法基本步骤:

  • 初始化搜索窗
  • 计算搜索窗区域的颜色概率分布(反向投影)
  • 运行mean-shift算法,得到搜索窗新的大小和位置。
  • 在下一帧视频图像中用步骤3中的值重新初始化搜索窗的大小和位置,继续从步骤2执行。

示例演示

在OpenCV自带的camShift的例子当中,是通过计算目标在HSV空间下的H分量直方图,通过直方图反向投影得到目标像素的概率分布,然后通过调用OpenCV的CAMSHIFT算法,自动跟踪并调整目标窗口的中心位置与大小。该算法对于简单背景下的单目标跟踪效果较好,但如果被跟踪目标与背景颜色或周围其它目标颜色比较接近,则跟踪效果较差。另外,由于采用颜色特征,所以它对被跟踪目标的形状变化有一定的抵抗能力。完整代码

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;
int main(int argc, char **argv)
{
    
    
	const string about =
		"This sample demonstrates the camshift algorithm.\n"
		"The example file can be downloaded from:\n"
		"  https://www.bogotobogo.com/python/OpenCV_Python/images/mean_shift_tracking/slow_traffic_small.mp4";
	const string keys =
		"{ h help |      | print this help message }"
		"{ @image |<none>| path to image file }";
	CommandLineParser parser(argc, argv, keys);
	parser.about(about);
	if (parser.has("help"))
	{
    
    
		parser.printMessage();
		return 0;
	}
	//string filename = parser.get<string>("@image");
	string filename = "D:\\TestData\\slow_traffic_small.mp4";
	if (!parser.check())
	{
    
    
		parser.printErrors();
		return 0;
	}
	VideoCapture capture(filename);
	if (!capture.isOpened()) {
    
    
		//error in opening the video input
		cerr << "Unable to open file!" << endl;
		return 0;
	}
	Mat frame, roi, hsv_roi, mask;
	// take first frame of the video
	capture >> frame;
	// setup initial location of window
	Rect track_window(300, 200, 100, 50); // simply hardcoded the values
	// set up the ROI for tracking
	roi = frame(track_window);
	cvtColor(roi, hsv_roi, COLOR_BGR2HSV);
	inRange(hsv_roi, Scalar(0, 60, 32), Scalar(180, 255, 255), mask);
	float range_[] = {
    
     0, 180 };
	const float* range[] = {
    
     range_ };
	Mat roi_hist;
	int histSize[] = {
    
     180 };
	int channels[] = {
    
     0 };
	calcHist(&hsv_roi, 1, channels, mask, roi_hist, 1, histSize, range);
	normalize(roi_hist, roi_hist, 0, 255, NORM_MINMAX);
	// Setup the termination criteria, either 10 iteration or move by atleast 1 pt
	TermCriteria term_crit(TermCriteria::EPS | TermCriteria::COUNT, 10, 1);
	while (true) {
    
    
		Mat hsv, dst;
		capture >> frame;
		if (frame.empty())
			break;
		cvtColor(frame, hsv, COLOR_BGR2HSV);
		calcBackProject(&hsv, 1, channels, roi_hist, dst, range);
		// apply camshift to get the new location
		RotatedRect rot_rect = CamShift(dst, track_window, term_crit);
		// Draw it on image
		Point2f points[4];
		rot_rect.points(points);
		for (int i = 0; i < 4; i++)
			line(frame, points[i], points[(i + 1) % 4], 255, 2);
		imshow("img2", frame);
		int keyboard = waitKey(30);
		if (keyboard == 'q' || keyboard == 27)
			break;
	}
}

运行结果

在这里插入图片描述

参考资料

  • 学习OpenCV(中文版)[M]

猜你喜欢

转载自blog.csdn.net/webzhuce/article/details/115447041