opencv:光流估计 L-K

cv::goodFeaturesToTrack(),它不仅支持Harris角点检测,也支持Shi Tomasi算法的角点检测

void goodFeaturesToTrack(
		// 输入图像(CV_8UC1 CV_32FC1)
		InputArray image, 
		/*
		检测到的所有角点,类型为vector或数组,由实际给定的参数类型而定。
		如果是vector,那么它应该是一个包含cv::Point2f的vector对象;
		如果类型是cv::Mat,那么它的每一行对应一个角点,点的x、y位置分别是两列
		*/
		OutputArray corner,
		/*
		规定的特征点最大数目
		比如一副图像你可以找到很多特征点,但是只是取前maxCorners个具有最大特征的那些点作为最后的特征点。
		opencv自有一个机制,随便一个方法,比如计算一下这个点与周围一定领域的点的灰度相差求和,认为这个和越大的那些点是不是越属于特征点。
		*/
		int maxCorners,
		// 质量水平系数(小于1.0的正数,一般在0.01-0.1之间)
		double qualityLevel, 
		// 用于区分相邻两个角点的最小距离(小于这个距离的点将进行合并)
		double minDistance, 
		// 如果指定,它的维度必须和输入图像一致,且在mask=0的点忽略
		InputArray mask = noArray(), 
		/*
		表示在计算角点时参与运算的区域大小,常用值为3,
		但是如果图像的分辨率较高则可以考虑使用较大一点的值。
		*/
		int blockSIze = 3,
		// false='Shi Tomasi metric'
		bool useHarrisDetector = false, 
		// Harris角点检测时用,最好使用默认值0.04
		double k = 0.04 
	)

calcOpticalFlowPyrLK函数

C++: void calcOpticalFlowPyrLK(InputArray prevImg, InputArray nextImg, InputArray prevPts, InputOutputArray nextPts, OutputArray status, OutputArray err, Size winSize=Size(15,15), int maxLevel=3, TermCriteria criteria=TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01), double derivLambda=0.5, int flags=0 )

参数:

prevImg:就是你需要输入计算光流的前一帧图像

nextImg就是下一帧图像(可以看到一次光流就是在两针图像之间找不同)。

prevPts是前一帧图像中的特征点,这个特征点必须自己去找,所以在使用calcOpticalFlowPyrLK函数的时候,前面需要有一个找特征点的操作,那么一般就是找图像的角点

nextPts参数就是计算特征点在第二幅图像中的新的位置,然后输出。特征点的新位置可能变化了,也可能没有变化,那么这种状态就存放在后一个参数status中。err就是新旧两个特征点位置的误差了,也是一个输出矩阵。

其他参数默认吧。

具体实现

#include 
#include 
#include 

using namespace std;
using namespace cv;

void main()
{
	const char* fn = "D:\\vs-projects\\moving\\vtest.avi";
	VideoCapture cap;
	//lastgray,gray对应上一帧和本帧灰度图
	Mat source, result, gray, lastgray;
	//对应上一帧和本帧的特征点,上一帧是给定的,本帧是预测结果
	vector points[2], temp;
	//每一特征点检测状态
	vector status;
	//每一特征点计算误差
	vector err;

	//打开视频
	cap.open(fn);
	if (!cap.isOpened())
	{
		cout << "无法打开视频文件:" << fn << endl;
		return;
	}

	for (;;)
	{
		cap >> source;
		if (source.empty())
			break;

		cvtColor(source, gray, COLOR_BGR2GRAY);
		//点数太少,重新检测特征点
		if (points[0].size() < 10)
		{
			// 角点检测,默认使用Shi-Tomasi角点检测
			goodFeaturesToTrack(gray, points[0], 200, 0.01, 20);
		}

		if (lastgray.empty())
		{
			gray.copyTo(lastgray);
		}

		//计算光流
		calcOpticalFlowPyrLK(lastgray, gray, points[0], points[1], status, err);

		//删除误判点
		int counter = 0;
		for (int i = 0; i < points[1].size(); i++)
		{
			// 距离
			double dist = norm(points[1][i] - points[0][i]);
			if (status[i] && dist >= 2.0 && dist <= 20.0)
			{
				points[0][counter] = points[0][i];
				points[1][counter++] = points[1][i];
			}
		}

		points[0].resize(counter);
		points[1].resize(counter);

		//显示特征点和运动轨迹
		source.copyTo(result);
		for (int i = 0; i < points[1].size(); i++)
		{
			line(result, points[0][i], points[1][i], Scalar(0, 0, 0xff));
			circle(result, points[1][i], 3, Scalar(0, 0xff, 0));
		}

		// 调换
		swap(points[0], points[1]);
		swap(lastgray, gray);

		imshow("源图像", source);
		imshow("检测结果", result);
		//以下检测是否终止(按下ESC终止,对应ASCII 27)
		char key = waitKey(100);
		if (key == 27)
		{
			break;
		}
	}
}

opencv:光流估计 L-K_第1张图片

参考资料:
【OpenCV3】角点检测——cv::goodFeaturesToTrack()与cv::cornerSubPix()详解
目标检测光流法(二):opencv下的光流L-K算法
Opencv学习笔记(九)光流法

你可能感兴趣的:(图像处理,光流估计,L-K,opencv,C++)