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