diff --git a/modules/imgproc/src/morph.cpp b/modules/imgproc/src/morph.cpp index 53d2347ec..fb901b726 100644 --- a/modules/imgproc/src/morph.cpp +++ b/modules/imgproc/src/morph.cpp @@ -1136,11 +1136,151 @@ private: Scalar borderValue; }; +#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) +static bool IPPMorphReplicate(int op, const Mat &src, Mat &dst, const Mat &kernel, const Point &anchor) +{ + int type = src.type(); + const Mat* _src = &src; + Mat temp; + if( src.data == dst.data ) + { + src.copyTo(temp); + _src = &temp; + } + //DEPRECATED. Allocates and initializes morphology state structure for erosion or dilation operation. + typedef IppStatus (CV_STDCALL* ippiMorphologyInitAllocFunc)(int, const void*, IppiSize, IppiPoint, IppiMorphState **); + ippiMorphologyInitAllocFunc ippInitAllocFunc = + type == CV_8UC1 ? (ippiMorphologyInitAllocFunc)ippiMorphologyInitAlloc_8u_C1R : + type == CV_8UC3 ? (ippiMorphologyInitAllocFunc)ippiMorphologyInitAlloc_8u_C3R : + type == CV_8UC4 ? (ippiMorphologyInitAllocFunc)ippiMorphologyInitAlloc_8u_C4R : + type == CV_32FC1 ? (ippiMorphologyInitAllocFunc)ippiMorphologyInitAlloc_32f_C1R : + type == CV_32FC3 ? (ippiMorphologyInitAllocFunc)ippiMorphologyInitAlloc_32f_C3R : + type == CV_32FC4 ? (ippiMorphologyInitAllocFunc)ippiMorphologyInitAlloc_32f_C4R : + 0; + typedef IppStatus (CV_STDCALL* ippiMorphologyBorderReplicateFunc)(const void*, int, void *, int, IppiSize, IppiBorderType, IppiMorphState *); + ippiMorphologyBorderReplicateFunc ippFunc = 0; + switch( op ) + { + case MORPH_DILATE: + { + ippFunc = + type == CV_8UC1 ? (ippiMorphologyBorderReplicateFunc)ippiDilateBorderReplicate_8u_C1R : + type == CV_8UC3 ? (ippiMorphologyBorderReplicateFunc)ippiDilateBorderReplicate_8u_C3R : + type == CV_8UC4 ? (ippiMorphologyBorderReplicateFunc)ippiDilateBorderReplicate_8u_C4R : + type == CV_32FC1 ? (ippiMorphologyBorderReplicateFunc)ippiDilateBorderReplicate_32f_C1R : + type == CV_32FC3 ? (ippiMorphologyBorderReplicateFunc)ippiDilateBorderReplicate_32f_C3R : + type == CV_32FC4 ? (ippiMorphologyBorderReplicateFunc)ippiDilateBorderReplicate_32f_C4R : + 0; + break; + } + case MORPH_ERODE: + { + ippFunc = + type == CV_8UC1 ? (ippiMorphologyBorderReplicateFunc)ippiErodeBorderReplicate_8u_C1R : + type == CV_8UC3 ? (ippiMorphologyBorderReplicateFunc)ippiErodeBorderReplicate_8u_C3R : + type == CV_8UC4 ? (ippiMorphologyBorderReplicateFunc)ippiErodeBorderReplicate_8u_C4R : + type == CV_32FC1 ? (ippiMorphologyBorderReplicateFunc)ippiErodeBorderReplicate_32f_C1R : + type == CV_32FC3 ? (ippiMorphologyBorderReplicateFunc)ippiErodeBorderReplicate_32f_C3R : + type == CV_32FC4 ? (ippiMorphologyBorderReplicateFunc)ippiErodeBorderReplicate_32f_C4R : + 0; + break; + } + } + if( ippFunc && ippInitAllocFunc) + { + IppiMorphState* pState; + IppiSize roiSize = {src.cols, src.rows}; + IppiSize kernelSize = {kernel.cols, kernel.rows}; + IppiPoint point = {anchor.x, anchor.y}; + if( ippInitAllocFunc( roiSize.width, kernel.data, kernelSize, point, &pState ) < 0 ) + return false; + bool is_ok = ippFunc( _src->data, _src->step[0], dst.data, dst.step[0], roiSize, ippBorderRepl, pState ) >= 0; + ippiMorphologyFree(pState); + return is_ok; + } + return false; +} + +static bool IPPMorphOp(int op, InputArray _src, OutputArray _dst, + InputArray _kernel, + const Point &anchor, int iterations, + int borderType, const Scalar &borderValue) +{ + Mat src = _src.getMat(), kernel = _kernel.getMat(); + 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) ) + return false; + if( borderType == cv::BORDER_CONSTANT ) + { + int x, y; + for( y = 0; y < kernel.rows; y++ ) + { + if( kernel.at(y, anchor.x) != 0 ) + continue; + for( x = 0; x < kernel.cols; x++ ) + { + if( kernel.at(y,x) != 0 ) + return false; + } + } + for( x = 0; y < kernel.cols; x++ ) + { + if( kernel.at(anchor.y, x) != 0 ) + continue; + for( y = 0; y < kernel.rows; y++ ) + { + if( kernel.at(y,x) != 0 ) + return false; + } + } + + } + 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(); + + if( iterations == 0 || kernel.rows*kernel.cols == 1 ) + { + src.copyTo(dst); + return true; + } + + if( !kernel.data ) + { + kernel = getStructuringElement(MORPH_RECT, Size(1+iterations*2,1+iterations*2)); + normanchor = Point(iterations, iterations); + iterations = 1; + } + else if( iterations > 1 && countNonZero(kernel) == kernel.rows*kernel.cols ) + { + normanchor = Point(normanchor.x*iterations, normanchor.y*iterations); + kernel = getStructuringElement(MORPH_RECT, + Size(ksize.width + (iterations-1)*(ksize.width-1), + ksize.height + (iterations-1)*(ksize.height-1)), + normanchor); + iterations = 1; + } + + return IPPMorphReplicate( op, src, dst, kernel, normanchor ); +} +#endif + static void morphOp( int op, InputArray _src, OutputArray _dst, InputArray _kernel, Point anchor, int iterations, int borderType, const Scalar& borderValue ) { + +#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) + 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);