diff --git a/hal/ipp/include/ipp_hal_imgproc.hpp b/hal/ipp/include/ipp_hal_imgproc.hpp index f3d5723bc1..4ab985c6e6 100644 --- a/hal/ipp/include/ipp_hal_imgproc.hpp +++ b/hal/ipp/include/ipp_hal_imgproc.hpp @@ -17,11 +17,15 @@ int ipp_hal_warpAffine(int src_type, const uchar *src_data, size_t src_step, int #define cv_hal_warpAffine ipp_hal_warpAffine #endif +#if IPP_VERSION_X100 >= 202600 + int ipp_hal_warpPerspective(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[9], int interpolation, int borderType, const double borderValue[4]); #undef cv_hal_warpPerspective #define cv_hal_warpPerspective ipp_hal_warpPerspective +#endif // IPP_VERSION_X100 >= 202600 + 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/warp_ipp.cpp b/hal/ipp/src/warp_ipp.cpp index fb059a82ea..7736b884fb 100644 --- a/hal/ipp/src/warp_ipp.cpp +++ b/hal/ipp/src/warp_ipp.cpp @@ -8,153 +8,13 @@ #include #include "precomp_ipp.hpp" +#include // Uncomment to enforce IPP calls for all supported by IPP configurations // #define IPP_CALLS_ENFORCED -#define CV_IPP_SAFE_CALL(pFunc, pFlag, ...) if (pFunc(__VA_ARGS__) != ippStsNoErr) {*pFlag = false; return;} #define CV_TYPE(src_type) (src_type & (CV_DEPTH_MAX - 1)) -#ifdef HAVE_IPP_IW -// Warp affine section - -#include "iw++/iw.hpp" - -class ipp_warpAffineParallel: public cv::ParallelLoopBody -{ -public: - ipp_warpAffineParallel(::ipp::IwiImage &src, ::ipp::IwiImage &dst, IppiInterpolationType _inter, double (&_coeffs)[2][3], ::ipp::IwiBorderType _borderType, IwTransDirection _iwTransDirection, bool *_ok):m_src(src), m_dst(dst) - { - ok = _ok; - - inter = _inter; - borderType = _borderType; - iwTransDirection = _iwTransDirection; - - for( int i = 0; i < 2; i++ ) - for( int j = 0; j < 3; j++ ) - coeffs[i][j] = _coeffs[i][j]; - - *ok = true; - } - ~ipp_warpAffineParallel() {} - - virtual void operator() (const cv::Range& range) const CV_OVERRIDE - { - //CV_INSTRUMENT_REGION_IPP(); - if(*ok == false) - return; - - try - { - ::ipp::IwiTile tile = ::ipp::IwiRoi(0, range.start, m_dst.m_size.width, range.end - range.start); - CV_INSTRUMENT_FUN_IPP(::ipp::iwiWarpAffine, m_src, m_dst, coeffs, iwTransDirection, inter, ::ipp::IwiWarpAffineParams(), borderType, tile); - } - catch(const ::ipp::IwException &) - { - *ok = false; - return; - } - CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT); - } -private: - ::ipp::IwiImage &m_src; - ::ipp::IwiImage &m_dst; - - IppiInterpolationType inter; - double coeffs[2][3]; - ::ipp::IwiBorderType borderType; - IwTransDirection iwTransDirection; - - bool *ok; - const ipp_warpAffineParallel& operator= (const ipp_warpAffineParallel&); -}; - -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]) -{ - CV_HAL_CHECK_USE_IPP(); - //CV_INSTRUMENT_REGION_IPP(); - - IppiInterpolationType ippInter = ippiGetInterpolation(interpolation); - if((int)ippInter < 0 || interpolation > 2) - return CV_HAL_ERROR_NOT_IMPLEMENTED; - -#if defined(IPP_CALLS_ENFORCED) - /* C1 C2 C3 C4 */ - char impl[CV_DEPTH_MAX][4][3]={{{1, 1, 0}, {0, 0, 0}, {1, 1, 0}, {1, 1, 0}}, //8U - {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, //8S - {{1, 1, 0}, {0, 0, 0}, {1, 1, 0}, {1, 1, 0}}, //16U - {{1, 1, 0}, {0, 0, 0}, {1, 1, 0}, {1, 1, 0}}, //16S - {{1, 1, 0}, {0, 0, 0}, {1, 1, 0}, {1, 1, 0}}, //32S - {{1, 1, 0}, {0, 0, 0}, {1, 1, 0}, {1, 1, 0}}, //32F - {{1, 1, 0}, {0, 0, 0}, {1, 1, 0}, {1, 1, 0}}}; //64F -#else // IPP_CALLS_ENFORCED is not defined, results are strictly aligned to OpenCV implementation - /* C1 C2 C3 C4 */ - char impl[CV_DEPTH_MAX][4][3]={{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, //8U - {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, //8S - {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {1, 0, 0}}, //16U - {{1, 0, 0}, {0, 0, 0}, {1, 0, 0}, {1, 0, 0}}, //16S - {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, //32S - {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, //32F - {{1, 0, 0}, {0, 0, 0}, {1, 0, 0}, {1, 0, 0}}}; //64F -#endif - - if(impl[CV_TYPE(src_type)][CV_MAT_CN(src_type)-1][interpolation] == 0) - { - return CV_HAL_ERROR_NOT_IMPLEMENTED; - } - - // Acquire data and begin processing - try - { - ::ipp::IwiImage iwSrc; - iwSrc.Init({src_width, src_height}, ippiGetDataType(src_type), CV_MAT_CN(src_type), NULL, src_data, IwSize(src_step)); - ::ipp::IwiImage iwDst({dst_width, dst_height}, ippiGetDataType(src_type), CV_MAT_CN(src_type), NULL, dst_data, dst_step); - ::ipp::IwiBorderType ippBorder(ippiGetBorderType(borderType), {borderValue[0], borderValue[1], borderValue[2], borderValue[3]}); - IwTransDirection iwTransDirection = iwTransInverse; - - if((int)ippBorder == -1) - return CV_HAL_ERROR_NOT_IMPLEMENTED; - - double coeffs[2][3]; - for( int i = 0; i < 2; i++ ) - for( int j = 0; j < 3; j++ ) - coeffs[i][j] = M[i*3 + j]; - - int min_payload = 1 << 16; // 64KB shall be minimal per thread to maximize scalability for warping functions - const int threads = ippiSuggestRowThreadsNum(iwDst, min_payload); - - if (threads > 1) - { - bool ok = true; - cv::Range range(0, (int)iwDst.m_size.height); - ipp_warpAffineParallel invoker(iwSrc, iwDst, ippInter, coeffs, ippBorder, iwTransDirection, &ok); - if(!ok) - return CV_HAL_ERROR_NOT_IMPLEMENTED; - - parallel_for_(range, invoker, threads); - - if(!ok) - return CV_HAL_ERROR_NOT_IMPLEMENTED; - } - else - { - CV_INSTRUMENT_FUN_IPP(::ipp::iwiWarpAffine, iwSrc, iwDst, coeffs, iwTransDirection, ippInter, ::ipp::IwiWarpAffineParams(), ippBorder); - } - } - catch (const ::ipp::IwException &) - { - return CV_HAL_ERROR_NOT_IMPLEMENTED; - } - - return CV_HAL_ERROR_OK; -} - -#endif // HAVE_IPP_IW - -// End of Warp affine section - typedef IppStatus (CV_STDCALL* ippiSetFunc)(const void*, void *, int, IppiSize); template @@ -214,168 +74,143 @@ static bool IPPSet(const double value[4], void *dataPointer, int step, IppiSize return false; } -// Warp perspective section +#ifdef HAVE_IPP_IW -typedef IppStatus (CV_STDCALL* ippiWarpPerspectiveFunc)(const Ipp8u*, int, Ipp8u*, int,IppiPoint, IppiSize, const IppiWarpSpec*,Ipp8u*); -typedef IppStatus (CV_STDCALL* ippiWarpPerspectiveInitFunc)(IppiSize, IppiRect, IppiSize, IppDataType,const double [3][3], IppiWarpDirection, int, IppiBorderType, const Ipp64f *, int, IppiWarpSpec*); +#include "iw++/iw.hpp" -class IPPWarpPerspectiveInvoker : - public cv::ParallelLoopBody +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]) { - // Mem object ot simplify IPP memory lifetime control - struct IPPWarpPerspectiveMem + //CV_INSTRUMENT_REGION_IPP(); + + IppiInterpolationType ippInter = ippiGetInterpolation(interpolation); + if((int)ippInter < 0 || interpolation > 2) + return CV_HAL_ERROR_NOT_IMPLEMENTED; + +#if defined(IPP_CALLS_ENFORCED) + /* C1 C2 C3 C4 */ + char impl[CV_DEPTH_MAX][4][3]={{{1, 1, 0}, {0, 0, 0}, {1, 1, 0}, {1, 1, 0}}, //8U + {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, //8S + {{1, 1, 0}, {0, 0, 0}, {1, 1, 0}, {1, 1, 0}}, //16U + {{1, 1, 0}, {0, 0, 0}, {1, 1, 0}, {1, 1, 0}}, //16S + {{1, 1, 0}, {0, 0, 0}, {1, 1, 0}, {1, 1, 0}}, //32S + {{1, 1, 0}, {0, 0, 0}, {1, 1, 0}, {1, 1, 0}}, //32F + {{1, 1, 0}, {0, 0, 0}, {1, 1, 0}, {1, 1, 0}}}; //64F +#else // IPP_CALLS_ENFORCED is not defined, results are strictly aligned to OpenCV implementation + /* C1 C2 C3 C4 */ + char impl[CV_DEPTH_MAX][4][3]={{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, //8U + {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, //8S + {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {1, 0, 0}}, //16U + {{1, 0, 0}, {0, 0, 0}, {1, 0, 0}, {1, 0, 0}}, //16S + {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, //32S + {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, //32F + {{1, 0, 0}, {0, 0, 0}, {1, 0, 0}, {1, 0, 0}}}; //64F +#endif + + if(impl[CV_TYPE(src_type)][CV_MAT_CN(src_type)-1][interpolation] == 0) { - IppiWarpSpec* pSpec = nullptr; - Ipp8u* pBuffer = nullptr; - - IPPWarpPerspectiveMem() = default; - IPPWarpPerspectiveMem (const IPPWarpPerspectiveMem&) = delete; - IPPWarpPerspectiveMem& operator= (const IPPWarpPerspectiveMem&) = delete; - - void AllocateSpec(int size) - { - pSpec = (IppiWarpSpec*)ippMalloc_L(size); - } - - void AllocateBuffer(int size) - { - pBuffer = (Ipp8u*)ippMalloc_L(size); - } - - ~IPPWarpPerspectiveMem() - { - if (nullptr != pSpec) ippFree(pSpec); - if (nullptr != pBuffer) ippFree(pBuffer); - } - }; -public: - IPPWarpPerspectiveInvoker(int _src_type, cv::Mat &_src, size_t _src_step, cv::Mat &_dst, size_t _dst_step, IppiInterpolationType _interpolation, - double (&_coeffs)[3][3], int &_borderType, const double _borderValue[4], ippiWarpPerspectiveFunc _func, ippiWarpPerspectiveInitFunc _initFunc, - bool *_ok) : - ParallelLoopBody(), src_type(_src_type), src(_src), src_step(_src_step), dst(_dst), dst_step(_dst_step), inter(_interpolation), coeffs(_coeffs), - borderType(_borderType), func(_func), initFunc(_initFunc), ok(_ok) - { - memcpy(this->borderValue, _borderValue, sizeof(this->borderValue)); - *ok = true; + return CV_HAL_ERROR_NOT_IMPLEMENTED; } - virtual void operator() (const cv::Range& range) const CV_OVERRIDE + // Acquire data and begin processing + double coeffs[2][3]; + for( int i = 0; i < 2; i++ ) + for( int j = 0; j < 3; j++ ) + coeffs[i][j] = M[i*3 + j]; + + try { - //CV_INSTRUMENT_REGION_IPP(); - if (*ok == false) - return; + std::atomic_bool ok{true}; + cv::Range cv_range(0, dst_height); + ::ipp::IwiImage iwSrc; + iwSrc.Init(IwiSize{src_width, src_height}, ippiGetDataType(src_type), CV_MAT_CN(src_type), IwiBorderSize(), src_data, IwSize(src_step)); + ::ipp::IwiImage iwDst(IwiSize{dst_width, dst_height}, ippiGetDataType(src_type), CV_MAT_CN(src_type), IwiBorderSize(), dst_data, IwSize(dst_step)); + ::ipp::IwiBorderType ippBorder(ippiGetBorderType(borderType), {borderValue, 4}); + // OpenCV inverts the affine matrix before calling the HAL (lines 2401-2411 of imgwarp.cpp), so the HAL receives the inverse transform. + IwTransDirection iwTransDirection = iwTransInverse; - IPPWarpPerspectiveMem mem; - - int specSize = 0, initSize = 0, bufSize = 0; - - IppiWarpDirection direction = ippWarpBackward; //fixed for IPP - const Ipp32u numChannels = CV_MAT_CN(src_type); - - IppiSize srcsize = {src.cols, src.rows}; - IppiSize dstsize = {dst.cols, dst.rows}; - IppiRect srcroi = {0, 0, src.cols, src.rows}; - - /* Spec and init buffer sizes */ - CV_IPP_SAFE_CALL(ippiWarpPerspectiveGetSize, ok, srcsize, srcroi, dstsize, ippiGetDataType(src_type), coeffs, inter, ippWarpBackward, ippiGetBorderType(borderType), &specSize, &initSize); - - mem.AllocateSpec(specSize); - - CV_IPP_SAFE_CALL(initFunc, ok, srcsize, srcroi, dstsize, ippiGetDataType(src_type), coeffs, direction, numChannels, ippiGetBorderType(borderType), - borderValue, 0, mem.pSpec); - - CV_IPP_SAFE_CALL(ippiWarpGetBufferSize, ok, mem.pSpec, dstsize, &bufSize); - - mem.AllocateBuffer(bufSize); - - IppiPoint dstRoiOffset = {0, range.start}; - IppiSize dstRoiSize = {dst.cols, range.size()}; - auto* pDst = dst.ptr(range.start); - if (borderType == cv::BorderTypes::BORDER_CONSTANT && - !IPPSet(borderValue, pDst, (int)dst_step, dstRoiSize, src.channels(), src.depth())) + if ((int)ippBorder == -1) { - *ok = false; - return; + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + // The lambda function is used to invoke IPP warping function in parallel for different image stripes. + // The function is exception safe and sets the 'ok' flag to false if any exception occurs during processing. + // The 'ok' flag is checked before and after parallel processing to determine if the operation was successful or + // if it should fall back to a non-IPP implementation. + auto IPPWarpAffineInvokerLambda = [&iwSrc, &iwDst, dst_width, ippInter, &coeffs, ippBorder, iwTransDirection, &ok](const cv::Range& range) + { + //CV_INSTRUMENT_REGION_IPP(); + if (!ok.load(std::memory_order_relaxed)) + { + return; + } + + try + { + ::ipp::IwiTile tile = ::ipp::IwiRoi(0, range.start, dst_width, range.end - range.start); + CV_INSTRUMENT_FUN_IPP(::ipp::iwiWarpAffine, iwSrc, iwDst, coeffs, iwTransDirection, ippInter, ::ipp::IwiWarpAffineParams(), ippBorder, tile); + } + catch (const ::ipp::IwException &) + { + ok.store(false, std::memory_order_relaxed); + return; + } + CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT); + }; + + int min_payload = 1 << 16; // 64KB shall be minimal per thread to maximize scalability for warping functions + const int num_threads = ippiSuggestRowThreadsNum(iwDst, min_payload); + + if (num_threads > 1) + { + parallel_for_(cv_range, IPPWarpAffineInvokerLambda, num_threads); + } + else + { + CV_INSTRUMENT_FUN_IPP(::ipp::iwiWarpAffine, iwSrc, iwDst, coeffs, iwTransDirection, ippInter, ::ipp::IwiWarpAffineParams(), ippBorder); } - if (ippStsNoErr != CV_INSTRUMENT_FUN_IPP(func, src.ptr(), (int)src_step, pDst, (int)dst_step, dstRoiOffset, dstRoiSize, mem.pSpec, mem.pBuffer)) + if (!ok) { - *ok = false; - return; + return CV_HAL_ERROR_NOT_IMPLEMENTED; } - - CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT); } -private: - int src_type; - cv::Mat &src; - size_t src_step; - cv::Mat &dst; - size_t dst_step; - IppiInterpolationType inter; - double (&coeffs)[3][3]; - int borderType; - double borderValue[4]; - ippiWarpPerspectiveFunc func; - ippiWarpPerspectiveInitFunc initFunc; - bool *ok; - const IPPWarpPerspectiveInvoker& operator= (const IPPWarpPerspectiveInvoker&); -}; + catch (const ::ipp::IwException &) + { + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + return CV_HAL_ERROR_OK; +} + +#if IPP_VERSION_X100 >= 202600 int ipp_hal_warpPerspective(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[9], int interpolation, int borderType, const double borderValue[4]) { - CV_HAL_CHECK_USE_IPP(); //CV_INSTRUMENT_REGION_IPP(); + IppiInterpolationType ippInter = ippiGetInterpolation(interpolation); + if (src_height <= 1 || src_width <= 1) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } - ippiWarpPerspectiveFunc ippFunc = nullptr; - ippiWarpPerspectiveInitFunc ippInitFunc = nullptr; + int mode = + interpolation == cv::InterpolationFlags::INTER_NEAREST ? IPPI_INTER_NN : + interpolation == cv::InterpolationFlags::INTER_LINEAR ? IPPI_INTER_LINEAR : 0; - if (interpolation == cv::InterpolationFlags::INTER_NEAREST) - { - ippInitFunc = ippiWarpPerspectiveNearestInit; - ippFunc = - src_type == CV_8UC1 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveNearest_8u_C1R : - src_type == CV_8UC3 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveNearest_8u_C3R : - src_type == CV_8UC4 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveNearest_8u_C4R : - src_type == CV_16UC1 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveNearest_16u_C1R : - src_type == CV_16UC3 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveNearest_16u_C3R : - src_type == CV_16UC4 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveNearest_16u_C4R : - src_type == CV_16SC1 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveNearest_16s_C1R : - src_type == CV_16SC3 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveNearest_16s_C3R : - src_type == CV_16SC4 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveNearest_16s_C4R : - src_type == CV_32FC1 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveNearest_32f_C1R : - src_type == CV_32FC3 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveNearest_32f_C3R : - src_type == CV_32FC4 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveNearest_32f_C4R : nullptr; - } - else if (interpolation == cv::InterpolationFlags::INTER_LINEAR) - { - ippInitFunc = ippiWarpPerspectiveLinearInit; - ippFunc = - src_type == CV_8UC1 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveLinear_8u_C1R : - src_type == CV_8UC3 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveLinear_8u_C3R : - src_type == CV_8UC4 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveLinear_8u_C4R : - src_type == CV_16UC1 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveLinear_16u_C1R : - src_type == CV_16UC3 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveLinear_16u_C3R : - src_type == CV_16UC4 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveLinear_16u_C4R : - src_type == CV_16SC1 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveLinear_16s_C1R : - src_type == CV_16SC3 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveLinear_16s_C3R : - src_type == CV_16SC4 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveLinear_16s_C4R : - src_type == CV_32FC1 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveLinear_32f_C1R : - src_type == CV_32FC3 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveLinear_32f_C3R : - src_type == CV_32FC4 ? (ippiWarpPerspectiveFunc)ippiWarpPerspectiveLinear_32f_C4R : nullptr; - } - else + if (mode == 0) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } - if (ippFunc == nullptr) + // Unsupported source type + if (src_type != CV_8UC1 && src_type != CV_8UC3 && src_type != CV_8UC4 && + src_type != CV_16UC1 && src_type != CV_16UC3 && src_type != CV_16UC4 && + src_type != CV_16SC1 && src_type != CV_16SC3 && src_type != CV_16SC4 && + src_type != CV_32FC1 && src_type != CV_32FC3 && src_type != CV_32FC4) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } @@ -396,46 +231,90 @@ int ipp_hal_warpPerspective(int src_type, const uchar *src_data, size_t src_step {{0, 0}, {0, 0}, {0, 1}, {0, 1}}, //16U {{1, 1}, {0, 0}, {1, 1}, {1, 1}}, //16S {{1, 1}, {0, 0}, {1, 0}, {1, 1}}, //32S - {{0, 0}, {0, 0}, {0, 0}, {1, 0}}, //32F + {{1, 0}, {0, 0}, {0, 0}, {1, 0}}, //32F {{0, 0}, {0, 0}, {0, 0}, {0, 0}}}; //64F #endif - const char type_size[CV_DEPTH_MAX] = {1,1,2,2,4,4,8}; - if(impl[CV_TYPE(src_type)][CV_MAT_CN(src_type)-1][interpolation] == 0) + if (impl[CV_TYPE(src_type)][CV_MAT_CN(src_type)-1][interpolation] == 0) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } + + // Acquire data and begin processing double coeffs[3][3]; for( int i = 0; i < 3; i++ ) for( int j = 0; j < 3; j++ ) coeffs[i][j] = M[i*3 + j]; - bool ok = true; - cv::Range range(0, dst_height); - cv::Mat src(cv::Size(src_width, src_height), src_type, const_cast(src_data), src_step); - cv::Mat dst(cv::Size(dst_width, dst_height), src_type, dst_data, dst_step); - IppiInterpolationType ippInter = ippiGetInterpolation(interpolation); - - int min_payload = 1 << 16; // 64KB shall be minimal per thread to maximize scalability for warping functions - int num_threads = ippiSuggestRowThreadsNum(dst_width, dst_height, type_size[CV_TYPE(src_type)]*CV_MAT_CN(src_type), min_payload); - - IPPWarpPerspectiveInvoker invoker(src_type, src, src_step, dst, dst_step, ippInter, coeffs, borderType, borderValue, ippFunc, ippInitFunc, &ok); - - (num_threads > 1) ? parallel_for_(range, invoker, num_threads) : invoker(range); - - if (ok) + try { - CV_IMPL_ADD(CV_IMPL_IPP | CV_IMPL_MT); - return CV_HAL_ERROR_OK; + std::atomic_bool ok{true}; + cv::Range cv_range(0, dst_height); + ::ipp::IwiImage iwSrc; // src_data is const pointer. So, we need to call an init function + iwSrc.Init(IwiSize{src_width, src_height}, ippiGetDataType(src_type), CV_MAT_CN(src_type), IwiBorderSize(), src_data, IwSize(src_step)); + ::ipp::IwiImage iwDst(IwiSize{dst_width, dst_height}, ippiGetDataType(src_type), CV_MAT_CN(src_type), IwiBorderSize(), dst_data, IwSize(dst_step)); + ::ipp::IwiBorderType ippBorder(ippiGetBorderType(borderType), {borderValue, 4}); + IwTransDirection iwTransDirection = iwTransInverse; //fixed for IPP + if ((int)ippBorder == -1) + { + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + // The lambda function is used to invoke IPP warping function in parallel for different image stripes. + // The function is exception safe and sets the 'ok' flag to false if any exception occurs during processing. + // The 'ok' flag is checked before and after parallel processing to determine + // if the operation was successful or if it should fall back to a non-IPP implementation. + auto IPPWarpPerspectiveInvokerLambda = [&iwSrc, &iwDst, dst_width, ippInter, &coeffs, ippBorder, iwTransDirection, &ok](const cv::Range& range) + { + //CV_INSTRUMENT_REGION_IPP(); + if (!ok.load(std::memory_order_relaxed)) + { + return; + } + + try + { + ::ipp::IwiTile tile = ::ipp::IwiRoi(0, range.start, dst_width, range.end - range.start); + CV_INSTRUMENT_FUN_IPP(::ipp::iwiWarpPerspective, iwSrc, iwDst, ippRectInfinite, coeffs, iwTransDirection, ippInter, ::ipp::IwiWarpPerspectiveParams(), ippBorder, tile); + } + catch (const ::ipp::IwException &) + { + ok.store(false, std::memory_order_relaxed); + return; + } + CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT); + }; + + int min_payload = 1 << 16; // 64KB shall be minimal per thread to maximize scalability for warping functions + const char type_size[CV_DEPTH_MAX] = {1,1,2,2,4,4,8}; + const int num_threads = ippiSuggestRowThreadsNum(dst_width, dst_height, type_size[CV_TYPE(src_type)]*CV_MAT_CN(src_type), min_payload); + + if (num_threads > 1) + { + parallel_for_(cv_range, IPPWarpPerspectiveInvokerLambda, num_threads); + } + else + { + CV_INSTRUMENT_FUN_IPP(::ipp::iwiWarpPerspective, iwSrc, iwDst, ippRectInfinite, coeffs, iwTransDirection, ippInter, ::ipp::IwiWarpPerspectiveParams(), ippBorder); + } + + if (!ok) + { + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + } + catch (const ::ipp::IwException &) + { + return CV_HAL_ERROR_NOT_IMPLEMENTED; } - return CV_HAL_ERROR_NOT_IMPLEMENTED; + return CV_HAL_ERROR_OK; } +#endif // IPP_VERSION_X100 >= 202600 -// End of Warp perspective section +#endif // HAVE_IPP_IW // Remap section - typedef IppStatus(CV_STDCALL *ippiRemap)(const void *pSrc, IppiSize srcSize, int srcStep, IppiRect srcRoi, const Ipp32f *pxMap, int xMapStep, const Ipp32f *pyMap, int yMapStep, void *pDst, int dstStep, IppiSize dstRoiSize, int interpolation); @@ -445,20 +324,18 @@ class IPPRemapInvoker : public cv::ParallelLoopBody public: IPPRemapInvoker(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, float *_mapx, size_t _mapx_step, float *_mapy, - size_t _mapy_step, ippiRemap _ippFunc, int _ippInterpolation, int _borderType, const double _borderValue[4], bool *_ok) : - ParallelLoopBody(), + size_t _mapy_step, ippiRemap _ippFunc, int _ippInterpolation, int _borderType, const double _borderValue[4], std::atomic_bool *_ok) : src_type(_src_type), src(_src_data), src_step(_src_step), src_width(_src_width), src_height(_src_height), dst(_dst_data), dst_step(_dst_step), dst_width(_dst_width), mapx(_mapx), mapx_step(_mapx_step), mapy(_mapy), mapy_step(_mapy_step), ippFunc(_ippFunc), ippInterpolation(_ippInterpolation), borderType(_borderType), ok(_ok) { memcpy(this->borderValue, _borderValue, sizeof(this->borderValue)); - *ok = true; } virtual void operator()(const cv::Range &range) const { //CV_INSTRUMENT_REGION_IPP(); - if (*ok == false) + if(!ok->load(std::memory_order_relaxed)) return; IppiRect srcRoiRect = {0, 0, src_width, src_height}; @@ -469,7 +346,7 @@ public: if (borderType == cv::BORDER_CONSTANT && !IPPSet(borderValue, dst_roi_data, (int)dst_step, dstRoiSize, cn, depth)) { - *ok = false; + ok->store(false, std::memory_order_relaxed); return; } @@ -477,7 +354,7 @@ public: mapx, (int)mapx_step, mapy, (int)mapy_step, dst_roi_data, (int)dst_step, dstRoiSize, ippInterpolation)) { - *ok = false; + ok->store(false, std::memory_order_relaxed); return; } @@ -499,7 +376,7 @@ private: ippiRemap ippFunc; int ippInterpolation, borderType; double borderValue[4]; - bool *ok; + std::atomic_bool *ok; }; int ipp_hal_remap32f(int src_type, const uchar *src_data, size_t src_step, int src_width, int src_height, @@ -507,7 +384,6 @@ int ipp_hal_remap32f(int src_type, const uchar *src_data, size_t src_step, int s float *mapx, size_t mapx_step, float *mapy, size_t mapy_step, int interpolation, int border_type, const double border_value[4]) { - CV_HAL_CHECK_USE_IPP(); if (!((interpolation == cv::INTER_LINEAR || interpolation == cv::INTER_CUBIC || interpolation == cv::INTER_NEAREST) && (border_type == cv::BORDER_CONSTANT || border_type == cv::BORDER_TRANSPARENT))) { @@ -555,7 +431,7 @@ int ipp_hal_remap32f(int src_type, const uchar *src_data, size_t src_step, int s if (ippFunc) { - bool ok = true; + std::atomic_bool ok{true}; IPPRemapInvoker invoker(src_type, src_data, src_step, src_width, src_height, dst_data, dst_step, dst_width, mapx, mapx_step, mapy, mapy_step, ippFunc, ippInterpolation, border_type, border_value, &ok);