opencv--LK光流算法--源码解析

本文深入解析了LK光流算法的opencv源码实现,详细介绍了算法的数学原理、流程及核心函数calcOpticalFlowPyrLK的内部机制,适合对光流追踪感兴趣的研究者和开发者。

因为在理解LK光流opencv源码的过程中,没有找到相关的资料,因此将自己理解的过程及思考贴出来,希望可以记录并便于大家查阅,如果大家对代码有不同的理解或想法,欢迎评论讨论~

opencv--LK光流算法--源码解析

LK光流算法由Jean - Yves Bouguet提出,该算法是基于亮度恒定、时间连续、空间具有一致性的前提下,提出的一种基于特征点的追踪算法。该算法是将求两帧间特征点的最小误差值应用到图像上进而转换为求图像微分、差分的一种迭代算法。

在理解源码时,需要提前掌握LK光流算法的数学原理,否则阅读起来是比较繁难的。

  1. 光流算法用例
    Mat old_frame, old_gray;
    vector<Point2f> p0, 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);

    // Create a mask image for drawing purposes
    Mat mask = Mat::zeros(old_frame.size(), old_frame.type());
	
    while(true){
        Mat frame, frame_gray;

        capture >> frame;
        if (frame.empty())
            break;
        cvtColor(frame, frame_gray, COLOR_BGR2GRAY);

        // calculate optical flow
        vector<uchar> status;
        vector<float> err;
        //设置光流迭代终止标准,10为迭代次数,0.03为迭代终止标准
        TermCriteria criteria = TermCriteria((TermCriteria::COUNT) + (TermCriteria::EPS), 10, 0.03);
        //光流算法,输入前一帧,后一帧,前一帧特征点,后一帧特征点,特征点状态以及微分窗口大小等
        calcOpticalFlowPyrLK(old_gray, frame_gray, p0, p1, status, err, Size(15,15), 2, criteria);

        vector<Point2f> good_new;
        for(uint i = 0; i < p0.size(); i++)
        {
            // Select good points
            if(status[i] == 1) {//如果特征点状态为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);//将绘制出的mask叠加到frame上

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

以上是opencv的官方用例摘自:d:\opencv\opencv3.4.7\opencv3.4.7\samples\cpp\tutorial_code\video\optical_flow\optical_flow.cpp

用例中最为核心的两句代码:goodFeaturesToTrack,calcOpticalFlowPyrLK;其中goodFeaturesToTrack负责查找特征点,calcOpticalFlowPyrLK是光流法的主体,我会以calcOpticalFlowPyrLK为开始,对代码进行解析。

        2. calcOpticalFlowPyrLK函数详解

void cv::calcOpticalFlowPyrLK( InputArray _prevImg, InputArray _nextImg,
                               InputArray _prevPts, InputOutputArray _nextPts,
                               OutputArray _status, OutputArray _err,
                               Size winSize, int maxLevel,
                               TermCriteria criteria,
                               int flags, double minEigThreshold )
{
    //初始化光流,包括winSize:微分窗口;maxLevel:金字塔层数;criteria:迭代终止条件
    //flag;minEigThreshold:特征值求解的最小阈值,小于该值,G不可逆,特征点不可追踪
    Ptr<cv::SparsePyrLKOpticalFlow> optflow = cv::SparsePyrLKOpticalFlow::create(winSize,maxLevel,criteria,flags,minEigThreshold);
    

    //根据初始条件,计算特征点在下一帧中的追踪位置
    optflow->calc(_prevImg,_nextImg,_prevPts,_nextPts,_status,_err);
    //_prevImg:上一帧图像,_nextImg:下一帧图像
    //_prevPts:_prevImg中的特征点,_nextPts:calc计算后,得出的特征点存放地址
    //_status:特征点状态,能否找到该特征点,_err:衡量特征点相似度或误差度
}

其实内层的光流计算代码为:void SparsePyrLKOpticalFlowImpl::calc( InputArray _prevImg, InputArray _nextImg,
                           InputArray _prevPts, InputOutputArray _nextPts,
                           OutputArray _status, OutputArray _err)

  • 2.1 calc函数详解--第一部分--输入变量处理
void SparsePyrLKOpticalFlowImpl::calc( InputArray _prevImg, InputArray _nextImg,
                           InputArray _prevPts, InputOutputArray _nextPts,
                           OutputArray _status, OutputArray _err)
{
    CV_INSTRUMENT_REGION();

    CV_OCL_RUN(ocl::isOpenCLActivated() &&
               (_prevImg.isUMat() || _nextImg.isUMat()) &&
               ocl::Image2D::isFormatSupported(CV_32F, 1, false),
               ocl_calcOpticalFlowPyrLK(_prevImg, _nextImg, _prevPts, _nextPts, _status, _err))

    // Disabled due to bad accuracy
    CV_OVX_RUN(false,
               openvx_pyrlk(_p
评论 10
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值