From a77623a32be00be52073134184ce8ee6d181a1b1 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Sat, 22 Mar 2025 10:43:25 +0300 Subject: [PATCH] Move IPP minMaxIdx to HAL. --- 3rdparty/ipphal/CMakeLists.txt | 6 +- 3rdparty/ipphal/include/ipp_hal_core.hpp | 6 + 3rdparty/ipphal/src/minmax_ipp.cpp | 252 ++++++++++++++++++ modules/core/src/mean.dispatch.cpp | 17 -- modules/core/src/minmax.cpp | 312 ----------------------- 5 files changed, 262 insertions(+), 331 deletions(-) create mode 100644 3rdparty/ipphal/src/minmax_ipp.cpp diff --git a/3rdparty/ipphal/CMakeLists.txt b/3rdparty/ipphal/CMakeLists.txt index dc1ec627cb..5e69b0511e 100644 --- a/3rdparty/ipphal/CMakeLists.txt +++ b/3rdparty/ipphal/CMakeLists.txt @@ -8,8 +8,10 @@ set(IPP_HAL_HEADERS CACHE INTERNAL "") add_library(ipphal STATIC - "${CMAKE_CURRENT_SOURCE_DIR}/src/mean_ipp.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/src/norm_ipp.cpp") + "${CMAKE_CURRENT_SOURCE_DIR}/src/mean_ipp.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/minmax_ipp.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/norm_ipp.cpp" +) if(HAVE_IPP_ICV) target_compile_definitions(ipphal PRIVATE HAVE_IPP_ICV) diff --git a/3rdparty/ipphal/include/ipp_hal_core.hpp b/3rdparty/ipphal/include/ipp_hal_core.hpp index beb1524ac7..441a8bb207 100644 --- a/3rdparty/ipphal/include/ipp_hal_core.hpp +++ b/3rdparty/ipphal/include/ipp_hal_core.hpp @@ -11,6 +11,12 @@ int ipp_hal_meanStdDev(const uchar* src_data, size_t src_step, int width, int he #undef cv_hal_meanStdDev #define cv_hal_meanStdDev ipp_hal_meanStdDev +int ipp_hal_minMaxIdxMaskStep(const uchar* src_data, size_t src_step, int width, int height, int depth, + double* _minVal, double* _maxVal, int* _minIdx, int* _maxIdx, uchar* mask, size_t mask_step); + +#undef cv_hal_minMaxIdxMaskStep +#define cv_hal_minMaxIdxMaskStep ipp_hal_minMaxIdxMaskStep + #define IPP_DISABLE_NORM_8U 1 // accuracy difference in perf test sanity check int ipp_hal_norm(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, diff --git a/3rdparty/ipphal/src/minmax_ipp.cpp b/3rdparty/ipphal/src/minmax_ipp.cpp new file mode 100644 index 0000000000..a87d5825e9 --- /dev/null +++ b/3rdparty/ipphal/src/minmax_ipp.cpp @@ -0,0 +1,252 @@ +#include "ipp_hal_core.hpp" + +#include +#include + +#define IPP_DISABLE_MINMAXIDX_MANY_ROWS 1 // see Core_MinMaxIdx.rows_overflow test + +static inline IppDataType ippiGetDataType(int depth) +{ + depth = CV_MAT_DEPTH(depth); + return depth == CV_8U ? ipp8u : + depth == CV_8S ? ipp8s : + depth == CV_16U ? ipp16u : + depth == CV_16S ? ipp16s : + depth == CV_32S ? ipp32s : + depth == CV_32F ? ipp32f : + depth == CV_64F ? ipp64f : + (IppDataType)-1; +} + +#if IPP_VERSION_X100 >= 700 + + +static IppStatus ipp_minMaxIndex_wrap(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType, + float* pMinVal, float* pMaxVal, IppiPoint* pMinIndex, IppiPoint* pMaxIndex, const Ipp8u*, int) +{ + switch(dataType) + { + case ipp8u: return CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_8u_C1R, (const Ipp8u*)pSrc, srcStep, size, pMinVal, pMaxVal, pMinIndex, pMaxIndex); + case ipp16u: return CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_16u_C1R, (const Ipp16u*)pSrc, srcStep, size, pMinVal, pMaxVal, pMinIndex, pMaxIndex); + case ipp32f: return CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_32f_C1R, (const Ipp32f*)pSrc, srcStep, size, pMinVal, pMaxVal, pMinIndex, pMaxIndex); + default: return ippStsDataTypeErr; + } +} + +static IppStatus ipp_minMaxIndexMask_wrap(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType, + float* pMinVal, float* pMaxVal, IppiPoint* pMinIndex, IppiPoint* pMaxIndex, const Ipp8u* pMask, int maskStep) +{ + switch(dataType) + { + case ipp8u: return CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_8u_C1MR, (const Ipp8u*)pSrc, srcStep, pMask, maskStep, size, pMinVal, pMaxVal, pMinIndex, pMaxIndex); + case ipp16u: return CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_16u_C1MR, (const Ipp16u*)pSrc, srcStep, pMask, maskStep, size, pMinVal, pMaxVal, pMinIndex, pMaxIndex); + case ipp32f: return CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_32f_C1MR, (const Ipp32f*)pSrc, srcStep, pMask, maskStep, size, pMinVal, pMaxVal, pMinIndex, pMaxIndex); + default: return ippStsDataTypeErr; + } +} + +static IppStatus ipp_minMax_wrap(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType, + float* pMinVal, float* pMaxVal, IppiPoint*, IppiPoint*, const Ipp8u*, int) +{ + IppStatus status; + + switch(dataType) + { +#if IPP_VERSION_X100 > 201701 // wrong min values + case ipp8u: + { + Ipp8u val[2]; + status = CV_INSTRUMENT_FUN_IPP(ippiMinMax_8u_C1R, (const Ipp8u*)pSrc, srcStep, size, &val[0], &val[1]); + *pMinVal = val[0]; + *pMaxVal = val[1]; + return status; + } +#endif + case ipp16u: + { + Ipp16u val[2]; + status = CV_INSTRUMENT_FUN_IPP(ippiMinMax_16u_C1R, (const Ipp16u*)pSrc, srcStep, size, &val[0], &val[1]); + *pMinVal = val[0]; + *pMaxVal = val[1]; + return status; + } + case ipp16s: + { + Ipp16s val[2]; + status = CV_INSTRUMENT_FUN_IPP(ippiMinMax_16s_C1R, (const Ipp16s*)pSrc, srcStep, size, &val[0], &val[1]); + *pMinVal = val[0]; + *pMaxVal = val[1]; + return status; + } + case ipp32f: return CV_INSTRUMENT_FUN_IPP(ippiMinMax_32f_C1R, (const Ipp32f*)pSrc, srcStep, size, pMinVal, pMaxVal); + default: return ipp_minMaxIndex_wrap(pSrc, srcStep, size, dataType, pMinVal, pMaxVal, NULL, NULL, NULL, 0); + } +} + +static IppStatus ipp_minIdx_wrap(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType, + float* pMinVal, float*, IppiPoint* pMinIndex, IppiPoint*, const Ipp8u*, int) +{ + IppStatus status; + + switch(dataType) + { + case ipp8u: + { + Ipp8u val; + status = CV_INSTRUMENT_FUN_IPP(ippiMinIndx_8u_C1R, (const Ipp8u*)pSrc, srcStep, size, &val, &pMinIndex->x, &pMinIndex->y); + *pMinVal = val; + return status; + } + case ipp16u: + { + Ipp16u val; + status = CV_INSTRUMENT_FUN_IPP(ippiMinIndx_16u_C1R, (const Ipp16u*)pSrc, srcStep, size, &val, &pMinIndex->x, &pMinIndex->y); + *pMinVal = val; + return status; + } + case ipp16s: + { + Ipp16s val; + status = CV_INSTRUMENT_FUN_IPP(ippiMinIndx_16s_C1R, (const Ipp16s*)pSrc, srcStep, size, &val, &pMinIndex->x, &pMinIndex->y); + *pMinVal = val; + return status; + } + case ipp32f: return CV_INSTRUMENT_FUN_IPP(ippiMinIndx_32f_C1R, (const Ipp32f*)pSrc, srcStep, size, pMinVal, &pMinIndex->x, &pMinIndex->y); + default: return ipp_minMaxIndex_wrap(pSrc, srcStep, size, dataType, pMinVal, NULL, pMinIndex, NULL, NULL, 0); + } +} + +static IppStatus ipp_maxIdx_wrap(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType, + float*, float* pMaxVal, IppiPoint*, IppiPoint* pMaxIndex, const Ipp8u*, int) +{ + IppStatus status; + + switch(dataType) + { + case ipp8u: + { + Ipp8u val; + status = CV_INSTRUMENT_FUN_IPP(ippiMaxIndx_8u_C1R, (const Ipp8u*)pSrc, srcStep, size, &val, &pMaxIndex->x, &pMaxIndex->y); + *pMaxVal = val; + return status; + } + case ipp16u: + { + Ipp16u val; + status = CV_INSTRUMENT_FUN_IPP(ippiMaxIndx_16u_C1R, (const Ipp16u*)pSrc, srcStep, size, &val, &pMaxIndex->x, &pMaxIndex->y); + *pMaxVal = val; + return status; + } + case ipp16s: + { + Ipp16s val; + status = CV_INSTRUMENT_FUN_IPP(ippiMaxIndx_16s_C1R, (const Ipp16s*)pSrc, srcStep, size, &val, &pMaxIndex->x, &pMaxIndex->y); + *pMaxVal = val; + return status; + } + case ipp32f: return CV_INSTRUMENT_FUN_IPP(ippiMaxIndx_32f_C1R, (const Ipp32f*)pSrc, srcStep, size, pMaxVal, &pMaxIndex->x, &pMaxIndex->y); + default: return ipp_minMaxIndex_wrap(pSrc, srcStep, size, dataType, NULL, pMaxVal, NULL, pMaxIndex, NULL, 0); + } +} + +typedef IppStatus (*IppMinMaxSelector)(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType, + float* pMinVal, float* pMaxVal, IppiPoint* pMinIndex, IppiPoint* pMaxIndex, const Ipp8u* pMask, int maskStep); + + +int ipp_hal_minMaxIdxMaskStep(const uchar* src_data, size_t src_step, int width, int height, int depth, + double* _minVal, double* _maxVal, int* _minIdx, int* _maxIdx, uchar* mask, size_t mask_step) +{ +#if IPP_VERSION_X100 < 201800 + // cv::minMaxIdx problem with NaN input + // Disable 32F processing only + if(depth == CV_32F && cv::ipp::getIppTopFeatures() == ippCPUID_SSE42) + return CV_HAL_ERROR_NOT_IMPLEMENTED; +#endif + +#if IPP_VERSION_X100 < 201801 + // cv::minMaxIdx problem with index positions on AVX + if(mask && _maxIdx && cv::ipp::getIppTopFeatures() != ippCPUID_SSE42) + return CV_HAL_ERROR_NOT_IMPLEMENTED; +#endif + + IppStatus status; + IppDataType dataType = ippiGetDataType(depth); + float minVal = 0; + float maxVal = 0; + IppiPoint minIdx = {-1, -1}; + IppiPoint maxIdx = {-1, -1}; + + float *pMinVal = (_minVal || _minIdx)?&minVal:NULL; + float *pMaxVal = (_maxVal || _maxIdx)?&maxVal:NULL; + IppiPoint *pMinIdx = (_minIdx)?&minIdx:NULL; + IppiPoint *pMaxIdx = (_maxIdx)?&maxIdx:NULL; + + IppMinMaxSelector ippMinMaxFun = ipp_minMaxIndexMask_wrap; + if(!mask) + { + if(_maxVal && _maxIdx && !_minVal && !_minIdx) + ippMinMaxFun = ipp_maxIdx_wrap; + else if(!_maxVal && !_maxIdx && _minVal && _minIdx) + ippMinMaxFun = ipp_minIdx_wrap; + else if(_maxVal && !_maxIdx && _minVal && !_minIdx) + ippMinMaxFun = ipp_minMax_wrap; + else if(!_maxVal && !_maxIdx && !_minVal && !_minIdx) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + else + ippMinMaxFun = ipp_minMaxIndex_wrap; + } + + IppiSize size = { width, height }; +#if defined(_WIN32) && !defined(_WIN64) && IPP_VERSION_X100 == 201900 && IPP_DISABLE_MINMAXIDX_MANY_ROWS + if (size.height > 65536) + return CV_HAL_ERROR_NOT_IMPLEMENTED; // test: Core_MinMaxIdx.rows_overflow +#endif + + status = ippMinMaxFun(src_data, (int)src_step, size, dataType, pMinVal, pMaxVal, pMinIdx, pMaxIdx, (Ipp8u*)mask, (int)mask_step); + if(status < 0) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + if(_minVal) + *_minVal = minVal; + if(_maxVal) + *_maxVal = maxVal; + if(_minIdx) + { +#if IPP_VERSION_X100 < 201801 + // Should be just ippStsNoOperation check, but there is a bug in the function so we need additional checks + if(status == ippStsNoOperation && mask && !pMinIdx->x && !pMinIdx->y) +#else + if(status == ippStsNoOperation) +#endif + { + _minIdx[0] = -1; + _minIdx[1] = -1; + } + else + { + _minIdx[0] = minIdx.y; + _minIdx[1] = minIdx.x; + } + } + if(_maxIdx) + { +#if IPP_VERSION_X100 < 201801 + // Should be just ippStsNoOperation check, but there is a bug in the function so we need additional checks + if(status == ippStsNoOperation && mask && !pMaxIdx->x && !pMaxIdx->y) +#else + if(status == ippStsNoOperation) +#endif + { + _maxIdx[0] = -1; + _maxIdx[1] = -1; + } + else + { + _maxIdx[0] = maxIdx.y; + _maxIdx[1] = maxIdx.x; + } + } + + return CV_HAL_ERROR_OK; +} + +#endif // IPP_VERSION_X100 >= 700 diff --git a/modules/core/src/mean.dispatch.cpp b/modules/core/src/mean.dispatch.cpp index 1e547bd0db..3a38377de9 100644 --- a/modules/core/src/mean.dispatch.cpp +++ b/modules/core/src/mean.dispatch.cpp @@ -7,24 +7,9 @@ #include "opencl_kernels_core.hpp" #include "stat.hpp" -#ifndef OPENCV_IPP_MEAN -#undef HAVE_IPP -#undef CV_IPP_RUN_FAST -#define CV_IPP_RUN_FAST(f, ...) -#undef CV_IPP_RUN -#define CV_IPP_RUN(c, f, ...) -#endif // OPENCV_IPP_MEAN - #include "mean.simd.hpp" #include "mean.simd_declarations.hpp" // defines CV_CPU_DISPATCH_MODES_ALL=AVX2,...,BASELINE based on CMakeLists.txt content -#ifndef OPENCV_IPP_MEAN -#undef HAVE_IPP -#undef CV_IPP_RUN_FAST -#define CV_IPP_RUN_FAST(f, ...) -#undef CV_IPP_RUN -#define CV_IPP_RUN(c, f, ...) -#endif // OPENCV_IPP_MEAN namespace cv { @@ -40,8 +25,6 @@ Scalar mean(InputArray _src, InputArray _mask) CV_Assert( cn <= 4 ); - CV_IPP_RUN(IPP_VERSION_X100 >= 700, ipp_mean(src, mask, s), s) - if (src.isContinuous() && mask.isContinuous()) { CALL_HAL_RET2(meanStdDev, cv_hal_meanStdDev, s, src.data, 0, (int)src.total(), 1, src.type(), diff --git a/modules/core/src/minmax.cpp b/modules/core/src/minmax.cpp index 5c819fcd61..876735d85d 100644 --- a/modules/core/src/minmax.cpp +++ b/modules/core/src/minmax.cpp @@ -10,16 +10,6 @@ #include -#ifndef OPENCV_IPP_MINMAX -#undef HAVE_IPP -#undef CV_IPP_RUN_FAST -#define CV_IPP_RUN_FAST(f, ...) -#undef CV_IPP_RUN -#define CV_IPP_RUN(c, f, ...) -#endif // OPENCV_IPP_MINMAX - -#define IPP_DISABLE_MINMAXIDX_MANY_ROWS 1 // see Core_MinMaxIdx.rows_overflow test - /****************************************************************************************\ * minMaxLoc * \****************************************************************************************/ @@ -1118,306 +1108,6 @@ bool ocl_minMaxIdx( InputArray _src, double* minVal, double* maxVal, int* minLoc #endif -#ifdef HAVE_IPP -static IppStatus ipp_minMaxIndex_wrap(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType, - float* pMinVal, float* pMaxVal, IppiPoint* pMinIndex, IppiPoint* pMaxIndex, const Ipp8u*, int) -{ - switch(dataType) - { - case ipp8u: return CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_8u_C1R, (const Ipp8u*)pSrc, srcStep, size, pMinVal, pMaxVal, pMinIndex, pMaxIndex); - case ipp16u: return CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_16u_C1R, (const Ipp16u*)pSrc, srcStep, size, pMinVal, pMaxVal, pMinIndex, pMaxIndex); - case ipp32f: return CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_32f_C1R, (const Ipp32f*)pSrc, srcStep, size, pMinVal, pMaxVal, pMinIndex, pMaxIndex); - default: return ippStsDataTypeErr; - } -} - -static IppStatus ipp_minMaxIndexMask_wrap(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType, - float* pMinVal, float* pMaxVal, IppiPoint* pMinIndex, IppiPoint* pMaxIndex, const Ipp8u* pMask, int maskStep) -{ - switch(dataType) - { - case ipp8u: return CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_8u_C1MR, (const Ipp8u*)pSrc, srcStep, pMask, maskStep, size, pMinVal, pMaxVal, pMinIndex, pMaxIndex); - case ipp16u: return CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_16u_C1MR, (const Ipp16u*)pSrc, srcStep, pMask, maskStep, size, pMinVal, pMaxVal, pMinIndex, pMaxIndex); - case ipp32f: return CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_32f_C1MR, (const Ipp32f*)pSrc, srcStep, pMask, maskStep, size, pMinVal, pMaxVal, pMinIndex, pMaxIndex); - default: return ippStsDataTypeErr; - } -} - -static IppStatus ipp_minMax_wrap(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType, - float* pMinVal, float* pMaxVal, IppiPoint*, IppiPoint*, const Ipp8u*, int) -{ - IppStatus status; - - switch(dataType) - { -#if IPP_VERSION_X100 > 201701 // wrong min values - case ipp8u: - { - Ipp8u val[2]; - status = CV_INSTRUMENT_FUN_IPP(ippiMinMax_8u_C1R, (const Ipp8u*)pSrc, srcStep, size, &val[0], &val[1]); - *pMinVal = val[0]; - *pMaxVal = val[1]; - return status; - } -#endif - case ipp16u: - { - Ipp16u val[2]; - status = CV_INSTRUMENT_FUN_IPP(ippiMinMax_16u_C1R, (const Ipp16u*)pSrc, srcStep, size, &val[0], &val[1]); - *pMinVal = val[0]; - *pMaxVal = val[1]; - return status; - } - case ipp16s: - { - Ipp16s val[2]; - status = CV_INSTRUMENT_FUN_IPP(ippiMinMax_16s_C1R, (const Ipp16s*)pSrc, srcStep, size, &val[0], &val[1]); - *pMinVal = val[0]; - *pMaxVal = val[1]; - return status; - } - case ipp32f: return CV_INSTRUMENT_FUN_IPP(ippiMinMax_32f_C1R, (const Ipp32f*)pSrc, srcStep, size, pMinVal, pMaxVal); - default: return ipp_minMaxIndex_wrap(pSrc, srcStep, size, dataType, pMinVal, pMaxVal, NULL, NULL, NULL, 0); - } -} - -static IppStatus ipp_minIdx_wrap(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType, - float* pMinVal, float*, IppiPoint* pMinIndex, IppiPoint*, const Ipp8u*, int) -{ - IppStatus status; - - switch(dataType) - { - case ipp8u: - { - Ipp8u val; - status = CV_INSTRUMENT_FUN_IPP(ippiMinIndx_8u_C1R, (const Ipp8u*)pSrc, srcStep, size, &val, &pMinIndex->x, &pMinIndex->y); - *pMinVal = val; - return status; - } - case ipp16u: - { - Ipp16u val; - status = CV_INSTRUMENT_FUN_IPP(ippiMinIndx_16u_C1R, (const Ipp16u*)pSrc, srcStep, size, &val, &pMinIndex->x, &pMinIndex->y); - *pMinVal = val; - return status; - } - case ipp16s: - { - Ipp16s val; - status = CV_INSTRUMENT_FUN_IPP(ippiMinIndx_16s_C1R, (const Ipp16s*)pSrc, srcStep, size, &val, &pMinIndex->x, &pMinIndex->y); - *pMinVal = val; - return status; - } - case ipp32f: return CV_INSTRUMENT_FUN_IPP(ippiMinIndx_32f_C1R, (const Ipp32f*)pSrc, srcStep, size, pMinVal, &pMinIndex->x, &pMinIndex->y); - default: return ipp_minMaxIndex_wrap(pSrc, srcStep, size, dataType, pMinVal, NULL, pMinIndex, NULL, NULL, 0); - } -} - -static IppStatus ipp_maxIdx_wrap(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType, - float*, float* pMaxVal, IppiPoint*, IppiPoint* pMaxIndex, const Ipp8u*, int) -{ - IppStatus status; - - switch(dataType) - { - case ipp8u: - { - Ipp8u val; - status = CV_INSTRUMENT_FUN_IPP(ippiMaxIndx_8u_C1R, (const Ipp8u*)pSrc, srcStep, size, &val, &pMaxIndex->x, &pMaxIndex->y); - *pMaxVal = val; - return status; - } - case ipp16u: - { - Ipp16u val; - status = CV_INSTRUMENT_FUN_IPP(ippiMaxIndx_16u_C1R, (const Ipp16u*)pSrc, srcStep, size, &val, &pMaxIndex->x, &pMaxIndex->y); - *pMaxVal = val; - return status; - } - case ipp16s: - { - Ipp16s val; - status = CV_INSTRUMENT_FUN_IPP(ippiMaxIndx_16s_C1R, (const Ipp16s*)pSrc, srcStep, size, &val, &pMaxIndex->x, &pMaxIndex->y); - *pMaxVal = val; - return status; - } - case ipp32f: return CV_INSTRUMENT_FUN_IPP(ippiMaxIndx_32f_C1R, (const Ipp32f*)pSrc, srcStep, size, pMaxVal, &pMaxIndex->x, &pMaxIndex->y); - default: return ipp_minMaxIndex_wrap(pSrc, srcStep, size, dataType, NULL, pMaxVal, NULL, pMaxIndex, NULL, 0); - } -} - -typedef IppStatus (*IppMinMaxSelector)(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType, - float* pMinVal, float* pMaxVal, IppiPoint* pMinIndex, IppiPoint* pMaxIndex, const Ipp8u* pMask, int maskStep); - -static bool ipp_minMaxIdx(Mat &src, double* _minVal, double* _maxVal, int* _minIdx, int* _maxIdx, Mat &mask) -{ -#if IPP_VERSION_X100 >= 700 - CV_INSTRUMENT_REGION_IPP(); - -#if IPP_VERSION_X100 < 201800 - // cv::minMaxIdx problem with NaN input - // Disable 32F processing only - if(src.depth() == CV_32F && cv::ipp::getIppTopFeatures() == ippCPUID_SSE42) - return false; -#endif - -#if IPP_VERSION_X100 < 201801 - // cv::minMaxIdx problem with index positions on AVX - if(!mask.empty() && _maxIdx && cv::ipp::getIppTopFeatures() != ippCPUID_SSE42) - return false; -#endif - - IppStatus status; - IppDataType dataType = ippiGetDataType(src.depth()); - float minVal = 0; - float maxVal = 0; - IppiPoint minIdx = {-1, -1}; - IppiPoint maxIdx = {-1, -1}; - - float *pMinVal = (_minVal || _minIdx)?&minVal:NULL; - float *pMaxVal = (_maxVal || _maxIdx)?&maxVal:NULL; - IppiPoint *pMinIdx = (_minIdx)?&minIdx:NULL; - IppiPoint *pMaxIdx = (_maxIdx)?&maxIdx:NULL; - - IppMinMaxSelector ippMinMaxFun = ipp_minMaxIndexMask_wrap; - if(mask.empty()) - { - if(_maxVal && _maxIdx && !_minVal && !_minIdx) - ippMinMaxFun = ipp_maxIdx_wrap; - else if(!_maxVal && !_maxIdx && _minVal && _minIdx) - ippMinMaxFun = ipp_minIdx_wrap; - else if(_maxVal && !_maxIdx && _minVal && !_minIdx) - ippMinMaxFun = ipp_minMax_wrap; - else if(!_maxVal && !_maxIdx && !_minVal && !_minIdx) - return false; - else - ippMinMaxFun = ipp_minMaxIndex_wrap; - } - - if(src.dims <= 2) - { - IppiSize size = ippiSize(src.size()); -#if defined(_WIN32) && !defined(_WIN64) && IPP_VERSION_X100 == 201900 && IPP_DISABLE_MINMAXIDX_MANY_ROWS - if (size.height > 65536) - return false; // test: Core_MinMaxIdx.rows_overflow -#endif - size.width *= src.channels(); - - status = ippMinMaxFun(src.ptr(), (int)src.step, size, dataType, pMinVal, pMaxVal, pMinIdx, pMaxIdx, (Ipp8u*)mask.ptr(), (int)mask.step); - if(status < 0) - return false; - if(_minVal) - *_minVal = minVal; - if(_maxVal) - *_maxVal = maxVal; - if(_minIdx) - { -#if IPP_VERSION_X100 < 201801 - // Should be just ippStsNoOperation check, but there is a bug in the function so we need additional checks - if(status == ippStsNoOperation && !mask.empty() && !pMinIdx->x && !pMinIdx->y) -#else - if(status == ippStsNoOperation) -#endif - { - _minIdx[0] = -1; - _minIdx[1] = -1; - } - else - { - _minIdx[0] = minIdx.y; - _minIdx[1] = minIdx.x; - } - } - if(_maxIdx) - { -#if IPP_VERSION_X100 < 201801 - // Should be just ippStsNoOperation check, but there is a bug in the function so we need additional checks - if(status == ippStsNoOperation && !mask.empty() && !pMaxIdx->x && !pMaxIdx->y) -#else - if(status == ippStsNoOperation) -#endif - { - _maxIdx[0] = -1; - _maxIdx[1] = -1; - } - else - { - _maxIdx[0] = maxIdx.y; - _maxIdx[1] = maxIdx.x; - } - } - } - else - { - const Mat *arrays[] = {&src, mask.empty()?NULL:&mask, NULL}; - uchar *ptrs[3] = {NULL}; - NAryMatIterator it(arrays, ptrs); - IppiSize size = ippiSize(it.size*src.channels(), 1); - int srcStep = (int)(size.width*src.elemSize1()); - int maskStep = size.width; - size_t idxPos = 1; - size_t minIdxAll = 0; - size_t maxIdxAll = 0; - float minValAll = IPP_MAXABS_32F; - float maxValAll = -IPP_MAXABS_32F; - - for(size_t i = 0; i < it.nplanes; i++, ++it, idxPos += size.width) - { - status = ippMinMaxFun(ptrs[0], srcStep, size, dataType, pMinVal, pMaxVal, pMinIdx, pMaxIdx, ptrs[1], maskStep); - if(status < 0) - return false; -#if IPP_VERSION_X100 > 201701 - // Zero-mask check, function should return ippStsNoOperation warning - if(status == ippStsNoOperation) - continue; -#else - // Crude zero-mask check, waiting for fix in IPP function - if(ptrs[1]) - { - Mat localMask(Size(size.width, 1), CV_8U, ptrs[1], maskStep); - if(!cv::countNonZero(localMask)) - continue; - } -#endif - - if(_minVal && minVal < minValAll) - { - minValAll = minVal; - minIdxAll = idxPos+minIdx.x; - } - if(_maxVal && maxVal > maxValAll) - { - maxValAll = maxVal; - maxIdxAll = idxPos+maxIdx.x; - } - } - if(!src.empty() && mask.empty()) - { - if(minIdxAll == 0) - minIdxAll = 1; - if(maxValAll == 0) - maxValAll = 1; - } - - if(_minVal) - *_minVal = minValAll; - if(_maxVal) - *_maxVal = maxValAll; - if(_minIdx) - ofs2idx(src, minIdxAll, _minIdx); - if(_maxIdx) - ofs2idx(src, maxIdxAll, _maxIdx); - } - - return true; -#else - CV_UNUSED(src); CV_UNUSED(minVal); CV_UNUSED(maxVal); CV_UNUSED(minIdx); CV_UNUSED(maxIdx); CV_UNUSED(mask); - return false; -#endif -} -#endif - } void cv::minMaxIdx(InputArray _src, double* minVal, @@ -1467,8 +1157,6 @@ void cv::minMaxIdx(InputArray _src, double* minVal, } } - CV_IPP_RUN_FAST(ipp_minMaxIdx(src, minVal, maxVal, minIdx, maxIdx, mask)) - MinMaxIdxFunc func = getMinmaxTab(depth); CV_Assert( func != 0 );