From 1a0e2d459d87f972850f6c70778b7486c1992ac2 Mon Sep 17 00:00:00 2001 From: tandede <1090179959@qq.com> Date: Thu, 20 Aug 2026 11:30:09 +0800 Subject: [PATCH] Fix reflected border interpolation for extreme coordinates --- modules/core/src/copy.cpp | 23 +++++------ modules/core/test/test_misc.cpp | 68 +++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 13 deletions(-) diff --git a/modules/core/src/copy.cpp b/modules/core/src/copy.cpp index 271858ad5b..d882c9359d 100644 --- a/modules/core/src/copy.cpp +++ b/modules/core/src/copy.cpp @@ -918,21 +918,18 @@ int cv::borderInterpolate( int p, int len, int borderType ) p = p < 0 ? 0 : len - 1; else if( borderType == BORDER_REFLECT || borderType == BORDER_REFLECT_101 ) { - int delta = borderType == BORDER_REFLECT_101; + const int delta = borderType == BORDER_REFLECT_101; if( len == 1 ) return 0; - do - { - if( p < 0 ) - p = -p - 1 + delta; - else - p = len - 1 - (p - len) - delta; - } -#ifdef CV_STATIC_ANALYSIS - while(p < 0 || p >= len); -#else - while( (unsigned)p >= (unsigned)len ); -#endif + + const int64 period = 2LL * (len - delta); + int64 p64 = p; + p64 %= period; + if( p64 < 0 ) + p64 += period; + if( p64 >= len ) + p64 = period - p64 - 1 + delta; + p = (int)p64; } else if( borderType == BORDER_WRAP ) { diff --git a/modules/core/test/test_misc.cpp b/modules/core/test/test_misc.cpp index 6e34e2b8d4..94b4d83781 100644 --- a/modules/core/test/test_misc.cpp +++ b/modules/core/test/test_misc.cpp @@ -37,6 +37,74 @@ TEST(Core_SaturateCast, NegativeNotClipped) ASSERT_EQ(0xffffffff, val); } +// See https://github.com/opencv/opencv/issues/29736 +static int borderReflectReference(int p, int len, int borderType) +{ + const int delta = borderType == BORDER_REFLECT_101; + if( len == 1 ) + return 0; + while( p < 0 || p >= len ) + { + if( p < 0 ) + p = -p - 1 + delta; + else + p = len - 1 - (p - len) - delta; + } + return p; +} + +TEST(Core_BorderInterpolate, ReflectCompatibility) +{ + const int borderTypes[] = { BORDER_REFLECT, BORDER_REFLECT_101 }; + const int lengths[] = { 1, 2, 3, 5, 17 }; + for( size_t i = 0; i < sizeof(borderTypes) / sizeof(borderTypes[0]); i++ ) + { + for( size_t j = 0; j < sizeof(lengths) / sizeof(lengths[0]); j++ ) + { + for( int p = -1000; p <= 1000; p++ ) + { + EXPECT_EQ(borderReflectReference(p, lengths[j], borderTypes[i]), + cv::borderInterpolate(p, lengths[j], borderTypes[i])) + << "p=" << p << ", len=" << lengths[j] + << ", borderType=" << borderTypes[i]; + } + } + } +} + +TEST(Core_BorderInterpolate, ReflectExtremeCoordinates) +{ + struct TestCase + { + int p; + int len; + int borderType; + int expected; + }; + const TestCase cases[] = { + { INT_MIN, 2, BORDER_REFLECT, 0 }, + { INT_MAX, 2, BORDER_REFLECT, 0 }, + { INT_MIN, 3, BORDER_REFLECT, 1 }, + { INT_MAX, 3, BORDER_REFLECT, 1 }, + { INT_MIN, INT_MAX, BORDER_REFLECT, INT_MAX - 1 }, + { INT_MAX, INT_MAX, BORDER_REFLECT, INT_MAX - 1 }, + { INT_MIN, 2, BORDER_REFLECT_101, 0 }, + { INT_MAX, 2, BORDER_REFLECT_101, 1 }, + { INT_MIN, 3, BORDER_REFLECT_101, 0 }, + { INT_MAX, 3, BORDER_REFLECT_101, 1 }, + { INT_MIN, INT_MAX, BORDER_REFLECT_101, INT_MAX - 3 }, + { INT_MAX, INT_MAX, BORDER_REFLECT_101, INT_MAX - 2 }, + }; + + for( size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++ ) + { + EXPECT_EQ(cases[i].expected, + cv::borderInterpolate(cases[i].p, cases[i].len, cases[i].borderType)) + << "p=" << cases[i].p << ", len=" << cases[i].len + << ", borderType=" << cases[i].borderType; + } +} + template static double maxAbsDiff(const T &t, const U &u) {