Commit be4312ec authored by alcinos's avatar alcinos

Wrap DenseOptFlow class around Farneback optical flow computation

parent 347ffbb0
...@@ -93,7 +93,7 @@ namespace cv { namespace cuda { namespace device { namespace optflow_farneback ...@@ -93,7 +93,7 @@ namespace cv { namespace cuda { namespace device { namespace optflow_farneback
namespace namespace
{ {
class FarnebackOpticalFlowImpl : public FarnebackOpticalFlow class FarnebackOpticalFlowImpl : public cv::cuda::FarnebackOpticalFlow
{ {
public: public:
FarnebackOpticalFlowImpl(int numLevels, double pyrScale, bool fastPyramids, int winSize, FarnebackOpticalFlowImpl(int numLevels, double pyrScale, bool fastPyramids, int winSize,
...@@ -459,7 +459,7 @@ namespace ...@@ -459,7 +459,7 @@ namespace
} }
} }
Ptr<FarnebackOpticalFlow> cv::cuda::FarnebackOpticalFlow::create(int numLevels, double pyrScale, bool fastPyramids, int winSize, Ptr<cv::cuda::FarnebackOpticalFlow> cv::cuda::FarnebackOpticalFlow::create(int numLevels, double pyrScale, bool fastPyramids, int winSize,
int numIters, int polyN, double polySigma, int flags) int numIters, int polyN, double polySigma, int flags)
{ {
return makePtr<FarnebackOpticalFlowImpl>(numLevels, pyrScale, fastPyramids, winSize, return makePtr<FarnebackOpticalFlowImpl>(numLevels, pyrScale, fastPyramids, winSize,
......
...@@ -508,6 +508,46 @@ public: ...@@ -508,6 +508,46 @@ public:
*/ */
CV_EXPORTS_W Ptr<DualTVL1OpticalFlow> createOptFlow_DualTVL1(); CV_EXPORTS_W Ptr<DualTVL1OpticalFlow> createOptFlow_DualTVL1();
/** @brief Class computing a dense optical flow using the Gunnar Farneback’s algorithm.
*/
class CV_EXPORTS_W FarnebackOpticalFlow : public DenseOpticalFlow
{
public:
virtual int getNumLevels() const = 0;
virtual void setNumLevels(int numLevels) = 0;
virtual double getPyrScale() const = 0;
virtual void setPyrScale(double pyrScale) = 0;
virtual bool getFastPyramids() const = 0;
virtual void setFastPyramids(bool fastPyramids) = 0;
virtual int getWinSize() const = 0;
virtual void setWinSize(int winSize) = 0;
virtual int getNumIters() const = 0;
virtual void setNumIters(int numIters) = 0;
virtual int getPolyN() const = 0;
virtual void setPolyN(int polyN) = 0;
virtual double getPolySigma() const = 0;
virtual void setPolySigma(double polySigma) = 0;
virtual int getFlags() const = 0;
virtual void setFlags(int flags) = 0;
static Ptr<FarnebackOpticalFlow> create(
int numLevels = 5,
double pyrScale = 0.5,
bool fastPyramids = false,
int winSize = 13,
int numIters = 10,
int polyN = 5,
double polySigma = 1.1,
int flags = 0);
};
//! @} video_track //! @} video_track
} // cv } // cv
......
...@@ -583,39 +583,63 @@ FarnebackUpdateFlow_GaussianBlur( const Mat& _R0, const Mat& _R1, ...@@ -583,39 +583,63 @@ FarnebackUpdateFlow_GaussianBlur( const Mat& _R0, const Mat& _R1,
} }
#ifdef HAVE_OPENCL
namespace cv namespace cv
{ {
class FarnebackOpticalFlow namespace
{
class FarnebackOpticalFlowImpl : public FarnebackOpticalFlow
{ {
public: public:
FarnebackOpticalFlow() FarnebackOpticalFlowImpl(int numLevels=5, double pyrScale=0.5, bool fastPyramids=false, int winSize=13,
int numIters=10, int polyN=5, double polySigma=1.1, int flags=0) :
numLevels_(numLevels), pyrScale_(pyrScale), fastPyramids_(fastPyramids), winSize_(winSize),
numIters_(numIters), polyN_(polyN), polySigma_(polySigma), flags_(flags)
{ {
numLevels = 5;
pyrScale = 0.5;
fastPyramids = false;
winSize = 13;
numIters = 10;
polyN = 5;
polySigma = 1.1;
flags = 0;
} }
int numLevels; virtual int getNumLevels() const { return numLevels_; }
double pyrScale; virtual void setNumLevels(int numLevels) { numLevels_ = numLevels; }
bool fastPyramids;
int winSize; virtual double getPyrScale() const { return pyrScale_; }
int numIters; virtual void setPyrScale(double pyrScale) { pyrScale_ = pyrScale; }
int polyN;
double polySigma; virtual bool getFastPyramids() const { return fastPyramids_; }
int flags; virtual void setFastPyramids(bool fastPyramids) { fastPyramids_ = fastPyramids; }
virtual int getWinSize() const { return winSize_; }
virtual void setWinSize(int winSize) { winSize_ = winSize; }
virtual int getNumIters() const { return numIters_; }
virtual void setNumIters(int numIters) { numIters_ = numIters; }
virtual int getPolyN() const { return polyN_; }
virtual void setPolyN(int polyN) { polyN_ = polyN; }
virtual double getPolySigma() const { return polySigma_; }
virtual void setPolySigma(double polySigma) { polySigma_ = polySigma; }
virtual int getFlags() const { return flags_; }
virtual void setFlags(int flags) { flags_ = flags; }
virtual void calc(InputArray I0, InputArray I1, InputOutputArray flow);
private:
int numLevels_;
double pyrScale_;
bool fastPyramids_;
int winSize_;
int numIters_;
int polyN_;
double polySigma_;
int flags_;
#ifdef HAVE_OPENCL
bool operator ()(const UMat &frame0, const UMat &frame1, UMat &flowx, UMat &flowy) bool operator ()(const UMat &frame0, const UMat &frame1, UMat &flowx, UMat &flowy)
{ {
CV_Assert(frame0.channels() == 1 && frame1.channels() == 1); CV_Assert(frame0.channels() == 1 && frame1.channels() == 1);
CV_Assert(frame0.size() == frame1.size()); CV_Assert(frame0.size() == frame1.size());
CV_Assert(polyN == 5 || polyN == 7); CV_Assert(polyN_ == 5 || polyN_ == 7);
CV_Assert(!fastPyramids || std::abs(pyrScale - 0.5) < 1e-6); CV_Assert(!fastPyramids_ || std::abs(pyrScale_ - 0.5) < 1e-6);
const int min_size = 32; const int min_size = 32;
...@@ -630,9 +654,9 @@ public: ...@@ -630,9 +654,9 @@ public:
// Crop unnecessary levels // Crop unnecessary levels
double scale = 1; double scale = 1;
int numLevelsCropped = 0; int numLevelsCropped = 0;
for (; numLevelsCropped < numLevels; numLevelsCropped++) for (; numLevelsCropped < numLevels_; numLevelsCropped++)
{ {
scale *= pyrScale; scale *= pyrScale_;
if (size.width*scale < min_size || size.height*scale < min_size) if (size.width*scale < min_size || size.height*scale < min_size)
break; break;
} }
...@@ -640,7 +664,7 @@ public: ...@@ -640,7 +664,7 @@ public:
frame0.convertTo(frames_[0], CV_32F); frame0.convertTo(frames_[0], CV_32F);
frame1.convertTo(frames_[1], CV_32F); frame1.convertTo(frames_[1], CV_32F);
if (fastPyramids) if (fastPyramids_)
{ {
// Build Gaussian pyramids using pyrDown() // Build Gaussian pyramids using pyrDown()
pyramid0_.resize(numLevelsCropped + 1); pyramid0_.resize(numLevelsCropped + 1);
...@@ -654,13 +678,13 @@ public: ...@@ -654,13 +678,13 @@ public:
} }
} }
setPolynomialExpansionConsts(polyN, polySigma); setPolynomialExpansionConsts(polyN_, polySigma_);
for (int k = numLevelsCropped; k >= 0; k--) for (int k = numLevelsCropped; k >= 0; k--)
{ {
scale = 1; scale = 1;
for (int i = 0; i < k; i++) for (int i = 0; i < k; i++)
scale *= pyrScale; scale *= pyrScale_;
double sigma = (1./scale - 1) * 0.5; double sigma = (1./scale - 1) * 0.5;
int smoothSize = cvRound(sigma*5) | 1; int smoothSize = cvRound(sigma*5) | 1;
...@@ -669,7 +693,7 @@ public: ...@@ -669,7 +693,7 @@ public:
int width = cvRound(size.width*scale); int width = cvRound(size.width*scale);
int height = cvRound(size.height*scale); int height = cvRound(size.height*scale);
if (fastPyramids) if (fastPyramids_)
{ {
width = pyramid0_[k].cols; width = pyramid0_[k].cols;
height = pyramid0_[k].rows; height = pyramid0_[k].rows;
...@@ -688,7 +712,7 @@ public: ...@@ -688,7 +712,7 @@ public:
if (prevFlowX.empty()) if (prevFlowX.empty())
{ {
if (flags & cv::OPTFLOW_USE_INITIAL_FLOW) if (flags_ & cv::OPTFLOW_USE_INITIAL_FLOW)
{ {
resize(flowx0, curFlowX, Size(width, height), 0, 0, INTER_LINEAR); resize(flowx0, curFlowX, Size(width, height), 0, 0, INTER_LINEAR);
resize(flowy0, curFlowY, Size(width, height), 0, 0, INTER_LINEAR); resize(flowy0, curFlowY, Size(width, height), 0, 0, INTER_LINEAR);
...@@ -705,8 +729,8 @@ public: ...@@ -705,8 +729,8 @@ public:
{ {
resize(prevFlowX, curFlowX, Size(width, height), 0, 0, INTER_LINEAR); resize(prevFlowX, curFlowX, Size(width, height), 0, 0, INTER_LINEAR);
resize(prevFlowY, curFlowY, Size(width, height), 0, 0, INTER_LINEAR); resize(prevFlowY, curFlowY, Size(width, height), 0, 0, INTER_LINEAR);
multiply(1./pyrScale, curFlowX, curFlowX); multiply(1./pyrScale_, curFlowX, curFlowX);
multiply(1./pyrScale, curFlowY, curFlowY); multiply(1./pyrScale_, curFlowY, curFlowY);
} }
UMat M = allocMatFromBuf(5*height, width, CV_32F, M_); UMat M = allocMatFromBuf(5*height, width, CV_32F, M_);
...@@ -717,7 +741,7 @@ public: ...@@ -717,7 +741,7 @@ public:
allocMatFromBuf(5*height, width, CV_32F, R_[1]) allocMatFromBuf(5*height, width, CV_32F, R_[1])
}; };
if (fastPyramids) if (fastPyramids_)
{ {
if (!polynomialExpansionOcl(pyramid0_[k], R[0])) if (!polynomialExpansionOcl(pyramid0_[k], R[0]))
return false; return false;
...@@ -752,18 +776,18 @@ public: ...@@ -752,18 +776,18 @@ public:
if (!updateMatricesOcl(curFlowX, curFlowY, R[0], R[1], M)) if (!updateMatricesOcl(curFlowX, curFlowY, R[0], R[1], M))
return false; return false;
if (flags & OPTFLOW_FARNEBACK_GAUSSIAN) if (flags_ & OPTFLOW_FARNEBACK_GAUSSIAN)
setGaussianBlurKernel(winSize, winSize/2*0.3f); setGaussianBlurKernel(winSize_, winSize_/2*0.3f);
for (int i = 0; i < numIters; i++) for (int i = 0; i < numIters_; i++)
{ {
if (flags & OPTFLOW_FARNEBACK_GAUSSIAN) if (flags_ & OPTFLOW_FARNEBACK_GAUSSIAN)
{ {
if (!updateFlow_gaussianBlur(R[0], R[1], curFlowX, curFlowY, M, bufM, winSize, i < numIters-1)) if (!updateFlow_gaussianBlur(R[0], R[1], curFlowX, curFlowY, M, bufM, winSize_, i < numIters_-1))
return false; return false;
} }
else else
{ {
if (!updateFlow_boxFilter(R[0], R[1], curFlowX, curFlowY, M, bufM, winSize, i < numIters-1)) if (!updateFlow_boxFilter(R[0], R[1], curFlowX, curFlowY, M, bufM, winSize_, i < numIters_-1))
return false; return false;
} }
} }
...@@ -776,7 +800,9 @@ public: ...@@ -776,7 +800,9 @@ public:
flowy = curFlowY; flowy = curFlowY;
return true; return true;
} }
virtual void collectGarbage(){
releaseMemory();
}
void releaseMemory() void releaseMemory()
{ {
frames_[0].release(); frames_[0].release();
...@@ -898,15 +924,15 @@ private: ...@@ -898,15 +924,15 @@ private:
#else #else
size_t localsize[2] = { 256, 1}; size_t localsize[2] = { 256, 1};
#endif #endif
size_t globalsize[2] = { DIVUP((size_t)src.cols, localsize[0] - 2*polyN) * localsize[0], (size_t)src.rows}; size_t globalsize[2] = { DIVUP((size_t)src.cols, localsize[0] - 2*polyN_) * localsize[0], (size_t)src.rows};
#if 0 #if 0
const cv::ocl::Device &device = cv::ocl::Device::getDefault(); const cv::ocl::Device &device = cv::ocl::Device::getDefault();
bool useDouble = (0 != device.doubleFPConfig()); bool useDouble = (0 != device.doubleFPConfig());
cv::String build_options = cv::format("-D polyN=%d -D USE_DOUBLE=%d", polyN, useDouble ? 1 : 0); cv::String build_options = cv::format("-D polyN=%d -D USE_DOUBLE=%d", polyN_, useDouble ? 1 : 0);
#else #else
cv::String build_options = cv::format("-D polyN=%d", polyN); cv::String build_options = cv::format("-D polyN=%d", polyN_);
#endif #endif
ocl::Kernel kernel; ocl::Kernel kernel;
if (!kernel.create("polynomialExpansion", cv::ocl::video::optical_flow_farneback_oclsrc, build_options)) if (!kernel.create("polynomialExpansion", cv::ocl::video::optical_flow_farneback_oclsrc, build_options))
...@@ -1036,60 +1062,43 @@ private: ...@@ -1036,60 +1062,43 @@ private:
return false; return false;
return true; return true;
} }
}; bool calc_ocl( InputArray _prev0, InputArray _next0,
InputOutputArray _flow0)
static bool ocl_calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0,
InputOutputArray _flow0, double pyr_scale, int levels, int winsize,
int iterations, int poly_n, double poly_sigma, int flags )
{
if ((5 != poly_n) && (7 != poly_n))
return false;
if (_next0.size() != _prev0.size())
return false;
int typePrev = _prev0.type();
int typeNext = _next0.type();
if ((1 != CV_MAT_CN(typePrev)) || (1 != CV_MAT_CN(typeNext)))
return false;
FarnebackOpticalFlow opticalFlow;
opticalFlow.numLevels = levels;
opticalFlow.pyrScale = pyr_scale;
opticalFlow.fastPyramids= false;
opticalFlow.winSize = winsize;
opticalFlow.numIters = iterations;
opticalFlow.polyN = poly_n;
opticalFlow.polySigma = poly_sigma;
opticalFlow.flags = flags;
std::vector<UMat> flowar;
if (!_flow0.empty())
split(_flow0, flowar);
else
{ {
flowar.push_back(UMat()); if ((5 != polyN_) && (7 != polyN_))
flowar.push_back(UMat()); return false;
} if (_next0.size() != _prev0.size())
if (!opticalFlow(_prev0.getUMat(), _next0.getUMat(), flowar[0], flowar[1])) return false;
return false; int typePrev = _prev0.type();
merge(flowar, _flow0); int typeNext = _next0.type();
return true; if ((1 != CV_MAT_CN(typePrev)) || (1 != CV_MAT_CN(typeNext)))
} return false;
}
#endif // HAVE_OPENCL
void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0, std::vector<UMat> flowar;
InputOutputArray _flow0, double pyr_scale, int levels, int winsize, if (!_flow0.empty())
int iterations, int poly_n, double poly_sigma, int flags ) split(_flow0, flowar);
{ else
#ifdef HAVE_OPENCL {
bool use_opencl = ocl::useOpenCL() && _flow0.isUMat(); flowar.push_back(UMat());
if( use_opencl && ocl_calcOpticalFlowFarneback(_prev0, _next0, _flow0, pyr_scale, levels, winsize, iterations, poly_n, poly_sigma, flags)) flowar.push_back(UMat());
{ }
CV_IMPL_ADD(CV_IMPL_OCL); if(!this->operator()(_prev0.getUMat(), _next0.getUMat(), flowar[0], flowar[1])){
return; return false;
}
merge(flowar, _flow0);
return true;
} }
#else // HAVE_OPENCL
virtual void collectGarbage(){}
#endif #endif
};
void FarnebackOpticalFlowImpl::calc(InputArray _prev0, InputArray _next0,
InputOutputArray _flow0)
{
CV_OCL_RUN(_flow0.isUMat() &&
ocl::Image2D::isFormatSupported(CV_32F, 1, false),
calc_ocl(_prev0,_next0,_flow0))
Mat prev0 = _prev0.getMat(), next0 = _next0.getMat(); Mat prev0 = _prev0.getMat(), next0 = _next0.getMat();
const int min_size = 32; const int min_size = 32;
const Mat* img[2] = { &prev0, &next0 }; const Mat* img[2] = { &prev0, &next0 };
...@@ -1097,15 +1106,16 @@ void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0, ...@@ -1097,15 +1106,16 @@ void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0,
int i, k; int i, k;
double scale; double scale;
Mat prevFlow, flow, fimg; Mat prevFlow, flow, fimg;
int levels = numLevels_;
CV_Assert( prev0.size() == next0.size() && prev0.channels() == next0.channels() && CV_Assert( prev0.size() == next0.size() && prev0.channels() == next0.channels() &&
prev0.channels() == 1 && pyr_scale < 1 ); prev0.channels() == 1 && pyrScale_ < 1 );
_flow0.create( prev0.size(), CV_32FC2 ); _flow0.create( prev0.size(), CV_32FC2 );
Mat flow0 = _flow0.getMat(); Mat flow0 = _flow0.getMat();
for( k = 0, scale = 1; k < levels; k++ ) for( k = 0, scale = 1; k < levels; k++ )
{ {
scale *= pyr_scale; scale *= pyrScale_;
if( prev0.cols*scale < min_size || prev0.rows*scale < min_size ) if( prev0.cols*scale < min_size || prev0.rows*scale < min_size )
break; break;
} }
...@@ -1115,7 +1125,7 @@ void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0, ...@@ -1115,7 +1125,7 @@ void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0,
for( k = levels; k >= 0; k-- ) for( k = levels; k >= 0; k-- )
{ {
for( i = 0, scale = 1; i < k; i++ ) for( i = 0, scale = 1; i < k; i++ )
scale *= pyr_scale; scale *= pyrScale_;
double sigma = (1./scale-1)*0.5; double sigma = (1./scale-1)*0.5;
int smooth_sz = cvRound(sigma*5)|1; int smooth_sz = cvRound(sigma*5)|1;
...@@ -1131,7 +1141,7 @@ void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0, ...@@ -1131,7 +1141,7 @@ void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0,
if( prevFlow.empty() ) if( prevFlow.empty() )
{ {
if( flags & OPTFLOW_USE_INITIAL_FLOW ) if( flags_ & OPTFLOW_USE_INITIAL_FLOW )
{ {
resize( flow0, flow, Size(width, height), 0, 0, INTER_AREA ); resize( flow0, flow, Size(width, height), 0, 0, INTER_AREA );
flow *= scale; flow *= scale;
...@@ -1142,7 +1152,7 @@ void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0, ...@@ -1142,7 +1152,7 @@ void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0,
else else
{ {
resize( prevFlow, flow, Size(width, height), 0, 0, INTER_LINEAR ); resize( prevFlow, flow, Size(width, height), 0, 0, INTER_LINEAR );
flow *= 1./pyr_scale; flow *= 1./pyrScale_;
} }
Mat R[2], I, M; Mat R[2], I, M;
...@@ -1151,19 +1161,38 @@ void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0, ...@@ -1151,19 +1161,38 @@ void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0,
img[i]->convertTo(fimg, CV_32F); img[i]->convertTo(fimg, CV_32F);
GaussianBlur(fimg, fimg, Size(smooth_sz, smooth_sz), sigma, sigma); GaussianBlur(fimg, fimg, Size(smooth_sz, smooth_sz), sigma, sigma);
resize( fimg, I, Size(width, height), INTER_LINEAR ); resize( fimg, I, Size(width, height), INTER_LINEAR );
FarnebackPolyExp( I, R[i], poly_n, poly_sigma ); FarnebackPolyExp( I, R[i], polyN_, polySigma_ );
} }
FarnebackUpdateMatrices( R[0], R[1], flow, M, 0, flow.rows ); FarnebackUpdateMatrices( R[0], R[1], flow, M, 0, flow.rows );
for( i = 0; i < iterations; i++ ) for( i = 0; i < numIters_; i++ )
{ {
if( flags & OPTFLOW_FARNEBACK_GAUSSIAN ) if( flags_ & OPTFLOW_FARNEBACK_GAUSSIAN )
FarnebackUpdateFlow_GaussianBlur( R[0], R[1], flow, M, winsize, i < iterations - 1 ); FarnebackUpdateFlow_GaussianBlur( R[0], R[1], flow, M, winSize_, i < numIters_ - 1 );
else else
FarnebackUpdateFlow_Blur( R[0], R[1], flow, M, winsize, i < iterations - 1 ); FarnebackUpdateFlow_Blur( R[0], R[1], flow, M, winSize_, i < numIters_ - 1 );
} }
prevFlow = flow; prevFlow = flow;
} }
} }
} // namespace
} // namespace cv
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 )
{
Ptr<cv::FarnebackOpticalFlow> optflow;
optflow = makePtr<FarnebackOpticalFlowImpl>(levels,pyr_scale,false,winsize,iterations,poly_n,poly_sigma,flags);
optflow->calc(_prev0,_next0,_flow0);
}
cv::Ptr<cv::FarnebackOpticalFlow> cv::FarnebackOpticalFlow::create(int numLevels, double pyrScale, bool fastPyramids, int winSize,
int numIters, int polyN, double polySigma, int flags)
{
return makePtr<FarnebackOpticalFlowImpl>(numLevels, pyrScale, fastPyramids, winSize,
numIters, polyN, polySigma, flags);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment