diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp index e6c189421f..a4fda282dc 100644 --- a/modules/imgproc/src/imgwarp.cpp +++ b/modules/imgproc/src/imgwarp.cpp @@ -50,9 +50,73 @@ #include #include +#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) +static IppStatus sts = ippInit(); +#endif + namespace cv { +#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) + typedef IppStatus (CV_STDCALL* ippiSetFunc)(const void*, void *, int, IppiSize); + typedef IppStatus (CV_STDCALL* ippiWarpPerspectiveBackFunc)(const void*, IppiSize, int, IppiRect, void *, int, IppiRect, double [3][3], int); + typedef IppStatus (CV_STDCALL* ippiWarpAffineBackFunc)(const void*, IppiSize, int, IppiRect, void *, int, IppiRect, double [2][3], int); + typedef IppStatus (CV_STDCALL* ippiResizeSqrPixelFunc)(const void*, IppiSize, int, IppiRect, void*, int, IppiRect, double, double, double, double, int, Ipp8u *); + + template + bool IPPSetSimple(cv::Scalar value, void *dataPointer, int step, IppiSize &size, ippiSetFunc func) + { + Type values[channels]; + for( int i = 0; i < channels; i++ ) + values[i] = (Type)value[i]; + return func(values, dataPointer, step, size) >= 0; + } + + bool IPPSet(const cv::Scalar &value, void *dataPointer, int step, IppiSize &size, int channels, int depth) + { + if( channels == 1 ) + { + switch( depth ) + { + case CV_8U: + return ippiSet_8u_C1R((Ipp8u)value[0], (Ipp8u *)dataPointer, step, size) >= 0; + case CV_16U: + return ippiSet_16u_C1R((Ipp16u)value[0], (Ipp16u *)dataPointer, step, size) >= 0; + case CV_32F: + return ippiSet_32f_C1R((Ipp32f)value[0], (Ipp32f *)dataPointer, step, size) >= 0; + } + } + else + { + if( channels == 3 ) + { + switch( depth ) + { + case CV_8U: + return IPPSetSimple<3, Ipp8u>(value, dataPointer, step, size, (ippiSetFunc)ippiSet_8u_C3R); + case CV_16U: + return IPPSetSimple<3, Ipp16u>(value, dataPointer, step, size, (ippiSetFunc)ippiSet_16u_C3R); + case CV_32F: + return IPPSetSimple<3, Ipp32f>(value, dataPointer, step, size, (ippiSetFunc)ippiSet_32f_C3R); + } + } + else if( channels == 4 ) + { + switch( depth ) + { + case CV_8U: + return IPPSetSimple<4, Ipp8u>(value, dataPointer, step, size, (ippiSetFunc)ippiSet_8u_C4R); + case CV_16U: + return IPPSetSimple<4, Ipp16u>(value, dataPointer, step, size, (ippiSetFunc)ippiSet_16u_C4R); + case CV_32F: + return IPPSetSimple<4, Ipp32f>(value, dataPointer, step, size, (ippiSetFunc)ippiSet_32f_C4R); + } + } + } + return false; + } +#endif + /************** interpolation formulas and tables ***************/ const int INTER_RESIZE_COEF_BITS=11; @@ -1604,6 +1668,45 @@ static int computeResizeAreaTab( int ssize, int dsize, int cn, double scale, Dec return k; } +#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) +class IPPresizeInvoker : + public ParallelLoopBody +{ +public: + IPPresizeInvoker(Mat &_src, Mat &_dst, double &_inv_scale_x, double &_inv_scale_y, int _mode, ippiResizeSqrPixelFunc _func, bool *_ok) : + ParallelLoopBody(), src(_src), dst(_dst), inv_scale_x(_inv_scale_x), inv_scale_y(_inv_scale_y), mode(_mode), func(_func), ok(_ok) + { + *ok = true; + } + + virtual void operator() (const Range& range) const + { + int cn = src.channels(); + IppiRect srcroi = { 0, range.start, src.cols, range.end - range.start }; + int dsty = CV_IMIN(cvRound(range.start * inv_scale_y), dst.rows); + int dstwidth = CV_IMIN(cvRound(src.cols * inv_scale_x), dst.cols); + int dstheight = CV_IMIN(cvRound(range.end * inv_scale_y), dst.rows); + IppiRect dstroi = { 0, dsty, dstwidth, dstheight - dsty }; + int bufsize; + ippiResizeGetBufSize( srcroi, dstroi, cn, mode, &bufsize ); + Ipp8u *buf; + buf = ippsMalloc_8u( bufsize ); + IppStatus sts; + if( func( src.data, ippiSize(src.cols, src.rows), (int)src.step[0], srcroi, dst.data, (int)dst.step[0], dstroi, inv_scale_x, inv_scale_y, 0, 0, mode, buf ) < 0 ) + *ok = false; + ippsFree(buf); + } +private: + Mat &src; + Mat &dst; + double inv_scale_x; + double inv_scale_y; + int mode; + ippiResizeSqrPixelFunc func; + bool *ok; + const IPPresizeInvoker& operator= (const IPPresizeInvoker&); +}; +#endif } @@ -1746,6 +1849,34 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize, double scale_x = 1./inv_scale_x, scale_y = 1./inv_scale_y; int k, sx, sy, dx, dy; +#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) + int mode = interpolation == INTER_LINEAR ? IPPI_INTER_LINEAR : 0; + int type = src.type(); + ippiResizeSqrPixelFunc ippFunc = + type == CV_8UC1 ? (ippiResizeSqrPixelFunc)ippiResizeSqrPixel_8u_C1R : + type == CV_8UC3 ? (ippiResizeSqrPixelFunc)ippiResizeSqrPixel_8u_C3R : + type == CV_8UC4 ? (ippiResizeSqrPixelFunc)ippiResizeSqrPixel_8u_C4R : + type == CV_16UC1 ? (ippiResizeSqrPixelFunc)ippiResizeSqrPixel_16u_C1R : + type == CV_16UC3 ? (ippiResizeSqrPixelFunc)ippiResizeSqrPixel_16u_C3R : + type == CV_16UC4 ? (ippiResizeSqrPixelFunc)ippiResizeSqrPixel_16u_C4R : + type == CV_16SC1 ? (ippiResizeSqrPixelFunc)ippiResizeSqrPixel_16s_C1R : + type == CV_16SC3 ? (ippiResizeSqrPixelFunc)ippiResizeSqrPixel_16s_C3R : + type == CV_16SC4 ? (ippiResizeSqrPixelFunc)ippiResizeSqrPixel_16s_C4R : + type == CV_32FC1 ? (ippiResizeSqrPixelFunc)ippiResizeSqrPixel_32f_C1R : + type == CV_32FC3 ? (ippiResizeSqrPixelFunc)ippiResizeSqrPixel_32f_C3R : + type == CV_32FC4 ? (ippiResizeSqrPixelFunc)ippiResizeSqrPixel_32f_C4R : + 0; + if( ippFunc && mode != 0 ) + { + bool ok; + Range range(0, src.rows); + IPPresizeInvoker invoker(src, dst, inv_scale_x, inv_scale_y, mode, ippFunc, &ok); + parallel_for_(range, invoker, dst.total()/(double)(1<<16)); + if( ok ) + return; + } +#endif + if( interpolation == INTER_NEAREST ) { resizeNN( src, dst, inv_scale_x, inv_scale_y ); @@ -3257,6 +3388,49 @@ private: double *M; }; +#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) +class IPPwarpAffineInvoker : + public ParallelLoopBody +{ +public: + IPPwarpAffineInvoker(Mat &_src, Mat &_dst, double (&_coeffs)[2][3], int &_interpolation, int &_borderType, const Scalar &_borderValue, ippiWarpAffineBackFunc _func, bool *_ok) : + ParallelLoopBody(), src(_src), dst(_dst), mode(_interpolation), coeffs(_coeffs), borderType(_borderType), borderValue(_borderValue), func(_func), ok(_ok) + { + *ok = true; + } + + virtual void operator() (const Range& range) const + { + IppiSize srcsize = { src.cols, src.rows }; + IppiRect srcroi = { 0, 0, src.cols, src.rows }; + IppiRect dstroi = { 0, range.start, dst.cols, range.end - range.start }; + int cnn = src.channels(); + if( borderType == BORDER_CONSTANT ) + { + IppiSize setSize = { dst.cols, range.end - range.start }; + void *dataPointer = dst.data + dst.step[0] * range.start; + if( !IPPSet( borderValue, dataPointer, (int)dst.step[0], setSize, cnn, src.depth() ) ) + { + *ok = false; + return; + } + } + if( func( src.data, srcsize, (int)src.step[0], srcroi, dst.data, (int)dst.step[0], dstroi, coeffs, mode ) < 0) ////Aug 2013: problem in IPP 7.1, 8.0 : sometimes function return ippStsCoeffErr + *ok = false; + } +private: + Mat &src; + Mat &dst; + double (&coeffs)[2][3]; + int mode; + int borderType; + Scalar borderValue; + ippiWarpAffineBackFunc func; + bool *ok; + const IPPwarpAffineInvoker& operator= (const IPPwarpAffineInvoker&); +}; +#endif + } @@ -3303,6 +3477,50 @@ void cv::warpAffine( InputArray _src, OutputArray _dst, const int AB_BITS = MAX(10, (int)INTER_BITS); const int AB_SCALE = 1 << AB_BITS; +#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) + int depth = src.depth(); + int channels = src.channels(); + if( ( depth == CV_8U || depth == CV_16U || depth == CV_32F ) && + ( channels == 1 || channels == 3 || channels == 4 ) && + ( borderType == cv::BORDER_TRANSPARENT || ( borderType == cv::BORDER_CONSTANT ) ) ) + { + int type = src.type(); + ippiWarpAffineBackFunc ippFunc = + type == CV_8UC1 ? (ippiWarpAffineBackFunc)ippiWarpAffineBack_8u_C1R : + type == CV_8UC3 ? (ippiWarpAffineBackFunc)ippiWarpAffineBack_8u_C3R : + type == CV_8UC4 ? (ippiWarpAffineBackFunc)ippiWarpAffineBack_8u_C4R : + type == CV_16UC1 ? (ippiWarpAffineBackFunc)ippiWarpAffineBack_16u_C1R : + type == CV_16UC3 ? (ippiWarpAffineBackFunc)ippiWarpAffineBack_16u_C3R : + type == CV_16UC4 ? (ippiWarpAffineBackFunc)ippiWarpAffineBack_16u_C4R : + type == CV_32FC1 ? (ippiWarpAffineBackFunc)ippiWarpAffineBack_32f_C1R : + type == CV_32FC3 ? (ippiWarpAffineBackFunc)ippiWarpAffineBack_32f_C3R : + type == CV_32FC4 ? (ippiWarpAffineBackFunc)ippiWarpAffineBack_32f_C4R : + 0; + int mode = + flags == INTER_LINEAR ? IPPI_INTER_LINEAR : + flags == INTER_NEAREST ? IPPI_INTER_NN : + flags == INTER_CUBIC ? IPPI_INTER_CUBIC : + 0; + if( mode && ippFunc ) + { + double coeffs[2][3]; + for( int i = 0; i < 2; i++ ) + { + for( int j = 0; j < 3; j++ ) + { + coeffs[i][j] = matM.at(i, j); + } + } + bool ok; + Range range(0, dst.rows); + IPPwarpAffineInvoker invoker(src, dst, coeffs, mode, borderType, borderValue, ippFunc, &ok); + parallel_for_(range, invoker, dst.total()/(double)(1<<16)); + if( ok ) + return; + } + } +#endif + for( x = 0; x < dst.cols; x++ ) { adelta[x] = saturate_cast(M[0]*x*AB_SCALE); @@ -3410,6 +3628,50 @@ private: Scalar borderValue; }; +#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) +class IPPwarpPerspectiveInvoker : + public ParallelLoopBody +{ +public: + IPPwarpPerspectiveInvoker(Mat &_src, Mat &_dst, double (&_coeffs)[3][3], int &_interpolation, int &_borderType, const Scalar &_borderValue, ippiWarpPerspectiveBackFunc _func, bool *_ok) : + ParallelLoopBody(), src(_src), dst(_dst), mode(_interpolation), coeffs(_coeffs), borderType(_borderType), borderValue(_borderValue), func(_func), ok(_ok) + { + *ok = true; + } + + virtual void operator() (const Range& range) const + { + IppiSize srcsize = {src.cols, src.rows}; + IppiRect srcroi = {0, 0, src.cols, src.rows}; + IppiRect dstroi = {0, range.start, dst.cols, range.end - range.start}; + int cnn = src.channels(); + + if( borderType == BORDER_CONSTANT ) + { + IppiSize setSize = {dst.cols, range.end - range.start}; + void *dataPointer = dst.data + dst.step[0] * range.start; + if( !IPPSet( borderValue, dataPointer, (int)dst.step[0], setSize, cnn, src.depth() ) ) + { + *ok = false; + return; + } + } + if( func(src.data, srcsize, (int)src.step[0], srcroi, dst.data, (int)dst.step[0], dstroi, coeffs, mode) < 0) + *ok = false; + } +private: + Mat &src; + Mat &dst; + double (&coeffs)[3][3]; + int mode; + int borderType; + const Scalar borderValue; + ippiWarpPerspectiveBackFunc func; + bool *ok; + const IPPwarpPerspectiveInvoker& operator= (const IPPwarpPerspectiveInvoker&); +}; +#endif + } void cv::warpPerspective( InputArray _src, OutputArray _dst, InputArray _M0, @@ -3440,6 +3702,50 @@ void cv::warpPerspective( InputArray _src, OutputArray _dst, InputArray _M0, if( !(flags & WARP_INVERSE_MAP) ) invert(matM, matM); +#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) + int depth = src.depth(); + int channels = src.channels(); + if( ( depth == CV_8U || depth == CV_16U || depth == CV_32F ) && + ( channels == 1 || channels == 3 || channels == 4 ) && + ( borderType == cv::BORDER_TRANSPARENT || borderType == cv::BORDER_CONSTANT ) ) + { + int type = src.type(); + ippiWarpPerspectiveBackFunc ippFunc = + type == CV_8UC1 ? (ippiWarpPerspectiveBackFunc)ippiWarpPerspectiveBack_8u_C1R : + type == CV_8UC3 ? (ippiWarpPerspectiveBackFunc)ippiWarpPerspectiveBack_8u_C3R : + type == CV_8UC4 ? (ippiWarpPerspectiveBackFunc)ippiWarpPerspectiveBack_8u_C4R : + type == CV_16UC1 ? (ippiWarpPerspectiveBackFunc)ippiWarpPerspectiveBack_16u_C1R : + type == CV_16UC3 ? (ippiWarpPerspectiveBackFunc)ippiWarpPerspectiveBack_16u_C3R : + type == CV_16UC4 ? (ippiWarpPerspectiveBackFunc)ippiWarpPerspectiveBack_16u_C4R : + type == CV_32FC1 ? (ippiWarpPerspectiveBackFunc)ippiWarpPerspectiveBack_32f_C1R : + type == CV_32FC3 ? (ippiWarpPerspectiveBackFunc)ippiWarpPerspectiveBack_32f_C3R : + type == CV_32FC4 ? (ippiWarpPerspectiveBackFunc)ippiWarpPerspectiveBack_32f_C4R : + 0; + int mode = + flags == INTER_LINEAR ? IPPI_INTER_LINEAR : + flags == INTER_NEAREST ? IPPI_INTER_NN : + flags == INTER_CUBIC ? IPPI_INTER_CUBIC : + 0; + if( mode && ippFunc ) + { + double coeffs[3][3]; + for( int i = 0; i < 3; i++ ) + { + for( int j = 0; j < 3; j++ ) + { + coeffs[i][j] = matM.at(i, j); + } + } + bool ok; + Range range(0, dst.rows); + IPPwarpPerspectiveInvoker invoker(src, dst, coeffs, mode, borderType, borderValue, ippFunc, &ok); + parallel_for_(range, invoker, dst.total()/(double)(1<<16)); + if( ok ) + return; + } + } +#endif + Range range(0, dst.rows); warpPerspectiveInvoker invoker(src, dst, M, interpolation, borderType, borderValue); parallel_for_(range, invoker, dst.total()/(double)(1<<16)); diff --git a/modules/imgproc/src/morph.cpp b/modules/imgproc/src/morph.cpp index b8bb7cf381..19636bc963 100644 --- a/modules/imgproc/src/morph.cpp +++ b/modules/imgproc/src/morph.cpp @@ -1213,11 +1213,10 @@ static bool IPPMorphReplicate(int op, const Mat &src, Mat &dst, const Mat &kerne } static bool IPPMorphOp(int op, InputArray _src, OutputArray _dst, - InputArray _kernel, - const Point &anchor, int iterations, + const Mat& _kernel, Point anchor, int iterations, int borderType, const Scalar &borderValue) { - Mat src = _src.getMat(), kernel = _kernel.getMat(); + Mat src = _src.getMat(), kernel = _kernel; if( !( src.depth() == CV_8U || src.depth() == CV_32F ) || ( iterations > 1 ) || !( borderType == cv::BORDER_REPLICATE || (borderType == cv::BORDER_CONSTANT && borderValue == morphologyDefaultBorderValue()) ) || !( op == MORPH_DILATE || op == MORPH_ERODE) ) @@ -1248,9 +1247,6 @@ static bool IPPMorphOp(int op, InputArray _src, OutputArray _dst, } Size ksize = kernel.data ? kernel.size() : Size(3,3); - Point normanchor = normalizeAnchor(anchor, ksize); - - CV_Assert( normanchor.inside(Rect(0, 0, ksize.width, ksize.height)) ); _dst.create( src.size(), src.type() ); Mat dst = _dst.getMat(); @@ -1265,7 +1261,7 @@ static bool IPPMorphOp(int op, InputArray _src, OutputArray _dst, if( !kernel.data ) { ksize = Size(1+iterations*2,1+iterations*2); - normanchor = Point(iterations, iterations); + anchor = Point(iterations, iterations); rectKernel = true; iterations = 1; } @@ -1273,7 +1269,7 @@ static bool IPPMorphOp(int op, InputArray _src, OutputArray _dst, { ksize = Size(ksize.width + (iterations-1)*(ksize.width-1), ksize.height + (iterations-1)*(ksize.height-1)), - normanchor = Point(normanchor.x*iterations, normanchor.y*iterations); + anchor = Point(anchor.x*iterations, anchor.y*iterations); kernel = Mat(); rectKernel = true; iterations = 1; @@ -1283,7 +1279,7 @@ static bool IPPMorphOp(int op, InputArray _src, OutputArray _dst, if( iterations > 1 ) return false; - return IPPMorphReplicate( op, src, dst, kernel, ksize, normanchor, rectKernel ); + return IPPMorphReplicate( op, src, dst, kernel, ksize, anchor, rectKernel ); } #endif @@ -1292,17 +1288,18 @@ static void morphOp( int op, InputArray _src, OutputArray _dst, Point anchor, int iterations, int borderType, const Scalar& borderValue ) { + Mat kernel = _kernel.getMat(); + Size ksize = kernel.data ? kernel.size() : Size(3,3); + anchor = normalizeAnchor(anchor, ksize); + + CV_Assert( anchor.inside(Rect(0, 0, ksize.width, ksize.height)) ); #if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) - if( IPPMorphOp(op, _src, _dst, _kernel, anchor, iterations, borderType, borderValue) ) + if( IPPMorphOp(op, _src, _dst, kernel, anchor, iterations, borderType, borderValue) ) return; #endif - Mat src = _src.getMat(), kernel = _kernel.getMat(); - Size ksize = kernel.data ? kernel.size() : Size(3,3); - anchor = normalizeAnchor(anchor, ksize); - - CV_Assert( anchor.inside(Rect(0, 0, ksize.width, ksize.height)) ); + Mat src = _src.getMat(); _dst.create( src.size(), src.type() ); Mat dst = _dst.getMat();