diff --git a/modules/video/src/dis_flow.cpp b/modules/video/src/dis_flow.cpp index a453d8b2b516..806d6f1ddaf3 100644 --- a/modules/video/src/dis_flow.cpp +++ b/modules/video/src/dis_flow.cpp @@ -140,6 +140,8 @@ class DISOpticalFlowImpl CV_FINAL : public DISOpticalFlow void prepareBuffers(Mat &I0, Mat &I1, Mat &flow, bool use_flow); void precomputeStructureTensor(Mat &dst_I0xx, Mat &dst_I0yy, Mat &dst_I0xy, Mat &dst_I0x, Mat &dst_I0y, Mat &I0x, Mat &I0y); + int autoSelectCoarsestScale(int img_width); + void autoSelectPatchSizeAndScales(int img_width); struct PatchInverseSearch_ParBody : public ParallelLoopBody { @@ -435,6 +437,44 @@ void DISOpticalFlowImpl::precomputeStructureTensor(Mat &dst_I0xx, Mat &dst_I0yy, } } +int DISOpticalFlowImpl::autoSelectCoarsestScale(int img_width) +{ + const int fratio = 5; + return std::max(0, (int)std::floor(log2((2.0f*(float)img_width) / ((float)fratio * (float)patch_size)))); +} + +void DISOpticalFlowImpl::autoSelectPatchSizeAndScales(int img_width) +{ + switch (finest_scale) + { + case 1: + patch_size = 8; + coarsest_scale = autoSelectCoarsestScale(img_width); + finest_scale = std::max(coarsest_scale-2, 0); + break; + + case 3: + patch_size = 12; + coarsest_scale = autoSelectCoarsestScale(img_width); + finest_scale = std::max(coarsest_scale-4, 0); + break; + + case 4: + patch_size = 12; + coarsest_scale = autoSelectCoarsestScale(img_width); + finest_scale = std::max(coarsest_scale-5, 0); + break; + + // default case, fall-through. + case 2: + default: + patch_size = 8; + coarsest_scale = autoSelectCoarsestScale(img_width); + finest_scale = std::max(coarsest_scale-2, 0); + break; + } +} + DISOpticalFlowImpl::PatchInverseSearch_ParBody::PatchInverseSearch_ParBody(DISOpticalFlowImpl &_dis, int _nstripes, int _hs, Mat &dst_Sx, Mat &dst_Sy, Mat &src_Ux, Mat &src_Uy, Mat &_I0, Mat &_I1, @@ -1318,9 +1358,20 @@ bool DISOpticalFlowImpl::ocl_calc(InputArray I0, InputArray I1, InputOutputArray else flow.create(I1Mat.size(), CV_32FC2); UMat &u_flowMat = flow.getUMatRef(); - coarsest_scale = min((int)(log(max(I0Mat.cols, I0Mat.rows) / (4.0 * patch_size)) / log(2.0) + 0.5), /* Original code serach for maximal movement of width/4 */ + coarsest_scale = min((int)(log(max(I0Mat.cols, I0Mat.rows) / (4.0 * patch_size)) / log(2.0) + 0.5), /* Original code search for maximal movement of width/4 */ (int)(log(min(I0Mat.cols, I0Mat.rows) / patch_size) / log(2.0))); /* Deepest pyramid level greater or equal than patch*/ + if (coarsest_scale<0) + CV_Error(cv::Error::StsBadSize, "The input image must have either width or height >= 12"); + + if (coarsest_scale= 12"); + + if (coarsest_scale of = cv::DISOpticalFlow::create(); + const int mat_size = 10; + + cv::Mat x(mat_size, mat_size, CV_8UC1, 42); + cv::Mat y(mat_size, mat_size, CV_8UC1, 42); + cv::Mat flow; + + ASSERT_THROW(of->calc(x, y, flow), cv::Exception); +} + +// make sure that autoSelectPatchSizeAndScales() works properly. +TEST(DenseOpticalFlow_DIS, InvalidImgSize_CoarsestLevelLessThanFinestLevel) +{ + cv::Ptr of = cv::DISOpticalFlow::create(); + const int mat_size = 80; + + cv::Mat x(mat_size, mat_size, CV_8UC1, 42); + cv::Mat y(mat_size, mat_size, CV_8UC1, 42); + cv::Mat flow; + + of->calc(x, y, flow); + + ASSERT_EQ(flow.rows, mat_size); + ASSERT_EQ(flow.cols, mat_size); +} + TEST(DenseOpticalFlow_VariationalRefinement, ReferenceAccuracy) { Mat frame1, frame2, GT;