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);
}
}