【学习OpenCV】OpenCV中CalcOpticalFlowFarneback()函数分析

OpenCV中CalcOpticalFlowFarneback函数

  • 函数简介

    CalcOpticalFlowFarneback()函数是利用用Gunnar Farneback的算法计算全局性的稠密光流算法(即图像上所有像素点的光流都计算出来),由于要计算图像上所有点的光流,故计算耗时,速度慢。它的核心思想主要源于”Two-Frame Motion Estimation Based on PolynomialExpansion”论文。下面是是对此函数的详细介绍。

  • 函数分析

    void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0,
                                   OutputArray _flow0, double pyr_scale, int levels, int winsize,
                                   int iterations, int poly_n, double poly_sigma, int flags )
    // 参数说明如下:
    // _prev0:输入前一帧图像
    // _next0:输入后一帧图像
    // _flow0:输出的光流
    // pyr_scale:金字塔上下两层之间的尺度关系
    // levels:金字塔层数
    // winsize:均值窗口大小,越大越能denoise并且能够检测快速移动目标,但会引起模糊运动区域
    // iterations:迭代次数
    // poly_n:像素领域大小,一般为5,7等
    // poly_sigma:高斯标注差,一般为1-1.5
    // flags:计算方法。主要包括OPTFLOW_USE_INITIAL_FLOW和OPTFLOW_FARNEBACK_GAUSSIAN
    
    // OpenCV中此函数源码
    void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0,
                                   InputOutputArray _flow0, double pyr_scale, int levels, int winsize,
                                   int iterations, int poly_n, double poly_sigma, int flags )
    {
    #ifdef HAVE_OPENCL
        bool use_opencl = ocl::useOpenCL() && _flow0.isUMat();
        if( use_opencl && ocl_calcOpticalFlowFarneback(_prev0, _next0, _flow0, pyr_scale, levels, winsize, iterations, poly_n, poly_sigma, flags))
        {
            CV_IMPL_ADD(CV_IMPL_OCL);
            return;
        }
    #endif
        // 将_prev0和_next0转换为Mat类型
        Mat prev0 = _prev0.getMat(), next0 = _next0.getMat();
        const int min_size = 32;
        // 创建img指针数组,img[0]指向prev0,img[1]指向next0
        const Mat* img[2] = { &prev0, &next0 };
    
        int i, k;
        double scale;
        Mat prevFlow, flow, fimg;
        // 检查prev0和next0是否大小相同、单通道图像,金字塔尺度关系pyr_scale小于1
        CV_Assert( prev0.size() == next0.size() && prev0.channels() == next0.channels() &&
            prev0.channels() == 1 && pyr_scale < 1 );
        // 创建和prev0大小相同,32位浮点双通道图像
        _flow0.create( prev0.size(), CV_32FC2 );
        // 将_flow0转换成Mat类型
        Mat flow0 = _flow0.getMat();
        // 循环确定金字塔层数
        for( k = 0, scale = 1; k < levels; k++ )
        {
            // scale用于存放第k层图像与原图的尺寸广西
            scale *= pyr_scale;
            // 判断第k层图像行数与min_size关系,确定金字塔层数结束
            if( prev0.cols*scale < min_size || prev0.rows*scale < min_size )
                break;
        }
        // 将计算出的金字塔层数k赋给levels
        levels = k;
        // 遍历金字塔层数
        for( k = levels; k >= 0; k-- )
        {
            // 计算原图与k-1层图像的尺寸关系
            for( i = 0, scale = 1; i < k; i++ )
                scale *= pyr_scale;
            // 定义高斯滤波系数
            double sigma = (1./scale-1)*0.5;
            int smooth_sz = cvRound(sigma*5)|1;
            // 得到高斯滤波器模板大小
            smooth_sz = std::max(smooth_sz, 3);
            // 计算第k层图像矩阵的列数
            int width = cvRound(prev0.cols*scale);
            // 计算第k层图像矩阵的行数
            int height = cvRound(prev0.rows*scale);
    
            if( k > 0 )
                // 创建第k层图像尺寸大小的32位双通道图像,用于存储第k层图像光流flow
                flow.create( height, width, CV_32FC2 );
            else
                // 否则为原图像
                flow = flow0;
            // 如果preFlow未指向任何矩阵数据
            if( prevFlow.empty() )
            {
                // 如果flags为OPTFLOW_USE_INITIAL_FLOW
                if( flags & OPTFLOW_USE_INITIAL_FLOW )
                {
                    // 改变flow0图像大小为flow,用像素关系重采样插值
                    // 插值使用錓NTER_AREA,主要是为了避免波纹出现
                    resize( flow0, flow, Size(width, height), 0, 0, INTER_AREA );
                    // 将flow缩小scale
                    flow *= scale;
                }
                // flags为OPTFLOW_FARNEBACK_GAUSSIAN
                else
                    // 创建一个Mat给flow
                    flow = Mat::zeros( height, width, CV_32FC2 ); 
            }
            else
            {
                // 改变prevFlow图像大小为flow,利用INTER_LINEAR方式进行双线性插值
                resize( prevFlow, flow, Size(width, height), 0, 0, INTER_LINEAR );
                // 将flow增加(1./pyr_sacle)倍
                flow *= 1./pyr_scale;
            }
    
            Mat R[2], I, M;
            for( i = 0; i < 2; i++ )
            {
                // 将img[i]转换为CV_32F格式
                img[i]->convertTo(fimg, CV_32F);
                // 对输出图像fimg进行高斯滤波后用fimg输出
                GaussianBlur(fimg, fimg, Size(smooth_sz, smooth_sz), sigma, sigma);
                // 改变fimg图像大小I,使用双线性插值INTER_LINEAR
                resize( fimg, I, Size(width, height), INTER_LINEAR );
                // 计算邻域图像R[i]
                FarnebackPolyExp( I, R[i], poly_n, poly_sigma );
            }
            // 依据R[0]、R[1]、flow等信息更新矩阵M
            FarnebackUpdateMatrices( R[0], R[1], flow, M, 0, flow.rows );
    
            for( i = 0; i < iterations; i++ )
            {
                // flags为OPTFLOW_FARNEBACK_GAUSSIAN
                if( flags & OPTFLOW_FARNEBACK_GAUSSIAN )
                    // 利用R[0]、R[1]、M等,利用高斯平滑原理,更新光流flow
                    FarnebackUpdateFlow_GaussianBlur( R[0], R[1], flow, M, winsize, i < iterations - 1 );
                // flags为OPTFLOW_USE_INITIAL_FLOW
                else
                    // 利用R[0]、R[1]、M等初始化光流flow
                    FarnebackUpdateFlow_Blur( R[0], R[1], flow, M, winsize, i < iterations - 1 );
            }
            // 将flow赋给prevFlow
            prevFlow = flow;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
  • 参考文献:

    http://www.chinadmd.com/file/poeootxpoprwtxpcwzw6awiu_1.html

    http://www.aichengxu.com/view/2450131

    http://blog.csdn.net/zouxy09/article/details/8683859


calcOpticalFlowFarneback

Computes a dense optical flow using the Gunnar Farneback’s algorithm.

double   pyrScale, int   levels, int   winsize, int   iterations, int   polyN, double   polySigma, int   flags )
Python:   cv2. calcOpticalFlowFarneback (prevImg, nextImg, pyr_scale, levels, winsize, iterations, poly_n, poly_sigma, flags [, flow ] )  → flow
Parameters:
  • prevImg – First 8-bit single-channel input image.   输入单通道图片
  • nextImg – Second input image of the same size and the same type asprevImg . 下一帧图片。
  • flow – Computed flow image that has the same size as prevImg and typeCV_32FC2 .输出的双通道flow
  • pyrScale – Parameter specifying the image scale (<1) to build pyramids for each image. pyrScale=0.5 means a classical pyramid, where each next layer is twice smaller than the previous one.金字塔上上下两层之间的尺度关系。
  • levels – Number of pyramid layers including the initial image.levels=1 means that no extra layers are created and only the original images are used. 金字塔层数
  • winsize – Averaging window size. Larger values increase the algorithm robustness to image noise and give more chances for fast motion detection, but yield more blurred motion field.均值窗口大小,越大越能denoise并且能够检测快速移动目标,但是会引起模糊运动区域。
  • iterations – Number of iterations the algorithm does at each pyramid level.迭代次数。
  • polyN – Size of the pixel neighborhood used to find polynomial expansion in each pixel. Larger values mean that the image will be approximated with smoother surfaces, yielding more robust algorithm and more blurred motion field. Typically, polyN =5 or 7.
  • polySigma – Standard deviation of the Gaussian that is used to smooth derivatives used as a basis for the polynomial expansion. ForpolyN=5 , you can set polySigma=1.1 . For polyN=7 , a good value would be polySigma=1.5 
  • calcOpticalFlowFarneback

    Computes a dense optical flow using the Gunnar Farneback’s algorithm.

    C++:  void  calcOpticalFlowFarneback (InputArray  prevImg, InputArray  nextImg, InputOutputArray  flow, double  pyrScale, int  levels, int  winsize, int  iterations, int  polyN, double  polySigma, int  flags )
    C:  void  cvCalcOpticalFlowFarneback (const CvArr*  prevImg, const CvArr*  nextImg, CvArr*  flow, double  pyrScale, int  levels, int  winsize, int  iterations, int  polyN, double  polySigma, int  flags )
    Python:   cv2. calcOpticalFlowFarneback (prevImg, nextImg, pyr_scale, levels, winsize, iterations, poly_n, poly_sigma, flags [, flow ] ) → flow
    Parameters:
    • prevImg – First 8-bit single-channel input image.
    • nextImg – Second input image of the same size and the same type as prevImg .
    • flow – Computed flow image that has the same size as prevImg and type CV_32FC2 .
    • pyrScale – Parameter specifying the image scale (<1) to build pyramids for each image. pyrScale=0.5 means a classical pyramid, where each next layer is twice smaller than the previous one.
    • levels – Number of pyramid layers including the initial image. levels=1 means that no extra layers are created and only the original images are used.
    • winsize – Averaging window size. Larger values increase the algorithm robustness to image noise and give more chances for fast motion detection, but yield more blurred motion field.
    • iterations – Number of iterations the algorithm does at each pyramid level.
    • polyN – Size of the pixel neighborhood used to find polynomial expansion in each pixel. Larger values mean that the image will be approximated with smoother surfaces, yielding more robust algorithm and more blurred motion field. Typically, polyN=5 or 7.
    • polySigma – Standard deviation of the Gaussian that is used to smooth derivatives used as a basis for the polynomial expansion. For polyN=5 , you can set polySigma=1.1 . For polyN=7 , a good value would be polySigma=1.5 .
    • flags –

      Operation flags that can be a combination of the following:

      • OPTFLOW_USE_INITIAL_FLOW Use the input flow as an initial flow approximation.
      • OPTFLOW_FARNEBACK_GAUSSIAN Use the Gaussian \texttt{winsize}\times\texttt{winsize} filter instead of a box filter of the same size for optical flow estimation. Usually, this option gives z more accurate flow than with a box filter, at the cost of lower speed. Normally, winsize for a Gaussian window should be set to a larger value to achieve the same level of robustness.

    The function finds an optical flow for each prevImg pixel using the [Farneback2003] alorithm so that

    \texttt{prevImg} (y,x)  \sim \texttt{nextImg} ( y + \texttt{flow} (y,x)[1],  x + \texttt{flow} (y,x)[0])

    .
opencv例程二 计算密集的光的流量的Gunnar Farneback’s 算法实现实例

opencv例程二 计算密集的光的流量的Gunnar Farneback’s 算法

#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>

using namespace cv;
using namespace std;
int main()
{
 VideoCapture cap(0);
 if (!cap.isOpened())
 {
  return -1;
 }
 Mat prevgray, gray, flow, cflow, frame;

 do
 {
  cap>>frame;
  cvtColor(frame, gray, CV_RGB2GRAY);

  if (prevgray.data)
  {
   calcOpticalFlowFarneback(prevgray, gray, flow, 0.5, 3,15, 3, 5, 1.2, 0);
   cvtColor(prevgray, cflow, CV_GRAY2RGB);
   
   for (int y = 0; y < cflow.rows; y += 10 )
   {
    for (int x = 0; x < cflow.cols; x += 10)
    {
     Point2f fxy = flow.at<Point2f>(y, x);
     line(cflow, Point(x, y), Point(cvRound(x+fxy.x), cvRound(y+fxy.y)), CV_RGB(0,255,0));
     circle(cflow, Point(x,y), 2, CV_RGB(255, 0, 0), -1);
    }
   }
   imshow("FLOW", cflow);
  }
  if (waitKey(100) >= 0)
  {
   break;
  }
 
  swap(prevgray, gray);
 } while (1);

return 0;
}

 

opencv例程二 <wbr>计算密集的光的流量的Gunnar <wbr>Farneback’s <wbr>算法


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值