diff --git a/hal/ipp/CMakeLists.txt b/hal/ipp/CMakeLists.txt index 7a3a48bacc..9318b931d1 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/box_filter_ipp.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/sum_ipp.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/filter_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 5c5999c1f3..7272cd2fe1 100644 --- a/hal/ipp/include/ipp_hal_imgproc.hpp +++ b/hal/ipp/include/ipp_hal_imgproc.hpp @@ -10,6 +10,10 @@ // Disabled in https://github.com/opencv/opencv/pull/13085 due large binary size #define DISABLE_IPP_BOX_FILTER 1 +// IPP filter2D integration is disabled in main OpenCV; kept behind a macro like box filter. +#define DISABLE_IPP_FILTER2D 1 +// Too big difference compared to OpenCV FFT-based convolution, different results on masks > 7x7 +#define IPP_DISABLE_FILTER2D_BIG_MASK 1 #if IPP_VERSION_X100 >= 810 @@ -50,6 +54,19 @@ int ipp_hal_boxFilter(const uchar* src_data, size_t src_step, uchar* dst_data, s #define cv_hal_boxFilter ipp_hal_boxFilter #endif // defined(HAVE_IPP_IW) && !DISABLE_IPP_BOX_FILTER +#if defined(HAVE_IPP_IW) && !DISABLE_IPP_FILTER2D +int ipp_hal_filter2D(const uchar * src_data, size_t src_step, int src_type, + uchar * dst_data, size_t dst_step, int dst_type, + int width, int height, int full_width, int full_height, + int offset_x, int offset_y, + const uchar * kernel_data, size_t kernel_step, int kernel_type, + int kernel_width, int kernel_height, + int anchor_x, int anchor_y, double delta, int borderType, + bool isSubmatrix, bool allowInplace); +#undef cv_hal_filter_stateless +#define cv_hal_filter_stateless ipp_hal_filter2D +#endif // defined(HAVE_IPP_IW) && !DISABLE_IPP_FILTER2D + #endif //IPP_VERSION_X100 >= 810 #if IPP_VERSION_X100 >= 700 diff --git a/hal/ipp/src/filter_ipp.cpp b/hal/ipp/src/filter_ipp.cpp new file mode 100644 index 0000000000..4066ddf59e --- /dev/null +++ b/hal/ipp/src/filter_ipp.cpp @@ -0,0 +1,162 @@ +// 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 + +#include "ipp_hal_imgproc.hpp" + +#if IPP_VERSION_X100 >= 810 + +#include +#include "precomp_ipp.hpp" + +#include +#include + +#if defined(HAVE_IPP_IW) && !DISABLE_IPP_FILTER2D + +#include "iw++/iw.hpp" + +static inline bool ippiCheckAnchor(int x, int y, int kernelWidth, int kernelHeight) +{ + return (x == ((kernelWidth - 1) / 2) && y == ((kernelHeight - 1) / 2)); +} + +static inline IppiBorderType ippiFilterGetBorderType(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 IppiBorderType ippiGetBorder(::ipp::IwiImage &image, int ocvBorderType, ::ipp::IwiBorderSize &borderSize) +{ + int inMemFlags = 0; + IppiBorderType border = ippiFilterGetBorderType(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_filter2D(const uchar * src_data, size_t src_step, int src_type, + uchar * dst_data, size_t dst_step, int dst_type, + int width, int height, int full_width, int full_height, + int offset_x, int offset_y, + const uchar * kernel_data, size_t kernel_step, int kernel_type, + int kernel_width, int kernel_height, + int anchor_x, int anchor_y, double delta, int borderType, + bool isSubmatrix, bool allowInplace) +{ + CV_HAL_CHECK_USE_IPP(); + + ::ipp::IwiSize iwSize(width, height); + ::ipp::IwiSize kernelSize(kernel_width, kernel_height); + IppDataType type = ippiGetDataType(CV_MAT_DEPTH(src_type)); + int channels = CV_MAT_CN(src_type); + + CV_UNUSED(isSubmatrix); + CV_UNUSED(allowInplace); + +#if IPP_VERSION_X100 >= 201700 && IPP_VERSION_X100 <= 201702 // IPP bug with 1x1 kernel + if(kernel_width == 1 && kernel_height == 1) + return CV_HAL_ERROR_NOT_IMPLEMENTED; +#endif + +#if IPP_DISABLE_FILTER2D_BIG_MASK + // Too big difference compared to OpenCV FFT-based convolution + if(kernel_type == CV_32FC1 && (type == ipp16s || type == ipp16u) && (kernel_width > 7 || kernel_height > 7)) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + + // Poor optimization for big kernels + if(kernel_width > 7 || kernel_height > 7) + return CV_HAL_ERROR_NOT_IMPLEMENTED; +#endif + + if(src_data == dst_data) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + + if(src_type != dst_type) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + + if(kernel_type != CV_16SC1 && kernel_type != CV_32FC1) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + + // TODO: Implement offset for 8u, 16u + if(std::fabs(delta) >= DBL_EPSILON) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + + if(!ippiCheckAnchor(anchor_x, anchor_y, kernel_width, kernel_height)) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + + try + { + ::ipp::IwiBorderSize iwBorderSize; + ::ipp::IwiBorderType iwBorderType; + ::ipp::IwiImage iwKernel(ippiSize(kernel_width, kernel_height), ippiGetDataType(CV_MAT_DEPTH(kernel_type)), CV_MAT_CN(kernel_type), 0, (void*)kernel_data, kernel_step); + ::ipp::IwiImage iwSrc(iwSize, type, channels, ::ipp::IwiBorderSize(offset_x, offset_y, full_width-offset_x-width, full_height-offset_y-height), (void*)src_data, src_step); + ::ipp::IwiImage iwDst(iwSize, type, channels, ::ipp::IwiBorderSize(offset_x, offset_y, full_width-offset_x-width, full_height-offset_y-height), (void*)dst_data, dst_step); + + iwBorderSize = ::ipp::iwiSizeToBorderSize(kernelSize); + iwBorderType = ippiGetBorder(iwSrc, borderType, iwBorderSize); + if(!iwBorderType) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + + CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilter, iwSrc, iwDst, iwKernel, ::ipp::IwiFilterParams(1, 0, ippAlgHintNone, ippRndFinancial), iwBorderType); + } + catch(const ::ipp::IwException& ex) + { + CV_UNUSED(ex); + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + CV_IMPL_ADD(CV_IMPL_IPP); + return CV_HAL_ERROR_OK; +} + +#endif // defined(HAVE_IPP_IW) && !DISABLE_IPP_FILTER2D + +#endif // IPP_VERSION_X100 >= 810 diff --git a/modules/imgproc/src/filter.dispatch.cpp b/modules/imgproc/src/filter.dispatch.cpp index e7be678799..228972f719 100644 --- a/modules/imgproc/src/filter.dispatch.cpp +++ b/modules/imgproc/src/filter.dispatch.cpp @@ -1227,93 +1227,6 @@ static bool replacementFilter2D(int stype, int dtype, int kernel_type, return success; } -#if 0 //defined HAVE_IPP -static bool ippFilter2D(int stype, int dtype, int kernel_type, - uchar * src_data, size_t src_step, - uchar * dst_data, size_t dst_step, - int width, int height, - int full_width, int full_height, - int offset_x, int offset_y, - uchar * kernel_data, size_t kernel_step, - int kernel_width, int kernel_height, - int anchor_x, int anchor_y, - double delta, int borderType, - bool isSubmatrix) -{ -#ifdef HAVE_IPP_IW - CV_INSTRUMENT_REGION_IPP(); - - ::ipp::IwiSize iwSize(width, height); - ::ipp::IwiSize kernelSize(kernel_width, kernel_height); - IppDataType type = ippiGetDataType(CV_MAT_DEPTH(stype)); - int channels = CV_MAT_CN(stype); - - CV_UNUSED(isSubmatrix); - -#if IPP_VERSION_X100 >= 201700 && IPP_VERSION_X100 <= 201702 // IPP bug with 1x1 kernel - if(kernel_width == 1 && kernel_height == 1) - return false; -#endif - -#if IPP_DISABLE_FILTER2D_BIG_MASK - // Too big difference compared to OpenCV FFT-based convolution - if(kernel_type == CV_32FC1 && (type == ipp16s || type == ipp16u) && (kernel_width > 7 || kernel_height > 7)) - return false; - - // Poor optimization for big kernels - if(kernel_width > 7 || kernel_height > 7) - return false; -#endif - - if(src_data == dst_data) - return false; - - if(stype != dtype) - return false; - - if(kernel_type != CV_16SC1 && kernel_type != CV_32FC1) - return false; - - // TODO: Implement offset for 8u, 16u - if(std::fabs(delta) >= DBL_EPSILON) - return false; - - if(!ippiCheckAnchor(anchor_x, anchor_y, kernel_width, kernel_height)) - return false; - - try - { - ::ipp::IwiBorderSize iwBorderSize; - ::ipp::IwiBorderType iwBorderType; - ::ipp::IwiImage iwKernel(ippiSize(kernel_width, kernel_height), ippiGetDataType(CV_MAT_DEPTH(kernel_type)), CV_MAT_CN(kernel_type), 0, (void*)kernel_data, kernel_step); - ::ipp::IwiImage iwSrc(iwSize, type, channels, ::ipp::IwiBorderSize(offset_x, offset_y, full_width-offset_x-width, full_height-offset_y-height), (void*)src_data, src_step); - ::ipp::IwiImage iwDst(iwSize, type, channels, ::ipp::IwiBorderSize(offset_x, offset_y, full_width-offset_x-width, full_height-offset_y-height), (void*)dst_data, dst_step); - - iwBorderSize = ::ipp::iwiSizeToBorderSize(kernelSize); - iwBorderType = ippiGetBorder(iwSrc, borderType, iwBorderSize); - if(!iwBorderType) - return false; - - CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilter, iwSrc, iwDst, iwKernel, ::ipp::IwiFilterParams(1, 0, ippAlgHintNone, ippRndFinancial), iwBorderType); - } - catch(const ::ipp::IwException& ex) - { - CV_UNUSED(ex); - return false; - } - - return true; -#else - CV_UNUSED(stype); CV_UNUSED(dtype); CV_UNUSED(kernel_type); CV_UNUSED(src_data); CV_UNUSED(src_step); - CV_UNUSED(dst_data); CV_UNUSED(dst_step); CV_UNUSED(width); CV_UNUSED(height); CV_UNUSED(full_width); - CV_UNUSED(full_height); CV_UNUSED(offset_x); CV_UNUSED(offset_y); CV_UNUSED(kernel_data); CV_UNUSED(kernel_step); - CV_UNUSED(kernel_width); CV_UNUSED(kernel_height); CV_UNUSED(anchor_x); CV_UNUSED(anchor_y); CV_UNUSED(delta); - CV_UNUSED(borderType); CV_UNUSED(isSubmatrix); - return false; -#endif -} -#endif - static bool dftFilter2D(int stype, int dtype, int kernel_type, uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, @@ -1524,17 +1437,6 @@ void filter2D(int stype, int dtype, int kernel_type, if (res) return; - /*CV_IPP_RUN_FAST(ippFilter2D(stype, dtype, kernel_type, - src_data, src_step, - dst_data, dst_step, - width, height, - full_width, full_height, - offset_x, offset_y, - kernel_data, kernel_step, - kernel_width, kernel_height, - anchor_x, anchor_y, - delta, borderType, isSubmatrix))*/ - res = dftFilter2D(stype, dtype, kernel_type, src_data, src_step, dst_data, dst_step,