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
calcOpticalFlowFarneback
Computes a dense optical flow using the Gunnar Farneback’s algorithm.
-
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 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
-
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;
}