From c77286749ae8daff65b5dfa1f4d0608c613174ea Mon Sep 17 00:00:00 2001 From: Prasad Ayush Kumar <129419372+Prasadayus@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:40:52 +0530 Subject: [PATCH] Merge pull request #29420 from Prasadayus:box_filter_ipp_extract Extract IPP integration as HAL function for box_filter #29420 Backport of https://github.com/opencv/opencv/pull/29414 **Performance Numbers on Intel(R) Core(TM) i9-11900K:** https://docs.google.com/spreadsheets/d/1kMKiZWh--pH30hqsQo6j1suNw1lfQiKzSankMCMa2FI/edit?usp=sharing ### 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 | 14 +- hal/ipp/src/box_filter_ipp.cpp | 144 ++++++++++++++++++++ modules/imgproc/src/box_filter.dispatch.cpp | 47 ------- 4 files changed, 158 insertions(+), 48 deletions(-) create mode 100644 hal/ipp/src/box_filter_ipp.cpp diff --git a/hal/ipp/CMakeLists.txt b/hal/ipp/CMakeLists.txt index 9427d5924c..87103fb803 100644 --- a/hal/ipp/CMakeLists.txt +++ b/hal/ipp/CMakeLists.txt @@ -18,6 +18,7 @@ add_library(ipphal STATIC "${CMAKE_CURRENT_SOURCE_DIR}/src/warp_ipp.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/deriv_ipp.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/resize_ipp.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/box_filter_ipp.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/sum_ipp.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/color_ipp.cpp" ) diff --git a/hal/ipp/include/ipp_hal_imgproc.hpp b/hal/ipp/include/ipp_hal_imgproc.hpp index dec9ec7ab8..d70fc83b0b 100644 --- a/hal/ipp/include/ipp_hal_imgproc.hpp +++ b/hal/ipp/include/ipp_hal_imgproc.hpp @@ -8,8 +8,10 @@ #include #include "ipp_utils.hpp" -#if IPP_VERSION_X100 >= 810 +// Disabled in https://github.com/opencv/opencv/pull/13085 due large binary size +#define DISABLE_IPP_BOX_FILTER 1 +#if IPP_VERSION_X100 >= 810 #if defined(HAVE_IPP_IW) int ipp_hal_warpAffine(int src_type, const uchar *src_data, size_t src_step, int src_width, int src_height, uchar *dst_data, size_t dst_step, int dst_width, int dst_height, const double M[6], int interpolation, int borderType, const double borderValue[4]); @@ -49,6 +51,16 @@ int ipp_hal_resize(int src_type, const uchar *src_data, size_t src_step, int src #define cv_hal_resize ipp_hal_resize #endif // HAVE_IPP_IW +#if defined(HAVE_IPP_IW) && !DISABLE_IPP_BOX_FILTER +int ipp_hal_boxFilter(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, + int width, int height, int src_depth, int dst_depth, int cn, + int margin_left, int margin_top, int margin_right, int margin_bottom, + size_t ksize_width, size_t ksize_height, int anchor_x, int anchor_y, + bool normalize, int border_type); +#undef cv_hal_boxFilter +#define cv_hal_boxFilter ipp_hal_boxFilter +#endif // defined(HAVE_IPP_IW) && !DISABLE_IPP_BOX_FILTER + int ipp_hal_remap32f(int src_type, const uchar *src_data, size_t src_step, int src_width, int src_height, uchar *dst_data, size_t dst_step, int dst_width, int dst_height, float* mapx, size_t mapx_step, float* mapy, size_t mapy_step, diff --git a/hal/ipp/src/box_filter_ipp.cpp b/hal/ipp/src/box_filter_ipp.cpp new file mode 100644 index 0000000000..b289a31cf9 --- /dev/null +++ b/hal/ipp/src/box_filter_ipp.cpp @@ -0,0 +1,144 @@ +// 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 defined(HAVE_IPP_IW) && !DISABLE_IPP_BOX_FILTER + +namespace cv { namespace ipp { unsigned long long getIppTopFeatures(); } } + +// Copied from core/private.hpp (gated by HAVE_IPP, which the plugin lacks). +// boxGetIppBorderType: distinct name, adds the REFLECT_101 precomp's version drops. +static inline IppiBorderType boxGetIppBorderType(int borderTypeNI) +{ + return borderTypeNI == cv::BORDER_CONSTANT ? ippBorderConst : + borderTypeNI == cv::BORDER_TRANSPARENT ? ippBorderTransp : + borderTypeNI == cv::BORDER_REPLICATE ? ippBorderRepl : + borderTypeNI == cv::BORDER_REFLECT_101 ? ippBorderMirror : + (IppiBorderType)-1; +} + +static inline bool ippiCheckAnchor(int x, int y, int kernelWidth, int kernelHeight) +{ + return (x == (kernelWidth - 1)/2 && y == (kernelHeight - 1)/2); +} + +static inline IppiBorderType ippiGetBorder(::ipp::IwiImage &image, int ocvBorderType, ::ipp::IwiBorderSize &borderSize) +{ + int inMemFlags = 0; + IppiBorderType border = boxGetIppBorderType(ocvBorderType & ~cv::BORDER_ISOLATED); + if((int)border == -1) + return (IppiBorderType)0; + + if(!(ocvBorderType & cv::BORDER_ISOLATED)) + { + if(image.m_inMemSize.left) + { + if(image.m_inMemSize.left >= borderSize.left) + inMemFlags |= ippBorderInMemLeft; + else + return (IppiBorderType)0; + } + else + borderSize.left = 0; + if(image.m_inMemSize.top) + { + if(image.m_inMemSize.top >= borderSize.top) + inMemFlags |= ippBorderInMemTop; + else + return (IppiBorderType)0; + } + else + borderSize.top = 0; + if(image.m_inMemSize.right) + { + if(image.m_inMemSize.right >= borderSize.right) + inMemFlags |= ippBorderInMemRight; + else + return (IppiBorderType)0; + } + else + borderSize.right = 0; + if(image.m_inMemSize.bottom) + { + if(image.m_inMemSize.bottom >= borderSize.bottom) + inMemFlags |= ippBorderInMemBottom; + else + return (IppiBorderType)0; + } + else + borderSize.bottom = 0; + } + else + borderSize.left = borderSize.right = borderSize.top = borderSize.bottom = 0; + + return (IppiBorderType)(border | inMemFlags); +} + +int ipp_hal_boxFilter(const uchar* src_data, size_t src_step, + uchar* dst_data, size_t dst_step, + int width, int height, int src_depth, int dst_depth, int cn, + int margin_left, int margin_top, int margin_right, int margin_bottom, + size_t ksize_width, size_t ksize_height, + int anchor_x, int anchor_y, + bool normalize, int border_type) +{ + CV_HAL_CHECK_USE_IPP(); + +#if IPP_VERSION_X100 < 201801 + // Problem with SSE42 optimization for 16s and some 8u modes + if(cv::ipp::getIppTopFeatures() == ippCPUID_SSE42 && + (((src_depth == CV_16S || src_depth == CV_16U) && (cn == 3 || cn == 4)) || + (src_depth == CV_8U && cn == 3 && (ksize_width > 5 || ksize_height > 5)))) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + + // Other optimizations has some degradations too + if(((src_depth == CV_16S || src_depth == CV_16U) && cn == 4) || + (src_depth == CV_8U && cn == 1 && (ksize_width > 5 || ksize_height > 5))) + return CV_HAL_ERROR_NOT_IMPLEMENTED; +#endif + + if(!normalize) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + + if(!ippiCheckAnchor(anchor_x, anchor_y, (int)ksize_width, (int)ksize_height)) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + + try + { + // raw-pointer equivalent of ippiGetImage: margins are the in-memory border + ::ipp::IwiBorderSize inMemBorder; + inMemBorder.left = (IwSize)margin_left; + inMemBorder.top = (IwSize)margin_top; + inMemBorder.right = (IwSize)margin_right; + inMemBorder.bottom = (IwSize)margin_bottom; + + ::ipp::IwiImage iwSrc, iwDst; + iwSrc.Init(IwiSize{width, height}, ippiGetDataType(src_depth), cn, + inMemBorder, (void*)src_data, IwSize(src_step)); + iwDst.Init(IwiSize{width, height}, ippiGetDataType(dst_depth), cn, + ::ipp::IwiBorderSize(), dst_data, IwSize(dst_step)); + + ::ipp::IwiSize iwKSize{(int)ksize_width, (int)ksize_height}; + ::ipp::IwiBorderSize borderSize(iwKSize); + ::ipp::IwiBorderType ippBorder(ippiGetBorder(iwSrc, border_type, borderSize)); + if(!ippBorder) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + + CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterBox, iwSrc, iwDst, iwKSize, ::ipp::IwDefault(), ippBorder); + } + catch (const ::ipp::IwException &) + { + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + return CV_HAL_ERROR_OK; +} + +#endif // defined(HAVE_IPP_IW) && !DISABLE_IPP_BOX_FILTER diff --git a/modules/imgproc/src/box_filter.dispatch.cpp b/modules/imgproc/src/box_filter.dispatch.cpp index 1d23c72859..64a895b8c8 100644 --- a/modules/imgproc/src/box_filter.dispatch.cpp +++ b/modules/imgproc/src/box_filter.dispatch.cpp @@ -314,52 +314,6 @@ Ptr createBoxFilter(int srcType, int dstType, Size ksize, CV_CPU_DISPATCH_MODES_ALL); } -#if 0 //defined(HAVE_IPP) -static bool ipp_boxfilter(Mat &src, Mat &dst, Size ksize, Point anchor, bool normalize, int borderType) -{ -#ifdef HAVE_IPP_IW - CV_INSTRUMENT_REGION_IPP(); - -#if IPP_VERSION_X100 < 201801 - // Problem with SSE42 optimization for 16s and some 8u modes - if(ipp::getIppTopFeatures() == ippCPUID_SSE42 && (((src.depth() == CV_16S || src.depth() == CV_16U) && (src.channels() == 3 || src.channels() == 4)) || (src.depth() == CV_8U && src.channels() == 3 && (ksize.width > 5 || ksize.height > 5)))) - return false; - - // Other optimizations has some degradations too - if((((src.depth() == CV_16S || src.depth() == CV_16U) && (src.channels() == 4)) || (src.depth() == CV_8U && src.channels() == 1 && (ksize.width > 5 || ksize.height > 5)))) - return false; -#endif - - if(!normalize) - return false; - - if(!ippiCheckAnchor(anchor, ksize)) - return false; - - try - { - ::ipp::IwiImage iwSrc = ippiGetImage(src); - ::ipp::IwiImage iwDst = ippiGetImage(dst); - ::ipp::IwiSize iwKSize = ippiGetSize(ksize); - ::ipp::IwiBorderSize borderSize(iwKSize); - ::ipp::IwiBorderType ippBorder(ippiGetBorder(iwSrc, borderType, borderSize)); - if(!ippBorder) - return false; - - CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterBox, iwSrc, iwDst, iwKSize, ::ipp::IwDefault(), ippBorder); - } - catch (const ::ipp::IwException &) - { - return false; - } - - return true; -#else - CV_UNUSED(src); CV_UNUSED(dst); CV_UNUSED(ksize); CV_UNUSED(anchor); CV_UNUSED(normalize); CV_UNUSED(borderType); - return false; -#endif -} -#endif void boxFilter(InputArray _src, OutputArray _dst, int ddepth, @@ -401,7 +355,6 @@ void boxFilter(InputArray _src, OutputArray _dst, int ddepth, ofs.x, ofs.y, wsz.width - src.cols - ofs.x, wsz.height - src.rows - ofs.y, ksize.width, ksize.height, anchor.x, anchor.y, normalize, borderType&~BORDER_ISOLATED); - //CV_IPP_RUN_FAST(ipp_boxfilter(src, dst, ksize, anchor, normalize, borderType)); borderType = (borderType&~BORDER_ISOLATED);