欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Opencv 稀疏光流法跟踪详细教程

程序员文章站 2022-06-15 09:50:34
...

Opencv 稀疏光流法跟踪详细教程

#include <iostream>  
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <math.h>
#include <stdio.h>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/videoio.hpp>
#include <chrono>
#include <fstream>
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>

#include "opencv2/calib3d/calib3d.hpp"
#include <cctype>
#include <string.h>
#include <time.h>

#include <windows.h>
#include <cstdio>
#include<windows.h>
#include"glew.h"
#include<GL/GL.h>
#include<GL/GLU.h>

//#include <sl/Camera.hpp>

using namespace std;
using namespace cv;

Mat frame,gray;
Mat pre_frame, pre_gray;
//通过容器将角点特征数据保存起来
vector<Point2f>features;

//定义两个容器将特征点保存起来
//初始化特征数据
vector<Point2f>inPoints;
//保存两帧的特征点,一个是前一帧,一个是当前帧
vector<Point2f>fpts[2];
//calcOpticalFlowPyrLK这个函数里面的一个追踪成功标志位和追踪区域误差
vector<uchar>status;
vector<float>errors;

//特征点检测---角点检测
void detectFeatures(Mat &inframe, Mat &ingray);
//将角点检测的结果绘制出来
void drawFeature(Mat &inframe);
//KLT算法追踪特征点函数
void KLTtracking(Mat &pre_gray, Mat &gray);
//将轨迹画出的函数
void drawTracklines(Mat &frame);

int main(int argc, char**argv)
{
	VideoCapture capture;
	capture.open(0);
	//capture.open("C:/Users/58214/Pictures/data/4.mp4");
	if (!capture.isOpened())
	{
		printf("could not load video data.....\n");
		return - 1;
	}

	
	namedWindow("input viedo", CV_WINDOW_AUTOSIZE);
	namedWindow("tracking viedo", CV_WINDOW_AUTOSIZE);

	while (capture.read(frame))
	{
		flip(frame, frame, 1);
		//imshow("input viedo", frame);
		//进行角点检测之前,需要将原图转换成灰度图
		cvtColor(frame, gray, COLOR_BGR2GRAY);

		//确保当前帧的角点检测数超过40,否则重新回到前面检测特征点以便更多留下来
		//防止到后面一直检测,特征点一直减少,最后没有了
		if (fpts[0].size() < 40)
		{
			//角点检测
			detectFeatures(frame, gray);
			//初始特征点
			fpts[0].insert(fpts[0].end(), features.begin(), features.end());
			//画出移动轨迹
			inPoints.insert(inPoints.end(), features.begin(), features.end());
		}
		else
		{
			cout << "检测成功" << endl;
		}
		

		//确认前一帧的特征点是否为空
		if (pre_gray.empty())//为空的处理
		{
			gray.copyTo(pre_gray);
		}
		//特征点不为空,开始追踪特征点
		KLTtracking(pre_gray,gray);
		drawFeature(frame);


		//将当前帧的特征点拷贝到前一帧,更新前一帧参数
		gray.copyTo(pre_gray);
		frame.copyTo(pre_frame);


		imshow("input viedo", frame);

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

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

void detectFeatures(Mat &inframe, Mat &ingray)
{
	//角点检测的点数
	int maxcorners = 5000;
	//符合条件
	double qualitylevel = 0.01;
	//两个特征点之间的最小距离
	double mindistance = 10;
	//特征点大小
	int blocksize = 3;
	//角点检测参数
	double k = 0.04;
	//角点检测API
	goodFeaturesToTrack(ingray,features, maxcorners, qualitylevel, 
		mindistance,Mat(),blocksize,false,k);
	cout << "检测特征点数量为:" << features.size() << endl;

}

//绘制角点检测的结果
void drawFeature(Mat &inframe)
{
	for (size_t t = 0; t < features.size(); t++)
	{
		//features[t]是圆的中心
		circle(inframe, features[t], 2, Scalar(0,0,255), 2, 8);
	}
}

//KLT追踪函数
void KLTtracking(Mat &pre_gray, Mat &gray)
{
	//光流法跟踪
	calcOpticalFlowPyrLK(pre_gray, gray, fpts[0], fpts[1], status, errors,Size(21,21),3);
	//新的特征点由fpts[0]转向fpts[1]
	int k = 0;
	//特征点过滤
	for (int i = 0; i < fpts[1].size(); i++)
	{
		//特征点有位移说明特征点在移动,没有位移说明是静止的
		//动的特征点需要考虑标志位,标志位为1说明跟踪成功,如果是0说明失败
		//直接看位移,定义位移
		double dist = abs(fpts[0][i].x - fpts[1][i].x) + (fpts[0][i].y - fpts[1][i].y);
		if (dist > 2 && status[i])//追踪成功的标志
		{
			//重新初始化,删除损失的特征点,k=0
			inPoints[k] = inPoints[i];
			//把特征点拷贝到前一帧,保存跟踪的特征点
			fpts[1][k++] = fpts[1][i];
		}
	}
	//保存特征点并绘制轨迹
	inPoints.resize(k);
	fpts[1].resize(k);
	drawTracklines(frame);
	//将前一帧与当前帧交换
	swap(fpts[0], fpts[1]);
}

//画出轨迹线
void drawTracklines(Mat &frame)
{
	for (size_t t = 0; t < fpts[1].size(); t++)
	{
		//画线
		line(frame, inPoints[t], fpts[1][t], Scalar(22, 156, 69), 1);
		//features[t]是圆的中心
		circle(frame, features[t], 2, Scalar(0, 0, 255), 2, 8);
	}
}
相关标签: Opencv 图像处理