diff --git a/modules/core/include/opencv2/core/private.hpp b/modules/core/include/opencv2/core/private.hpp index eea2281dc..d0c90e70c 100644 --- a/modules/core/include/opencv2/core/private.hpp +++ b/modules/core/include/opencv2/core/private.hpp @@ -243,6 +243,17 @@ static inline IppiBorderType ippiGetBorderType(int borderTypeNI) borderTypeNI == cv::BORDER_REFLECT ? ippBorderMirrorR : (IppiBorderType)-1; } +static inline IppDataType ippiGetDataType(int 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; +} + #else # define IPP_VERSION_X100 0 #endif diff --git a/modules/imgproc/src/filter.cpp b/modules/imgproc/src/filter.cpp index a6ab7afb7..4837d3b9a 100644 --- a/modules/imgproc/src/filter.cpp +++ b/modules/imgproc/src/filter.cpp @@ -3644,11 +3644,11 @@ cv::Ptr cv::createLinearFilter( int _srcType, int _dstType, void cv::filter2D( InputArray _src, OutputArray _dst, int ddepth, - InputArray _kernel, Point anchor, + InputArray _kernel, Point anchor0, double delta, int borderType ) { CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2, - ocl_filter2D(_src, _dst, ddepth, _kernel, anchor, delta, borderType)) + ocl_filter2D(_src, _dst, ddepth, _kernel, anchor0, delta, borderType)) Mat src = _src.getMat(), kernel = _kernel.getMat(); @@ -3664,7 +3664,73 @@ void cv::filter2D( InputArray _src, OutputArray _dst, int ddepth, _dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) ); Mat dst = _dst.getMat(); - anchor = normalizeAnchor(anchor, kernel.size()); + Point anchor = normalizeAnchor(anchor0, kernel.size()); + +#if IPP_VERSION_X100 > 0 && !defined HAVE_IPP_ICV_ONLY + typedef IppStatus (CV_STDCALL * ippiFilterBorder)(const void * pSrc, int srcStep, void * pDst, int dstStep, IppiSize dstRoiSize, + IppiBorderType border, const void * borderValue, + const IppiFilterBorderSpec* pSpec, Ipp8u* pBuffer); + + int stype = src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype), + ktype = kernel.type(), kdepth = CV_MAT_DEPTH(ktype); + bool isolated = (borderType & BORDER_ISOLATED) != 0; + Point ippAnchor(kernel.cols >> 1, kernel.rows >> 1); + int borderTypeNI = borderType & ~BORDER_ISOLATED; + IppiBorderType ippBorderType = ippiGetBorderType(borderTypeNI); + + if (borderTypeNI == BORDER_CONSTANT || borderTypeNI == BORDER_REPLICATE) + { + ippiFilterBorder ippFunc = + stype == CV_8UC1 ? (ippiFilterBorder)ippiFilterBorder_8u_C1R : + stype == CV_8UC3 ? (ippiFilterBorder)ippiFilterBorder_8u_C3R : + stype == CV_8UC4 ? (ippiFilterBorder)ippiFilterBorder_8u_C4R : + stype == CV_16UC1 ? (ippiFilterBorder)ippiFilterBorder_16u_C1R : + stype == CV_16UC3 ? (ippiFilterBorder)ippiFilterBorder_16u_C3R : + stype == CV_16UC4 ? (ippiFilterBorder)ippiFilterBorder_16u_C4R : + stype == CV_16SC1 ? (ippiFilterBorder)ippiFilterBorder_16s_C1R : + stype == CV_16SC3 ? (ippiFilterBorder)ippiFilterBorder_16s_C3R : + stype == CV_16SC4 ? (ippiFilterBorder)ippiFilterBorder_16s_C4R : + stype == CV_32FC1 ? (ippiFilterBorder)ippiFilterBorder_32f_C1R : + stype == CV_32FC3 ? (ippiFilterBorder)ippiFilterBorder_32f_C3R : + stype == CV_32FC4 ? (ippiFilterBorder)ippiFilterBorder_32f_C4R : 0; + + if (sdepth == ddepth && (ktype == CV_16SC1 || ktype == CV_32FC1) && + ippFunc && (int)ippBorderType >= 0 && (!src.isSubmatrix() || isolated) && + std::fabs(delta - 0) < DBL_EPSILON && ippAnchor == anchor && dst.data != src.data) + { + IppiSize kernelSize = { kernel.cols, kernel.rows }, dstRoiSize = { dst.cols, dst.rows }; + IppDataType dataType = ippiGetDataType(ddepth), kernelType = ippiGetDataType(kdepth); + Ipp32s specSize = 0, bufsize = 0; + IppStatus status = (IppStatus)-1; + + if ((status = ippiFilterBorderGetSize(kernelSize, dstRoiSize, dataType, kernelType, cn, &specSize, &bufsize)) >= 0) + { + IppiFilterBorderSpec * spec = (IppiFilterBorderSpec *)ippMalloc(specSize); + Ipp8u * buffer = ippsMalloc_8u(bufsize); + Ipp32f borderValue[4] = { 0, 0, 0, 0 }; + + Mat reversedKernel; + flip(kernel, reversedKernel, -1); + + if ((kdepth == CV_32F && (status = ippiFilterBorderInit_32f((const Ipp32f *)reversedKernel.data, kernelSize, + dataType, cn, ippRndFinancial, spec)) >= 0 ) || + (kdepth == CV_16S && (status = ippiFilterBorderInit_16s((const Ipp16s *)reversedKernel.data, + kernelSize, 0, dataType, cn, ippRndFinancial, spec)) >= 0)) + { + status = ippFunc(src.data, (int)src.step, dst.data, (int)dst.step, dstRoiSize, + ippBorderType, borderValue, spec, buffer); + } + + ippsFree(buffer); + ippsFree(spec); + } + + if (status >= 0) + return; + setIppErrorStatus(); + } + } +#endif #ifdef HAVE_TEGRA_OPTIMIZATION if( tegra::filter2D(src, dst, kernel, anchor, delta, borderType) )