(六)OpenCV视频分析与对象跟踪_04_稀疏KLT_光流的对象跟踪

  1. 移动对象跟踪三要素
    外观模型、图像表示、移动模型
  2. 稀疏光流-LK
    亮度恒定、时间持续性或"微小移动"、空间一致性
    Sparse Optical Flow(Lucas-Kanade)
    calcOpticalFlowPyrLK + goodFeaturesToTrack(角点检测)
  3. 稠密光流-HF
    calcOpticalFlowFarneback
  4. 输入第一帧图像、特征点检测选择、保存特征点、输入第二帧图像(开始跟踪)
    跟踪特征点、删除损失特征点、保存跟踪特征点
    用第二帧图像替换第一帧图像、用后续输入帧替换第二帧图像、选择新的特征点来替换损失特征点数据、保存特征点数据
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

VideoCapture capture;
Mat frame, gray, pre_gray;
RNG rng;

void detectFeatures(Mat& gray);//检测角点
vector<Point2f> corners; // shi-tomasi角点检测-特征数据
void drawFeatures(Mat& frame);//绘制角点

vector<Point2f> corners_init;//初始化特征数据
vector<Point2f> pyLk[2];//用于calcOpticalFlowPyrLK//保存当前帧和前一帧的角点位置

void KLTrackFeature(Mat& frame);//稀疏光流跟踪,KLT
static vector<uchar> status; // 特征点跟踪成功标志位//用于calcOpticalFlowPyrLK
static vector<float> errors; // 跟踪时候区域误差和//用于calcOpticalFlowPyrLK
void drawTrackLine(Mat& frame);//绘制跟踪线

//http://www.freesion.com/article/6081117469/
int main(int argc, char** argv)
{
	capture.open("../path.avi");
	if (!capture.isOpened())
	{
		cout << "could not load video..." << endl;
		return -1;
	}

	namedWindow("Video_demo", WINDOW_AUTOSIZE);
	while (capture.read(frame))
	{

		cvtColor(frame, gray, COLOR_BGR2GRAY);

		if (pyLk[0].size() < 40) // 跟踪40个特征点,如果跟踪的时候损失了一些特征点,重新检测,追加
		{
			detectFeatures(gray);//在灰度视频中检测角点
			pyLk[0].insert(pyLk[0].end(), corners.begin(), corners.end());//STL//追加带跟踪的特征点
			corners_init.insert(corners_init.end(), corners.begin(), corners.end());
		}
		else
		{
			cout << "正在跟踪..." << endl;// 表示特征点没有损失,一直在跟踪
		}
		//判断前一帧是否有角点
		if (pre_gray.empty())
			gray.copyTo(pre_gray);//保存前一帧,第一帧过完就不保存了

		KLTrackFeature(frame);// 稀疏光流跟踪,KLT

		drawFeatures(frame);//在源视频上绘制角点

		// 更新前一帧数据
		gray.copyTo(pre_gray); // 只需要灰度图

		imshow("Video_demo", frame);

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

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

void detectFeatures(Mat& gray)
{
	int max_corners = 500;
	double qualityLevel = 0.01;
	int minDistance = 10;
	int blockSize = 3;
	//shi-tomasi角点检测
	goodFeaturesToTrack(gray,
		corners,//输出的角点
		max_corners,//限制角点的个数
		qualityLevel,//qualityLevel设置点的返回质量(通常介于0.10和0.01之间,绝对不超过1.0)
		minDistance,//设置相邻角之间的最小间距
		Mat(),//mask
		blockSize,//blockSize计算角点时需要考虑的区域大小
		false);//使用Shi-Tomasi,如果为true则使用Harris

	cout << "detect features : " << corners.size() << endl;//输出角点个数//不在跟踪的时候输出

	return;
}

void drawFeatures(Mat& frame)
{
	//绘制角点
	//for (size_t i = 0; i < corners.size(); i++)
	//{
	//	circle(frame, corners[i], 2, Scalar(0, 0, 255), 2, 8, 0);
	//}
	for (size_t i = 0; i < pyLk[0].size(); i++)
	{
		circle(frame, pyLk[0][i], 2, Scalar(0, 0, 255), 2, 8, 0);
	}
	return;
}



void KLTrackFeature(Mat& frame)//稀疏光流跟踪,KLT
{
	// 稀疏光流跟踪,KLT
	calcOpticalFlowPyrLK(pre_gray,//要跟踪的图像,8bit
		gray, //在目标图像 跟踪 pre_gray 上的 pyLk 特征点
		pyLk[0],// pre_gray 上的特征点(光流)的坐标位置;点坐标必须是单精度浮点数
		pyLk[1], // 如果在 gray 上跟踪到了 pre_gray 上的 prevPts[i],则在 nextPts[i] 上保存该特征点现在的坐标,nextPts与prevPts尺寸相同
		status,// 输出状态向量(无符号char)
		errors);// 跟踪时候区域误差和
	int k = 0; // 保存跟踪到的特征点数,最后将特征点的尺寸 resize 为 k
	// 特征点过滤
	for (int i = 0; i < pyLk[1].size(); i++)
	{
		// 距离,为了计算更快,没有用欧几里得距离,用的L1
		double dist = abs(pyLk[0][i].x - pyLk[1][i].x) + abs(pyLk[0][i].y - pyLk[1][i].y);
		if (dist > 2 && status[i]) // 跟踪到的特征点,且距离移动了2以上的
		{
			corners_init[k] = corners_init[i]; // 将跟踪到的移动了的特征点在vector中连续起来,剔掉损失的和静止不动的特征点(这些跟踪点在前面帧中)
			pyLk[1][k++] = pyLk[1][i]; // 同上 (只是这些跟踪点在当前帧中)
		}
	}
	// 保存特征点并绘制跟踪轨迹
	corners_init.resize(k); // 重新设置尺寸, 下标k之后的clear掉
	pyLk[1].resize(k);
	drawTrackLine(frame);
	swap(pyLk[1], pyLk[0]); // 交换,将此帧跟踪到的特征点作为下一帧的待跟踪点

	return;
}


void drawTrackLine(Mat& frame)// 在跟踪到的且移动了的特征点(光流)的开始跟踪的位置 到 当前跟踪到的位置之间绘制线段
{
	for (size_t i = 0; i < pyLk[1].size(); i++)
	{
		line(frame, corners_init[i], pyLk[1][i], Scalar(rng.uniform(0, 255)), 1, 8, 0);
		circle(frame, pyLk[1][i], 2, Scalar(0, 0, 255), 2, 8, 0);
	}
}

输出结果:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值