From 3621c83f2f6b45db87cd657c550cd6b01ecef63c Mon Sep 17 00:00:00 2001 From: Akansha-977 Date: Mon, 17 Aug 2026 18:47:55 +0530 Subject: [PATCH] Merge pull request #29512 from Akansha-977:rectsubpix_IPP_4.x Extracted IPP to HAL for getRectSubPix function in 4.x - #29512 ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake --- hal/ipp/CMakeLists.txt | 1 + hal/ipp/include/ipp_hal_imgproc.hpp | 6 + hal/ipp/src/samplers_ipp.cpp | 49 +++++++ modules/imgproc/perf/perf_getrectsubpix.cpp | 134 ++++++++++++++++++++ modules/imgproc/src/hal_replacement.hpp | 22 ++++ modules/imgproc/src/samplers.cpp | 34 +---- 6 files changed, 216 insertions(+), 30 deletions(-) create mode 100644 hal/ipp/src/samplers_ipp.cpp create mode 100644 modules/imgproc/perf/perf_getrectsubpix.cpp diff --git a/hal/ipp/CMakeLists.txt b/hal/ipp/CMakeLists.txt index c83182df12..aac7fd0d16 100644 --- a/hal/ipp/CMakeLists.txt +++ b/hal/ipp/CMakeLists.txt @@ -27,6 +27,7 @@ add_library(ipphal STATIC "${CMAKE_CURRENT_SOURCE_DIR}/src/threshold_ipp.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/distancetransform_ipp.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/histogram_ipp.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/samplers_ipp.cpp" ) #TODO: HAVE_IPP_ICV and HAVE_IPP_IW added as private macro till OpenCV itself is diff --git a/hal/ipp/include/ipp_hal_imgproc.hpp b/hal/ipp/include/ipp_hal_imgproc.hpp index 25ffc31003..368285bdc2 100644 --- a/hal/ipp/include/ipp_hal_imgproc.hpp +++ b/hal/ipp/include/ipp_hal_imgproc.hpp @@ -159,6 +159,12 @@ int ipp_hal_calcHist(const uchar* src_data, size_t src_step, int src_type, int s #undef cv_hal_calcHist #define cv_hal_calcHist ipp_hal_calcHist +int ipp_hal_getRectSubPix(int src_type, const uchar* src_data, size_t src_step, int src_width, int src_height, + int patch_type, uchar* patch_data, size_t patch_step, int patch_width, int patch_height, + double center_x, double center_y); +#undef cv_hal_getRectSubPix +#define cv_hal_getRectSubPix ipp_hal_getRectSubPix + #endif // IPP_VERSION_X100 >= 700 #define IPP_DISABLE_PERF_CANNY_MT 1 // cv::Canny OpenCV MT performance is better diff --git a/hal/ipp/src/samplers_ipp.cpp b/hal/ipp/src/samplers_ipp.cpp new file mode 100644 index 0000000000..d757eff4be --- /dev/null +++ b/hal/ipp/src/samplers_ipp.cpp @@ -0,0 +1,49 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// Copyright (C) 2026, BigVision LLC, all rights reserved. +// Third party copyrights are property of their respective owners. + +#include "ipp_hal_imgproc.hpp" + +#include +#include "precomp_ipp.hpp" + +#if IPP_VERSION_X100 >= 700 + +using namespace cv; + +int ipp_hal_getRectSubPix(int src_type, const uchar* src_data, size_t src_step, int src_width, int src_height, + int patch_type, uchar* patch_data, size_t patch_step, int patch_width, int patch_height, + double center_x, double center_y) +{ + CV_HAL_CHECK_USE_IPP(); + + int ddepth = CV_MAT_DEPTH(patch_type); + + typedef IppStatus (CV_STDCALL *ippiGetRectSubPixFunc)( const void* src, int src_step, + IppiSize src_size, void* dst, + int dst_step, IppiSize win_size, + IppiPoint_32f center, + IppiPoint* minpt, IppiPoint* maxpt ); + + ippiGetRectSubPixFunc ippiCopySubpixIntersect = + src_type == CV_8UC1 && ddepth == CV_8U ? (ippiGetRectSubPixFunc)ippiCopySubpixIntersect_8u_C1R : + src_type == CV_8UC1 && ddepth == CV_32F ? (ippiGetRectSubPixFunc)ippiCopySubpixIntersect_8u32f_C1R : + src_type == CV_32FC1 && ddepth == CV_32F ? (ippiGetRectSubPixFunc)ippiCopySubpixIntersect_32f_C1R : 0; + + if( ippiCopySubpixIntersect ) + { + IppiPoint minpt = {0, 0}, maxpt = {0, 0}; + IppiPoint_32f icenter = {(float)center_x, (float)center_y}; + IppiSize src_size = {src_width, src_height}, win_size = {patch_width, patch_height}; + + if( CV_INSTRUMENT_FUN_IPP(ippiCopySubpixIntersect, src_data, (int)src_step, src_size, patch_data, + (int)patch_step, win_size, icenter, &minpt, &maxpt) >= 0 ) + return CV_HAL_ERROR_OK; + } + + return CV_HAL_ERROR_NOT_IMPLEMENTED; +} + +#endif diff --git a/modules/imgproc/perf/perf_getrectsubpix.cpp b/modules/imgproc/perf/perf_getrectsubpix.cpp new file mode 100644 index 0000000000..38def047be --- /dev/null +++ b/modules/imgproc/perf/perf_getrectsubpix.cpp @@ -0,0 +1,134 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// Copyright (C) 2026, BigVision LLC, all rights reserved. +// Third party copyrights are property of their respective owners. +#include "perf_precomp.hpp" + +namespace opencv_test { + +CV_ENUM(PatchDepth, CV_8U, CV_32F) + +typedef tuple GetRectSubPixParams; +typedef perf::TestBaseWithParam GetRectSubPix_Test; + +// Chessboard inner corners (9x6) of the cv/stereo/case1 boards, detected once with +// findChessboardCorners and hard-coded so this perf test needs no calib dependency. +static const Point2f corners_left01[] = { + Point2f(244.4541f, 94.3314f), Point2f(274.6218f, 92.2413f), Point2f(305.4939f, 90.4029f), + Point2f(338.3641f, 88.8363f), Point2f(371.5922f, 87.9836f), Point2f(406.8435f, 86.9164f), + Point2f(441.6335f, 86.3721f), Point2f(477.6230f, 86.3797f), Point2f(513.9866f, 86.7991f), + Point2f(244.9995f, 126.5384f), Point2f(274.9684f, 124.7523f), Point2f(306.0444f, 124.0323f), + Point2f(338.7149f, 123.2651f), Point2f(372.0939f, 122.1290f), Point2f(406.6485f, 122.1684f), + Point2f(442.1944f, 122.2465f), Point2f(477.8674f, 122.1053f), Point2f(514.0326f, 122.9214f), + Point2f(245.4698f, 158.3554f), Point2f(275.3708f, 158.3770f), Point2f(306.4206f, 157.6200f), + Point2f(338.7076f, 157.4221f), Point2f(372.3548f, 157.3757f), Point2f(406.5436f, 157.4915f), + Point2f(442.1193f, 157.6772f), Point2f(477.6427f, 158.4171f), Point2f(513.5308f, 159.2809f), + Point2f(246.3835f, 190.2633f), Point2f(275.7964f, 190.6393f), Point2f(307.2744f, 191.0970f), + Point2f(339.1837f, 191.5760f), Point2f(372.3740f, 191.8712f), Point2f(406.9517f, 192.4470f), + Point2f(441.5515f, 193.6797f), Point2f(477.3305f, 194.3325f), Point2f(513.2557f, 195.5269f), + Point2f(247.4330f, 222.4675f), Point2f(276.8233f, 223.4360f), Point2f(307.4332f, 224.2435f), + Point2f(339.5576f, 225.2065f), Point2f(372.9427f, 226.4245f), Point2f(406.4261f, 227.5323f), + Point2f(441.4084f, 228.5345f), Point2f(476.7176f, 230.1001f), Point2f(511.5294f, 231.5994f), + Point2f(248.7999f, 253.5990f), Point2f(277.5086f, 255.1773f), Point2f(308.5765f, 256.4403f), + Point2f(340.3875f, 258.2953f), Point2f(372.7524f, 259.7994f), Point2f(406.1046f, 261.6587f), + Point2f(440.4359f, 263.3060f), Point2f(475.4150f, 264.7134f), Point2f(510.1775f, 266.1992f), +}; + +static const Point2f corners_left02[] = { + Point2f(256.5867f, 357.3861f), Point2f(255.3215f, 334.4808f), Point2f(254.7554f, 309.0343f), + Point2f(253.2735f, 280.1345f), Point2f(252.5384f, 248.0337f), Point2f(251.7535f, 212.7699f), + Point2f(251.2085f, 172.4518f), Point2f(251.3873f, 128.3270f), Point2f(251.4556f, 78.3560f), + Point2f(291.6361f, 365.9622f), Point2f(292.5572f, 343.3497f), Point2f(293.5726f, 318.2415f), + Point2f(295.2780f, 289.9100f), Point2f(296.7264f, 257.9767f), Point2f(298.7410f, 222.1348f), + Point2f(301.2631f, 182.4788f), Point2f(303.7642f, 136.7058f), Point2f(307.1471f, 86.7391f), + Point2f(327.6240f, 374.3524f), Point2f(330.8632f, 352.3100f), Point2f(334.4490f, 327.3103f), + Point2f(337.8723f, 299.4167f), Point2f(342.3027f, 267.7063f), Point2f(347.3625f, 232.3861f), + Point2f(352.3509f, 192.1027f), Point2f(358.5134f, 147.0249f), Point2f(365.3164f, 97.3291f), + Point2f(364.5553f, 381.6275f), Point2f(369.4413f, 360.3667f), Point2f(375.1765f, 335.9256f), + Point2f(381.4051f, 308.1661f), Point2f(388.5566f, 277.6599f), Point2f(396.0829f, 242.0081f), + Point2f(404.5149f, 202.7227f), Point2f(413.7823f, 158.0101f), Point2f(424.3409f, 107.9548f), + Point2f(401.3313f, 389.5627f), Point2f(408.5090f, 368.3929f), Point2f(416.5022f, 344.4312f), + Point2f(425.1089f, 317.5573f), Point2f(434.4975f, 286.7095f), Point2f(445.0846f, 252.4719f), + Point2f(456.7321f, 213.5597f), Point2f(469.1978f, 169.3279f), Point2f(483.2666f, 120.4614f), + Point2f(437.8366f, 396.5025f), Point2f(446.5643f, 375.8865f), Point2f(456.9603f, 352.2726f), + Point2f(467.8020f, 326.0813f), Point2f(480.4469f, 295.9886f), Point2f(493.1928f, 262.2359f), + Point2f(508.0341f, 223.9814f), Point2f(523.4081f, 181.1591f), Point2f(540.2076f, 133.2355f), +}; + +static const Point2f corners_left03[] = { + Point2f(277.4323f, 72.5290f), Point2f(313.4367f, 81.5630f), Point2f(352.9303f, 91.0506f), + Point2f(393.5079f, 101.8541f), Point2f(434.6314f, 113.5358f), Point2f(476.8674f, 126.6859f), + Point2f(519.5198f, 139.4719f), Point2f(562.0754f, 154.0302f), Point2f(603.5757f, 168.5026f), + Point2f(259.6532f, 105.6526f), Point2f(297.3900f, 115.0693f), Point2f(337.2212f, 126.4162f), + Point2f(378.3126f, 137.9841f), Point2f(421.3062f, 150.6102f), Point2f(464.5258f, 164.5774f), + Point2f(508.5670f, 178.7557f), Point2f(552.4766f, 193.4379f), Point2f(595.2234f, 208.4552f), + Point2f(242.7253f, 141.3230f), Point2f(279.8400f, 152.2348f), Point2f(320.5120f, 163.9313f), + Point2f(362.5777f, 177.0284f), Point2f(406.0779f, 190.5102f), Point2f(450.5823f, 205.4244f), + Point2f(495.9811f, 220.1399f), Point2f(541.2142f, 235.4248f), Point2f(585.0867f, 250.9424f), + Point2f(223.8041f, 178.0292f), Point2f(262.7206f, 190.8443f), Point2f(303.1327f, 204.2207f), + Point2f(345.8119f, 218.4479f), Point2f(389.5984f, 233.0941f), Point2f(435.4800f, 248.5219f), + Point2f(481.7506f, 264.2025f), Point2f(528.0433f, 280.0055f), Point2f(573.3781f, 295.7106f), + Point2f(205.9287f, 217.1566f), Point2f(244.4685f, 230.9739f), Point2f(285.0102f, 245.5548f), + Point2f(328.2179f, 261.5405f), Point2f(373.1269f, 277.2205f), Point2f(419.5606f, 293.7301f), + Point2f(466.3259f, 310.0434f), Point2f(513.5237f, 326.6496f), Point2f(559.9616f, 342.5871f), + Point2f(187.4462f, 257.4862f), Point2f(225.3331f, 272.8211f), Point2f(266.7754f, 289.3292f), + Point2f(309.9885f, 305.9286f), Point2f(354.7533f, 323.2353f), Point2f(402.4073f, 340.2387f), + Point2f(449.5339f, 357.9061f), Point2f(497.6018f, 374.2831f), Point2f(544.2325f, 390.1797f), +}; + +struct Board { const char* path; const Point2f* corners; int ncorners; }; +static const Board g_boards[] = { + { "cv/stereo/case1/left01.png", corners_left01, (int)(sizeof(corners_left01) / sizeof(Point2f)) }, + { "cv/stereo/case1/left02.png", corners_left02, (int)(sizeof(corners_left02) / sizeof(Point2f)) }, + { "cv/stereo/case1/left03.png", corners_left03, (int)(sizeof(corners_left03) / sizeof(Point2f)) }, +}; + +PERF_TEST_P(GetRectSubPix_Test, getRectSubPix, + testing::Combine( + testing::Values(Size(16, 16), Size(32, 32), Size(64, 64), Size(128, 128)), + testing::Values(CV_8UC1, CV_32FC1), + PatchDepth::all() + ) + ) +{ + Size patchSize = get<0>(GetParam()); + int srcType = get<1>(GetParam()); + int patchDepth = get<2>(GetParam()); + + // getRectSubPix supports only 8U->8U, 8U->32F and 32F->32F + if (CV_MAT_DEPTH(srcType) == CV_32F && patchDepth == CV_8U) + throw SkipTestException("getRectSubPix does not support 32F source with 8U patch"); + + const size_t nboards = sizeof(g_boards) / sizeof(g_boards[0]); + std::vector srcs; + for (size_t b = 0; b < nboards; b++) + { + Mat image = imread(getDataPath(g_boards[b].path), IMREAD_GRAYSCALE); + ASSERT_FALSE(image.empty()); + if (CV_MAT_DEPTH(srcType) == CV_32F) + { + Mat f; + image.convertTo(f, CV_32F); + srcs.push_back(f); + } + else + srcs.push_back(image); + } + + int patchType = CV_MAKETYPE(patchDepth, 1); + Mat patch(patchSize, patchType); + + declare.in(srcs[0]); + + TEST_CYCLE() + { + for (size_t b = 0; b < nboards; b++) + for (int i = 0; i < g_boards[b].ncorners; i++) + getRectSubPix(srcs[b], patchSize, g_boards[b].corners[i], patch, patchType); + } + + SANITY_CHECK_NOTHING(); +} + +} // namespace diff --git a/modules/imgproc/src/hal_replacement.hpp b/modules/imgproc/src/hal_replacement.hpp index ca6ce6acd8..ccdc838a78 100644 --- a/modules/imgproc/src/hal_replacement.hpp +++ b/modules/imgproc/src/hal_replacement.hpp @@ -460,6 +460,28 @@ inline int hal_ni_warpPerspectiveBlockline(const double *M, short* xy, short* al #define cv_hal_warpPerspectiveBlockline hal_ni_warpPerspectiveBlockline //! @endcond +/** + @brief hal_getRectSubPix extract a rectangle from an image with sub-pixel accuracy + @param src_type source image type + @param src_data source image data + @param src_step source image step + @param src_width source image width + @param src_height source image height + @param patch_type extracted patch type + @param patch_data extracted patch data + @param patch_step extracted patch step + @param patch_width extracted patch width + @param patch_height extracted patch height + @param center_x x-coordinate of the rectangle center (sub-pixel) + @param center_y y-coordinate of the rectangle center (sub-pixel) + @sa cv::getRectSubPix + */ +inline int hal_ni_getRectSubPix(int src_type, const uchar* src_data, size_t src_step, int src_width, int src_height, int patch_type, uchar* patch_data, size_t patch_step, int patch_width, int patch_height, double center_x, double center_y) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } + +//! @cond IGNORED +#define cv_hal_getRectSubPix hal_ni_getRectSubPix +//! @endcond + /** @brief hal_remap with floating point maps @param src_type source and destination image type diff --git a/modules/imgproc/src/samplers.cpp b/modules/imgproc/src/samplers.cpp index 5fb30c9434..a1ef27db20 100644 --- a/modules/imgproc/src/samplers.cpp +++ b/modules/imgproc/src/samplers.cpp @@ -376,36 +376,10 @@ void cv::getRectSubPix( InputArray _image, Size patchSize, Point2f center, _patch.create(patchSize, CV_MAKETYPE(ddepth, cn)); Mat patch = _patch.getMat(); -#if defined (HAVE_IPP) && (IPP_VERSION_X100 >= 700) - CV_IPP_CHECK() - { - typedef IppStatus (CV_STDCALL *ippiGetRectSubPixFunc)( const void* src, int src_step, - IppiSize src_size, void* dst, - int dst_step, IppiSize win_size, - IppiPoint_32f center, - IppiPoint* minpt, IppiPoint* maxpt ); - - IppiPoint minpt={0,0}, maxpt={0,0}; - IppiPoint_32f icenter = {center.x, center.y}; - IppiSize src_size={image.cols, image.rows}, win_size={patch.cols, patch.rows}; - int srctype = image.type(); - ippiGetRectSubPixFunc ippiCopySubpixIntersect = - srctype == CV_8UC1 && ddepth == CV_8U ? (ippiGetRectSubPixFunc)ippiCopySubpixIntersect_8u_C1R : - srctype == CV_8UC1 && ddepth == CV_32F ? (ippiGetRectSubPixFunc)ippiCopySubpixIntersect_8u32f_C1R : - srctype == CV_32FC1 && ddepth == CV_32F ? (ippiGetRectSubPixFunc)ippiCopySubpixIntersect_32f_C1R : 0; - - if( ippiCopySubpixIntersect) - { - if (CV_INSTRUMENT_FUN_IPP(ippiCopySubpixIntersect, image.ptr(), (int)image.step, src_size, patch.ptr(), - (int)patch.step, win_size, icenter, &minpt, &maxpt) >= 0) - { - CV_IMPL_ADD(CV_IMPL_IPP); - return; - } - setIppErrorStatus(); - } - } -#endif + CALL_HAL(getRectSubPix, cv_hal_getRectSubPix, + image.type(), image.data, image.step, image.cols, image.rows, + patch.type(), patch.data, patch.step, patch.cols, patch.rows, + center.x, center.y); if( depth == CV_8U && ddepth == CV_8U ) getRectSubPix_Cn_