From 4366c8734fa7cf69c4a9bdcea91f41d1af345e9c Mon Sep 17 00:00:00 2001 From: Namgoo Lee Date: Fri, 11 Jan 2019 04:00:08 +0000 Subject: [PATCH] Fix Farneback Optical Flow Algorithm - Before this PR, following tests failed on some platform. CUDA_OptFlow/FarnebackOpticalFlow.Accuracy/19 CUDA_OptFlow/FarnebackOpticalFlow.Accuracy/23 - The algorithm now recognizes the OPTFLOW_USE_INITIAL_FLOW flag. Previously, when the flag was set, it did not use the flow data passed as input, instead used some garbage data in memory. - More strict test limit. --- modules/cudaoptflow/src/farneback.cpp | 29 +++++++++++++++++------ modules/cudaoptflow/test/test_optflow.cpp | 10 +++++++- modules/video/src/optflowgf.cpp | 24 ++++++++++++++----- 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/modules/cudaoptflow/src/farneback.cpp b/modules/cudaoptflow/src/farneback.cpp index 43032b4f8f..69ea437ec4 100644 --- a/modules/cudaoptflow/src/farneback.cpp +++ b/modules/cudaoptflow/src/farneback.cpp @@ -165,10 +165,29 @@ namespace { const GpuMat frame0 = _frame0.getGpuMat(); const GpuMat frame1 = _frame1.getGpuMat(); + GpuMat flow = _flow.getGpuMat(); - BufferPool pool(stream); - GpuMat flowx = pool.getBuffer(frame0.size(), CV_32FC1); - GpuMat flowy = pool.getBuffer(frame0.size(), CV_32FC1); + CV_Assert(frame0.channels() == 1 && frame1.channels() == 1); + CV_Assert(frame0.size() == frame1.size()); + + GpuMat flowx, flowy; + + // If flag is set, check for integrity; if not set, allocate memory space + if (flags_ & OPTFLOW_USE_INITIAL_FLOW) + { + CV_Assert(flow.size() == frame0.size() && flow.channels() == 2 && + flow.depth() == CV_32F); + + std::vector _flows(2); + cuda::split(flow, _flows, stream); + flowx = _flows[0]; + flowy = _flows[1]; + } + else + { + flowx.create(frame0.size(), CV_32FC1); + flowy.create(frame0.size(), CV_32FC1); + } calcImpl(frame0, frame1, flowx, flowy, stream); @@ -291,8 +310,6 @@ namespace void FarnebackOpticalFlowImpl::calcImpl(const GpuMat &frame0, const GpuMat &frame1, GpuMat &flowx, GpuMat &flowy, Stream &stream) { - CV_Assert(frame0.channels() == 1 && frame1.channels() == 1); - CV_Assert(frame0.size() == frame1.size()); CV_Assert(polyN_ == 5 || polyN_ == 7); CV_Assert(!fastPyramids_ || std::abs(pyrScale_ - 0.5) < 1e-6); @@ -303,8 +320,6 @@ namespace Size size = frame0.size(); GpuMat prevFlowX, prevFlowY, curFlowX, curFlowY; - flowx.create(size, CV_32F); - flowy.create(size, CV_32F); GpuMat flowx0 = flowx; GpuMat flowy0 = flowy; diff --git a/modules/cudaoptflow/test/test_optflow.cpp b/modules/cudaoptflow/test/test_optflow.cpp index c856474363..37ffe9e5c4 100644 --- a/modules/cudaoptflow/test/test_optflow.cpp +++ b/modules/cudaoptflow/test/test_optflow.cpp @@ -337,7 +337,15 @@ CUDA_TEST_P(FarnebackOpticalFlow, Accuracy) frame0, frame1, flow, farn->getPyrScale(), farn->getNumLevels(), farn->getWinSize(), farn->getNumIters(), farn->getPolyN(), farn->getPolySigma(), farn->getFlags()); - EXPECT_MAT_SIMILAR(flow, d_flow, 0.1); + // Relax test limit when the flag is set + if (farn->getFlags() & cv::OPTFLOW_FARNEBACK_GAUSSIAN) + { + EXPECT_MAT_SIMILAR(flow, d_flow, 2e-2); + } + else + { + EXPECT_MAT_SIMILAR(flow, d_flow, 1e-4); + } } INSTANTIATE_TEST_CASE_P(CUDA_OptFlow, FarnebackOpticalFlow, testing::Combine( diff --git a/modules/video/src/optflowgf.cpp b/modules/video/src/optflowgf.cpp index 2e6251b210..e06dbbf379 100644 --- a/modules/video/src/optflowgf.cpp +++ b/modules/video/src/optflowgf.cpp @@ -646,8 +646,6 @@ private: Size size = frame0.size(); UMat prevFlowX, prevFlowY, curFlowX, curFlowY; - flowx.create(size, CV_32F); - flowy.create(size, CV_32F); UMat flowx0 = flowx; UMat flowy0 = flowy; @@ -1075,12 +1073,19 @@ private: return false; std::vector flowar; - if (!_flow0.empty()) + + // If flag is set, check for integrity; if not set, allocate memory space + if (flags_ & OPTFLOW_USE_INITIAL_FLOW) + { + if (_flow0.empty() || _flow0.size() != _prev0.size() || _flow0.channels() != 2 || + _flow0.depth() != CV_32F) + return false; split(_flow0, flowar); + } else { - flowar.push_back(UMat()); - flowar.push_back(UMat()); + flowar.push_back(UMat(_prev0.size(), CV_32FC1)); + flowar.push_back(UMat(_prev0.size(), CV_32FC1)); } if(!this->operator()(_prev0.getUMat(), _next0.getUMat(), flowar[0], flowar[1])){ return false; @@ -1112,7 +1117,14 @@ void FarnebackOpticalFlowImpl::calc(InputArray _prev0, InputArray _next0, CV_Assert( prev0.size() == next0.size() && prev0.channels() == next0.channels() && prev0.channels() == 1 && pyrScale_ < 1 ); - _flow0.create( prev0.size(), CV_32FC2 ); + + // If flag is set, check for integrity; if not set, allocate memory space + if( flags_ & OPTFLOW_USE_INITIAL_FLOW ) + CV_Assert( _flow0.size() == prev0.size() && _flow0.channels() == 2 && + _flow0.depth() == CV_32F ); + else + _flow0.create( prev0.size(), CV_32FC2 ); + Mat flow0 = _flow0.getMat(); for( k = 0, scale = 1; k < levels; k++ )