OpenCV 基于Lucas-Kanade光流算法的对象跟踪

视频来源:https://www.youtube.com/watch?v=EvIwL0aSCZY

以下代码用OpenCV实现了视频中基于Lucas-Kanade光流算法【OpenCV中的实现为calcOpticalFlowPyrLK函数】的对象跟踪。为了规避孔径问题,以下代码实现仅对角点【通过goodFeaturesToTrack函数做角点检测】做光流计算。

//
//  main.cpp
//  opencv-learning
//
//  Created by _R on 2019/1/9.
//  Copyright © 2019 _R. All rights reserved.
//

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;


int main(int argc, char* argv[])
{
    VideoCapture video = VideoCapture("/Users/_R/Desktop/Flying_disc_freestyle_640x360.mp4");
    if (!video.isOpened()) {
        cout << "could not load video file ..." << endl;
        return -1;
    }
    
    Mat frame, frame_in_gray, prev_frame, prev_frame_in_gray;
    vector<Point2f> initPoints;
    vector<Point2f> feature_points[2];
    vector<uchar> status_of_feature_points;
    vector<float> errors;
    double count_of_success = 0;
    double distance_between_feature_points = 0.0;
    
    
    
    namedWindow("flying_disc", WINDOW_AUTOSIZE);
    
    while (video.read(frame)) {
        cvtColor(frame, frame_in_gray, COLOR_BGR2GRAY);
        
        if (feature_points[0].empty() || initPoints.size() < 10) {
            
            goodFeaturesToTrack(frame_in_gray, feature_points[0], 1000, 0.01, 10.0);
            initPoints.assign(feature_points[0].begin(), feature_points[0].end());
            
        } else {
            
            goodFeaturesToTrack(frame_in_gray, feature_points[1], 1000, 0.01, 10.0);
            calcOpticalFlowPyrLK(prev_frame_in_gray, frame_in_gray, feature_points[0], feature_points[1], status_of_feature_points, errors);
            
            count_of_success = 0;
            for (size_t t=0; t<status_of_feature_points.size(); t++) {
                distance_between_feature_points = abs(feature_points[0][t].x - feature_points[1][t].x) + abs(feature_points[0][t].y - feature_points[1][t].y);
                
                if (distance_between_feature_points > 2 && status_of_feature_points[t]) {
                    initPoints[count_of_success] = initPoints[t];
                    feature_points[1][count_of_success] = feature_points[1][t];
                    count_of_success++;
                }
                
            }
            initPoints.resize(count_of_success);
            feature_points[1].resize(count_of_success);
            std::swap(feature_points[0], feature_points[1]);
            
            cout << initPoints.size() << " " << feature_points[0].size() << endl;
            
            for (size_t t=0; t<feature_points[0].size(); t++) {
                cout << "(" << initPoints[t].x << "," << initPoints[t].y << ")" << " " << "(" << feature_points[0][t].x << "," << feature_points[0][t].y << ")" << endl;
                
                line(frame, initPoints[t], feature_points[0][t], Scalar(0,255,0));
                circle(frame, feature_points[0][t], 2, Scalar(0,0,255));
            }
            
            cout << endl;
        }
        
        frame.copyTo(prev_frame);
        frame_in_gray.copyTo(prev_frame_in_gray);
        
        imshow("flying_disc", frame);
        
        char c = waitKey(50);
        if (c == 27) {
            break;
        }
    }
    
    waitKey(0);
    video.release();
    return 0;
}


效果展示

在这里插入图片描述

Lucas-Kanade光流算法是一种基于局部区域的光流算法,它假设图像中任意两帧之间的像素值变化是平滑的,然后使用局部区域内的像素值变化来估计每个像素的运动向量。在本文中,我们将介绍如何在OpenCV中自实现Lucas-Kanade光流算法。 步骤一:读取图像 首先,我们需要读取两张待计算光流的图像。在本例中,我们将使用名为“frame1”和“frame2”的两张图像。 Mat frame1 = imread("frame1.jpg"); Mat frame2 = imread("frame2.jpg"); 步骤二:提取关键点 接下来,我们需要从两个图像中提取关键点。我们可以使用OpenCV中的FAST或SIFT等算法提取关键点。在本例中,我们将使用FAST算法。 vector<KeyPoint> keypoints1, keypoints2; int threshold = 20; // 设置FAST算法的阈值 bool nonmaxSuppression = true; // 设置是否进行非极大值抑制 FAST(frame1, keypoints1, threshold, nonmaxSuppression); FAST(frame2, keypoints2, threshold, nonmaxSuppression); 步骤三:计算光流 现在我们已经提取了关键点,接下来我们需要计算这些关键点的光流向量。我们可以使用OpenCV中的calcOpticalFlowPyrLK函数来计算光流向量。该函数使用金字塔表示法和Lucas-Kanade算法来计算光流向量。 vector<uchar> status; vector<float> err; Size winSize = Size(21, 21); // 设置光流计算窗口的大小 int maxLevel = 3; // 设置金字塔的最大层数 TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01); // 设置终止条件 calcOpticalFlowPyrLK(frame1, frame2, keypoints1, keypoints2, status, err, winSize, maxLevel, criteria); 步骤四:绘制光流 最后,我们可以将光流向量绘制在第一张图像上,以便我们可以观察到光流的效果。 for (int i = 0; i < keypoints1.size(); i++) { if (status[i]) { Point2f p1 = keypoints1[i].pt; Point2f p2 = keypoints2[i].pt; line(frame1, p1, p2, Scalar(0, 0, 255), 2); } } imshow("Optical Flow", frame1); 完整代码:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值