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

rewoked warp perspective and aligned the whole file

This commit is contained in:
Fedorov, Andrey
2026-05-19 09:33:41 -07:00
parent 666ad5bfcf
commit c2b89072c4
2 changed files with 184 additions and 304 deletions
+4
View File
@@ -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,
+180 -304
View File
@@ -8,153 +8,13 @@
#include <opencv2/core.hpp>
#include "precomp_ipp.hpp"
#include <atomic>
// 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 <int channels, typename Type>
@@ -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<uchar*>(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);