diff --git a/modules/video/src/dis_flow.cpp b/modules/video/src/dis_flow.cpp index c859555c22..5ebb3b8f45 100644 --- a/modules/video/src/dis_flow.cpp +++ b/modules/video/src/dis_flow.cpp @@ -818,10 +818,12 @@ void DISOpticalFlowImpl::PatchInverseSearch_ParBody::operator()(const Range &ran int i, j, dir; int start_is, end_is, start_js, end_js; int start_i, start_j; - float i_lower_limit = bsz - psz + 1.0f; - float i_upper_limit = bsz + dis->h - 1.0f; - float j_lower_limit = bsz - psz + 1.0f; - float j_upper_limit = bsz + dis->w - 1.0f; + // Clamp so the psz+1 (bilinear) read stays inside the padded I1_ext buffer even when + // psz > bsz; unchanged for psz <= bsz (the common case). See #20185. + float i_lower_limit = std::max(bsz - psz + 1.0f, 0.0f); + float i_upper_limit = std::min(bsz + dis->h - 1.0f, dis->h + 2.0f * bsz - 1.0f - psz); + float j_lower_limit = std::max(bsz - psz + 1.0f, 0.0f); + float j_upper_limit = std::min(bsz + dis->w - 1.0f, dis->w + 2.0f * bsz - 1.0f - psz); float dUx, dUy, i_I1, j_I1, w00, w01, w10, w11, dx, dy; #define INIT_BILINEAR_WEIGHTS(Ux, Uy) \ diff --git a/modules/video/test/test_OF_accuracy.cpp b/modules/video/test/test_OF_accuracy.cpp index cf51cd1dc4..063c221e1a 100644 --- a/modules/video/test/test_OF_accuracy.cpp +++ b/modules/video/test/test_OF_accuracy.cpp @@ -197,4 +197,24 @@ TEST(DenseOpticalFlow_DIS, ManualCoarsestScale) EXPECT_EQ(dis->getCoarsestScale(), -1); } -}} // namespace \ No newline at end of file +// See https://github.com/opencv/opencv/issues/20185 +TEST(DenseOpticalFlow_DIS, regression_20185_patch_larger_than_border) +{ + Mat prev(240, 320, CV_8UC1), next(240, 320, CV_8UC1); + theRNG().fill(prev, RNG::UNIFORM, 0, 256); + theRNG().fill(next, RNG::UNIFORM, 0, 256); + + Ptr dis = DISOpticalFlow::create(DISOpticalFlow::PRESET_MEDIUM); + dis->setPatchStride(10); + + Mat flow(prev.size(), CV_32FC2, Scalar(60.f, 60.f)); + ASSERT_NO_THROW(dis->calc(prev, next, flow)); + EXPECT_EQ(flow.size(), prev.size()); + + dis->setPatchSize(25); + flow.setTo(Scalar(60.f, 60.f)); + ASSERT_NO_THROW(dis->calc(prev, next, flow)); + EXPECT_EQ(flow.size(), prev.size()); +} + +}} // namespace