Optical Flow

Optical Flow

参考博客:

https://my.oschina.net/u/3702502/blog/1815343/

一.算法了解

光流Optical Flow)是一种研究图像对齐的算法,一般包括两大类:稀疏光流稠密光流。顾名思义,稀疏光流就是研究图像中稀疏点的光流,这些点一般是角点稠密光流则是研究图像中所有点的偏移量

1.稀疏光流

2.稠密光流

由于网上有较多的解释,此处附一个百科解释

参考网址:

https://baike.baidu.com/item/Optical Flow/19180399?fr=aladdin

二.代码实现

1.基于特征点(角点)的稀疏光流:Lucas-Kanade Optical Flow

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/video.hpp>
using namespace cv;
using namespace std;
int main(int argc, char **argv)
{
    const string about =
        "This sample demonstrates Lucas-Kanade Optical Flow calculation.\n"
        "The example file can be downloaded from:\n"
        "  https://www.bogotobogo.com/python/OpenCV_Python/images/mean_shift_tracking/slow_traffic_small.mp4";
    const string keys =
        "{ h help |      | print this help message }"
        "{ @image |<none>| path to image file }";
    CommandLineParser parser(argc, argv, keys);
    parser.about(about);
    if (parser.has("help"))
    {
        parser.printMessage();
        return 0;
    }
    string filename = parser.get<string>("@image");
    if (!parser.check())
    {
        parser.printErrors();
        return 0;
    }
    VideoCapture capture(filename);
    if (!capture.isOpened()){
        //error in opening the video input
        cerr << "Unable to open file!" << endl;
        return 0;
    }
    // Create some random colors 随机颜色,后期画光流需要
    vector<Scalar> colors;
    RNG rng;
    for(int i = 0; i < 100; i++)
    {
        int r = rng.uniform(0, 256);
        int g = rng.uniform(0, 256);
        int b = rng.uniform(0, 256);
        colors.push_back(Scalar(r,g,b));
    }
    Mat old_frame, old_gray;
    vector<Point2f> p0, p1;//特征点,p0为初始通过Shi-Tomas获取的角点,p1为检测到的对应角点(有好有坏,后期会进行选择)
    // Take first frame and find corners in it
    capture >> old_frame;
    cvtColor(old_frame, old_gray, COLOR_BGR2GRAY);//由于角点检测输入为灰度图像,此处转换
    goodFeaturesToTrack(old_gray, p0, 100, 0.3, 7, Mat(), 7, false, 0.04);//p0中角点的检测与初始化
    // Create a mask image for drawing purposes
    Mat mask = Mat::zeros(old_frame.size(), old_frame.type());//创建一个与frame大小、类型相同的掩膜
    while(true){
        Mat frame, frame_gray;
        capture >> frame;
        if (frame.empty())
            break;
        cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
        // calculate optical flow
        vector<uchar> status;//特征点检测的状态,相近(基本成功)为1,检测失败为0
        vector<float> err;
        TermCriteria criteria = TermCriteria((TermCriteria::COUNT) + (TermCriteria::EPS), 10, 0.03);
        calcOpticalFlowPyrLK(old_gray, frame_gray, p0, p1, status, err, Size(15,15), 2, criteria);//此处进行稀疏光流的计算,得到输出特征点向量p1
        vector<Point2f> good_new;//好的可以继续使用的特征点(角点)
        for(uint i = 0; i < p0.size(); i++)
        {
            // Select good points
            if(status[i] == 1) {
                good_new.push_back(p1[i]);//将匹配成功的特征点存入向量
                // draw the tracks
                line(mask,p1[i], p0[i], colors[i], 2);//在掩膜上连接初始特征点与检测到的特征点(只有检测成功时才画,所以可能会看到最后画出来的为折线,并不光滑)
                circle(frame, p1[i], 5, colors[i], -1);//突出转折的角点(就是标明检测到的特征点)
            }
        }
        Mat img;
        add(frame, mask, img);//在原图像上添加掩膜并输出到img中
        imshow("Frame", img);//展示检测结果
        int keyboard = waitKey(30);
        if (keyboard == 'q' || keyboard == 27)
            break;
        // Now update the previous frame and previous points
        old_gray = frame_gray.clone();
        p0 = good_new;//将此次检测成功的特征点作为下一次的输入,及不断进行特征点的更新(所以即使某一次检测出错,但后面还是有可能检测出正确的点)
    }
}

ps:

传视频地址时要加参数:

完整命令行:

./<当前路径下的可执行文件>    -@image=<视频文件路径>

运行截图:

在这里插入图片描述

2.基于所有点的稠密光流:Dense Optical Flow

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/video.hpp>
using namespace cv;
using namespace std;
int main()
{
    VideoCapture capture("./vtest.avi");//没有看懂此示例教程获取视频文件路径的方式,你可以自己在此处直接修改视频路径

    if (!capture.isOpened()){
        //error in opening the video input
        cerr << "Unable to open file!" << endl;
        return 0;
    }
    Mat frame1, prvs;
    capture >> frame1;
    cvtColor(frame1, prvs, COLOR_BGR2GRAY);//彩色转灰度
    while(true){
        Mat frame2, next;
        capture >> frame2;
        if (frame2.empty())
            break;
        cvtColor(frame2, next, COLOR_BGR2GRAY);//彩色转灰度
        Mat flow(prvs.size(), CV_32FC2);
        calcOpticalFlowFarneback(prvs, next, flow, 0.5, 3, 15, 3, 5, 1.2, 0);//此处计算没有看到算法原理,不敢乱讲
        // visualization
        Mat flow_parts[2];
        split(flow, flow_parts);
        Mat magnitude, angle, magn_norm;
        cartToPolar(flow_parts[0], flow_parts[1], magnitude, angle, true);
        normalize(magnitude, magn_norm, 0.0f, 1.0f, NORM_MINMAX);
        angle *= ((1.f / 360.f) * (180.f / 255.f));
        //build hsv image
        Mat _hsv[3], hsv, hsv8, bgr;
        _hsv[0] = angle;
        _hsv[1] = Mat::ones(angle.size(), CV_32F);
        _hsv[2] = magn_norm;
        merge(_hsv, 3, hsv);
        hsv.convertTo(hsv8, CV_8U, 255.0);
        cvtColor(hsv8, bgr, COLOR_HSV2BGR);
        imshow("frame2", bgr);
        imshow("frame", frame2);//我自己加的,为了和原图像形成对比
        int keyboard = waitKey(30);
        if (keyboard == 'q' || keyboard == 27)
            break;
        prvs = next;
    }
}

运行截图:

在这里插入图片描述

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值