1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-21 19:33:03 +04:00

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
This commit is contained in:
Prasad Ayush Kumar
2026-07-02 15:40:52 +05:30
committed by GitHub
parent e6d0c0340b
commit c77286749a
4 changed files with 158 additions and 48 deletions
+1
View File
@@ -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"
)
+13 -1
View File
@@ -8,8 +8,10 @@
#include <opencv2/core/base.hpp>
#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,
+144
View File
@@ -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 <opencv2/core.hpp>
#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
@@ -314,52 +314,6 @@ Ptr<FilterEngine> 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);