imgproc: don’t use ippiCopySubpixIntersect for windows crossing the image border - #30363

This commit is contained in:
Pulk17 authored and Alexander Smorkalov committed 2026-10-22 17:11:33 +03:00
1 parent 83f8d6e6c6
commit a90814606d
2 files changed
+58

No files matched your search

+18
View File
@@ -21,6 +21,24 @@ int ipp_hal_getRectSubPix(int src_type, const uchar* src_data, size_t src_step,
int ddepth = CV_MAT_DEPTH(patch_type);
// ippiCopySubpixIntersect replicates the border incorrectly in some cases, see
// https://github.com/opencv/opencv/issues/30301. The window position is computed the same way as IPP does,
// including (int)(x + w) - w, which is not equal to cvFloor() for some inputs.
float fx = (float)center_x - 0.5f * (patch_width - 1);
float fy = (float)center_y - 0.5f * (patch_height - 1);
int sx = (int)(fx + patch_width) - patch_width;
int sy = (int)(fy + patch_height) - patch_height;
// the window crosses the top edge and reaches the last column: the top rows get src(0, cols-2)
// instead of src(0, cols-1), and for 1-column images IPP reads outside of the image
if( sy < 0 && sx >= src_width - patch_width )
return CV_HAL_ERROR_NOT_IMPLEMENTED;
// 8u->8u, the window lies totally to the left of the image: the fixed-point weights overflow
if( src_type == CV_8UC1 && ddepth == CV_8U && fx + patch_width < 0 )
return CV_HAL_ERROR_NOT_IMPLEMENTED;
typedef IppStatus (CV_STDCALL *ippiGetRectSubPixFunc)( const void* src, int src_step,
IppiSize src_size, void* dst,
int dst_step, IppiSize win_size,
+40
View File
@@ -1386,5 +1386,45 @@ TEST(Imgproc_ConvertMaps, regression_22763)
EXPECT_EQ(CV_16UC1, dst2.type());
}
// https://github.com/opencv/opencv/issues/30301
typedef testing::TestWithParam<testing::tuple<int, int> > Imgproc_GetRectSubPix_Border;
TEST_P(Imgproc_GetRectSubPix_Border, regression_30301)
{
const int depth = get<0>(GetParam()), ddepth = get<1>(GetParam());
// The images are ROIs of a buffer filled with 250, so reads outside of them show up in the result
const Rect rampRoi(8, 8, 4, 4), columnRoi(2, 2, 1, 4);
Mat buf8u(20, 20, CV_8UC1, Scalar(250)), buf;
for (int r = 0; r < 4; r++)
{
for (int c = 0; c < 4; c++)
buf8u(rampRoi).at<uchar>(r, c) = (uchar)(r * 40 + c * 8);
buf8u(columnRoi).at<uchar>(r, 0) = (uchar)(10 + r * 10);
}
buf8u.convertTo(buf, depth);
const struct { Rect roi; Size size; Point2f center; std::vector<float> expected; } cases[] = {
// the window crosses the top and the right edges
{ rampRoi, Size(3, 3), Point2f(3.f, 0.f), { 16, 24, 24, 16, 24, 24, 56, 64, 64 } },
{ columnRoi, Size(3, 3), Point2f(0.f, 0.f), { 10, 10, 10, 10, 10, 10, 20, 20, 20 } },
// the window is to the left of the image
{ rampRoi, Size(1, 1), Point2f(-2.75f, 3.f), { 120 } },
};
for (const auto& tc : cases)
{
SCOPED_TRACE(cv::format("image=%dx%d center=(%g, %g)", tc.roi.width, tc.roi.height, tc.center.x, tc.center.y));
Mat patch, patch32f;
getRectSubPix(buf(tc.roi), tc.size, tc.center, patch, ddepth);
patch.convertTo(patch32f, CV_32F);
Mat expected = Mat(tc.expected).reshape(1, tc.size.height);
EXPECT_LE(cvtest::norm(patch32f, expected, NORM_INF), 1e-3) << patch32f;
}
}
INSTANTIATE_TEST_CASE_P(/**/, Imgproc_GetRectSubPix_Border, testing::Values(
testing::make_tuple(CV_8U, CV_8U), testing::make_tuple(CV_8U, CV_32F), testing::make_tuple(CV_32F, CV_32F)));
}} // namespace
/* End of file. */