图像处理|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)
文章图片

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

    推荐阅读