diff --git a/modules/gpu/include/opencv2/gpu/gpu.hpp b/modules/gpu/include/opencv2/gpu/gpu.hpp index d8dc5bf6ff..e2bb5ded3c 100644 --- a/modules/gpu/include/opencv2/gpu/gpu.hpp +++ b/modules/gpu/include/opencv2/gpu/gpu.hpp @@ -407,10 +407,12 @@ namespace cv //! computes sum of array elements //! supports CV_8UC1, CV_8UC4 types + //! disabled until fix crash CV_EXPORTS Scalar sum(const GpuMat& m); //! finds global minimum and maximum array elements and returns their values //! supports only CV_8UC1 type + //! disabled until fix npp bug CV_EXPORTS void minMax(const GpuMat& src, double* minVal, double* maxVal = 0); //! transforms 8-bit unsigned integers using lookup table: dst(i)=lut(src(i)) @@ -451,8 +453,10 @@ namespace cv CV_EXPORTS void log(const GpuMat& a, GpuMat& b); //! computes magnitude (magnitude(i)) of each (x(i), y(i)) vector + //! supports only CV_32FC1 type CV_EXPORTS void magnitude(const GpuMat& x, const GpuMat& y, GpuMat& magnitude); //! computes magnitude (magnitude(i)) of complex (x(i).re, x(i).im) vector + //! supports only CV_32FC2 type CV_EXPORTS void magnitude(const GpuMat& x, GpuMat& magnitude); ////////////////////////////// Image processing ////////////////////////////// @@ -517,34 +521,169 @@ namespace cv //! supports only CV_32FC1 source type CV_EXPORTS void integral(GpuMat& src, GpuMat& sum, GpuMat& sqsum); + //! applies Canny edge detector and produces the edge map + //! supprots only CV_8UC1 source type + //! disabled until fix crash + CV_EXPORTS void Canny(const GpuMat& image, GpuMat& edges, double threshold1, double threshold2, int apertureSize = 3); + + //////////////////////////////// Filter Engine //////////////////////////////// + + /*! + The Base Class for 1D or Row-wise Filters + + This is the base class for linear or non-linear filters that process 1D data. + In particular, such filters are used for the "horizontal" filtering parts in separable filters. + */ + class CV_EXPORTS BaseRowFilter_GPU + { + public: + BaseRowFilter_GPU(int ksize_, int anchor_) : ksize(ksize_), anchor(anchor_) {} + virtual ~BaseRowFilter_GPU() {} + virtual void operator()(const GpuMat& src, GpuMat& dst) = 0; + int ksize, anchor; + }; + + /*! + The Base Class for Column-wise Filters + + This is the base class for linear or non-linear filters that process columns of 2D arrays. + Such filters are used for the "vertical" filtering parts in separable filters. + */ + class CV_EXPORTS BaseColumnFilter_GPU + { + public: + BaseColumnFilter_GPU(int ksize_, int anchor_) : ksize(ksize_), anchor(anchor_) {} + virtual ~BaseColumnFilter_GPU() {} + virtual void operator()(const GpuMat& src, GpuMat& dst) = 0; + int ksize, anchor; + }; + + /*! + The Base Class for Non-Separable 2D Filters. + + This is the base class for linear or non-linear 2D filters. + */ + class CV_EXPORTS BaseFilter_GPU + { + public: + BaseFilter_GPU(const Size& ksize_, const Point& anchor_) : ksize(ksize_), anchor(anchor_) {} + virtual ~BaseFilter_GPU() {} + virtual void operator()(const GpuMat& src, GpuMat& dst) = 0; + Size ksize; + Point anchor; + }; + + /*! + The Base Class for Filter Engine. + + The class can be used to apply an arbitrary filtering operation to an image. + It contains all the necessary intermediate buffers. + */ + class CV_EXPORTS FilterEngine_GPU + { + public: + virtual ~FilterEngine_GPU() {} + + virtual void apply(const GpuMat& src, GpuMat& dst, Rect roi = Rect(0,0,-1,-1)) = 0; + }; + + //! returns the non-separable filter engine with the specified filter + CV_EXPORTS Ptr createFilter2D_GPU(const Ptr filter2D); + + //! returns the separable filter engine with the specified filters + CV_EXPORTS Ptr createSeparableFilter_GPU(const Ptr& rowFilter, + const Ptr& columnFilter); + + //! returns horizontal 1D box filter + //! supports only CV_8UC1 source type and CV_32FC1 sum type + CV_EXPORTS Ptr getRowSumFilter_GPU(int srcType, int sumType, int ksize, int anchor = -1); + + //! returns vertical 1D box filter + //! supports only CV_8UC1 sum type and CV_32FC1 dst type + CV_EXPORTS Ptr getColumnSumFilter_GPU(int sumType, int dstType, int ksize, int anchor = -1); + + //! returns 2D box filter + //! supports CV_8UC1 and CV_8UC4 source type, dst type must be the same as source type + CV_EXPORTS Ptr getBoxFilter_GPU(int srcType, int dstType, const Size& ksize, Point anchor = Point(-1, -1)); + + //! returns box filter engine + CV_EXPORTS Ptr createBoxFilter_GPU(int srcType, int dstType, const Size& ksize, + const Point& anchor = Point(-1,-1)); + + //! returns 2D morphological filter + //! only MORPH_ERODE and MORPH_DILATE are supported + //! supports CV_8UC1 and CV_8UC4 types + //! kernel must have CV_8UC1 type, one rows and cols == ksize.width * ksize.height + CV_EXPORTS Ptr getMorphologyFilter_GPU(int op, int type, const GpuMat& kernel, const Size& ksize, + Point anchor=Point(-1,-1)); + + //! returns morphological filter engine. Only MORPH_ERODE and MORPH_DILATE are supported. + CV_EXPORTS Ptr createMorphologyFilter_GPU(int op, int type, const Mat& kernel, + const Point& anchor = Point(-1,-1), int iterations = 1); + + //! returns 2D filter with the specified kernel + //! supports CV_8UC1 and CV_8UC4 types + //! kernel must have CV_8UC1 type, one rows and cols == ksize.width * ksize.height + CV_EXPORTS Ptr getLinearFilter_GPU(int srcType, int dstType, const GpuMat& kernel, const Size& ksize, + Point anchor = Point(-1, -1), int nDivisor = 1); + + //! returns the non-separable linear filter engine + CV_EXPORTS Ptr createLinearFilter_GPU(int srcType, int dstType, const Mat& kernel, + const Point& anchor = Point(-1,-1)); + + //! returns the primitive row filter with the specified kernel + CV_EXPORTS Ptr getLinearRowFilter_GPU(int srcType, int bufType, const GpuMat& rowKernel, + int anchor = -1, int nDivisor = 1); + + //! returns the primitive column filter with the specified kernel + CV_EXPORTS Ptr getLinearColumnFilter_GPU(int bufType, int dstType, const GpuMat& columnKernel, + int anchor = -1, int nDivisor = 1); + + //! returns the separable linear filter engine + CV_EXPORTS Ptr createSeparableLinearFilter_GPU(int srcType, int dstType, const Mat& rowKernel, + const Mat& columnKernel, const Point& anchor = Point(-1,-1)); + + //! returns filter engine for the generalized Sobel operator + CV_EXPORTS Ptr createDerivFilter_GPU(int srcType, int dstType, int dx, int dy, int ksize); + + //! returns the Gaussian filter engine + CV_EXPORTS Ptr createGaussianFilter_GPU(int type, Size ksize, double sigma1, double sigma2 = 0); + //! smooths the image using the normalized box filter - //! supports CV_8UC1, CV_8UC4 types and kernel size 3, 5, 7 - CV_EXPORTS void boxFilter(const GpuMat& src, GpuMat& dst, Size ksize, Point anchor = Point(-1,-1)); + //! supports CV_8UC1, CV_8UC4 types + CV_EXPORTS void boxFilter(const GpuMat& src, GpuMat& dst, int ddepth, Size ksize, Point anchor = Point(-1,-1)); //! a synonym for normalized box filter - static inline void blur(const GpuMat& src, GpuMat& dst, Size ksize, Point anchor = Point(-1,-1)) { boxFilter(src, dst, ksize, anchor); } - + static inline void blur(const GpuMat& src, GpuMat& dst, Size ksize, Point anchor = Point(-1,-1)) { boxFilter(src, dst, -1, ksize, anchor); } + //! erodes the image (applies the local minimum operator) - CV_EXPORTS void erode( const GpuMat& src, GpuMat& dst, const Mat& kernel, Point anchor, int iterations); + CV_EXPORTS void erode( const GpuMat& src, GpuMat& dst, const Mat& kernel, Point anchor = Point(-1, -1), int iterations = 1); //! dilates the image (applies the local maximum operator) - CV_EXPORTS void dilate( const GpuMat& src, GpuMat& dst, const Mat& kernel, Point anchor, int iterations); + CV_EXPORTS void dilate( const GpuMat& src, GpuMat& dst, const Mat& kernel, Point anchor = Point(-1, -1), int iterations = 1); //! applies an advanced morphological operation to the image - CV_EXPORTS void morphologyEx( const GpuMat& src, GpuMat& dst, int op, const Mat& kernel, Point anchor, int iterations); + CV_EXPORTS void morphologyEx( const GpuMat& src, GpuMat& dst, int op, const Mat& kernel, Point anchor = Point(-1, -1), int iterations = 1); + + //! applies non-separable 2D linear filter to the image + CV_EXPORTS void filter2D(const GpuMat& src, GpuMat& dst, int ddepth, const Mat& kernel, Point anchor=Point(-1,-1)); - //! 1D mask Window Sum for 8 bit images - CV_EXPORTS void sumWindowColumn(const GpuMat& src, GpuMat& dst, int ksize, int anchor = -1); - CV_EXPORTS void sumWindowRow(const GpuMat& src, GpuMat& dst, int ksize, int anchor = -1); + //! applies separable 2D linear filter to the image + CV_EXPORTS void sepFilter2D(const GpuMat& src, GpuMat& dst, int ddepth, const Mat& kernelX, const Mat& kernelY, + Point anchor = Point(-1,-1)); //! applies generalized Sobel operator to the image CV_EXPORTS void Sobel(const GpuMat& src, GpuMat& dst, int ddepth, int dx, int dy, int ksize = 3, double scale = 1); + //! applies the vertical or horizontal Scharr operator to the image + CV_EXPORTS void Scharr(const GpuMat& src, GpuMat& dst, int ddepth, int dx, int dy, double scale = 1); + //! smooths the image using Gaussian filter. CV_EXPORTS void GaussianBlur(const GpuMat& src, GpuMat& dst, Size ksize, double sigma1, double sigma2 = 0); - //! applies Canny edge detector and produces the edge map. - CV_EXPORTS void Canny(const GpuMat& image, GpuMat& edges, double threshold1, double threshold2, int apertureSize = 3); + //! applies Laplacian operator to the image + //! supports only ksize = 1 and ksize = 3 + CV_EXPORTS void Laplacian(const GpuMat& src, GpuMat& dst, int ddepth, int ksize = 1, double scale = 1); //////////////////////////////// Image Labeling //////////////////////////////// diff --git a/modules/gpu/src/arithm.cpp b/modules/gpu/src/arithm.cpp index 00e08a142a..4104cb0ab1 100644 --- a/modules/gpu/src/arithm.cpp +++ b/modules/gpu/src/arithm.cpp @@ -387,6 +387,7 @@ void cv::gpu::flip(const GpuMat& src, GpuMat& dst, int flipCode) Scalar cv::gpu::sum(const GpuMat& src) { + CV_Assert(!"disabled until fix crash"); CV_Assert(src.type() == CV_8UC1 || src.type() == CV_8UC4); NppiSize sz; @@ -420,6 +421,7 @@ Scalar cv::gpu::sum(const GpuMat& src) void cv::gpu::minMax(const GpuMat& src, double* minVal, double* maxVal) { + CV_Assert(!"disabled until fix npp bug"); CV_Assert(src.type() == CV_8UC1); NppiSize sz; diff --git a/modules/gpu/src/filtering_npp.cpp b/modules/gpu/src/filtering_npp.cpp index 1100db72cc..1ca51e1521 100644 --- a/modules/gpu/src/filtering_npp.cpp +++ b/modules/gpu/src/filtering_npp.cpp @@ -48,82 +48,413 @@ using namespace cv::gpu; #if !defined (HAVE_CUDA) +Ptr cv::gpu::createFilter2D_GPU(const Ptr) { throw_nogpu(); return Ptr(0); } +Ptr cv::gpu::createSeparableFilter_GPU(const Ptr&, const Ptr&) { throw_nogpu(); return Ptr(0); } +Ptr cv::gpu::getRowSumFilter_GPU(int, int, int, int) { throw_nogpu(); return Ptr(0); } +Ptr cv::gpu::getColumnSumFilter_GPU(int, int, int, int) { throw_nogpu(); return Ptr(0); } +Ptr cv::gpu::getBoxFilter_GPU(int, int, const Size&, Point) { throw_nogpu(); return Ptr(0); } +Ptr cv::gpu::createBoxFilter_GPU(int, int, const Size&, const Point&) { throw_nogpu(); return Ptr(0); } +Ptr cv::gpu::getMorphologyFilter_GPU(int, int, const GpuMat&, const Size&, Point) { throw_nogpu(); return Ptr(0); } +Ptr cv::gpu::createMorphologyFilter_GPU(int, int, const Mat&, const Point&, int) { throw_nogpu(); return Ptr(0); } +Ptr cv::gpu::getLinearFilter_GPU(int, int, const GpuMat&, const Size&, Point, int) { throw_nogpu(); return Ptr(0); } +Ptr cv::gpu::createLinearFilter_GPU(int, int, const Mat&, const Point&) { throw_nogpu(); return Ptr(0); } +Ptr cv::gpu::getLinearRowFilter_GPU(int, int, const GpuMat&, int, int) { throw_nogpu(); return Ptr(0); } +Ptr cv::gpu::getLinearColumnFilter_GPU(int, int, const GpuMat&, int, int) { throw_nogpu(); return Ptr(0); } +Ptr cv::gpu::createSeparableLinearFilter_GPU(int, int, const Mat&, const Mat&, const Point&) { throw_nogpu(); return Ptr(0); } +Ptr cv::gpu::createDerivFilter_GPU(int, int, int, int, int) { throw_nogpu(); return Ptr(0); } +Ptr cv::gpu::createGaussianFilter_GPU(int, Size, double, double) { throw_nogpu(); return Ptr(0); } +void cv::gpu::boxFilter(const GpuMat&, GpuMat&, int, Size, Point) { throw_nogpu(); } void cv::gpu::erode( const GpuMat&, GpuMat&, const Mat&, Point, int) { throw_nogpu(); } void cv::gpu::dilate( const GpuMat&, GpuMat&, const Mat&, Point, int) { throw_nogpu(); } void cv::gpu::morphologyEx( const GpuMat&, GpuMat&, int, const Mat&, Point, int) { throw_nogpu(); } -void cv::gpu::boxFilter(const GpuMat&, GpuMat&, Size, Point) { throw_nogpu(); } -void cv::gpu::sumWindowColumn(const GpuMat&, GpuMat&, int, int) { throw_nogpu(); } -void cv::gpu::sumWindowRow(const GpuMat&, GpuMat&, int, int) { throw_nogpu(); } +void cv::gpu::filter2D(const GpuMat&, GpuMat&, int, const Mat&, Point) { throw_nogpu(); } +void cv::gpu::sepFilter2D(const GpuMat&, GpuMat&, int, const Mat&, const Mat&, Point) { throw_nogpu(); } void cv::gpu::Sobel(const GpuMat&, GpuMat&, int, int, int, int, double) { throw_nogpu(); } +void cv::gpu::Scharr(const GpuMat&, GpuMat&, int, int, int, double) { throw_nogpu(); } void cv::gpu::GaussianBlur(const GpuMat&, GpuMat&, Size, double, double) { throw_nogpu(); } +void cv::gpu::Laplacian(const GpuMat&, GpuMat&, int, int, double) { throw_nogpu(); } #else -namespace +namespace { - typedef NppStatus (*npp_morf_func)(const Npp8u*, Npp32s, Npp8u*, Npp32s, NppiSize, const Npp8u*, NppiSize, NppiPoint); + inline void normalizeAnchor(int& anchor, int ksize) + { + if (anchor < 0) + anchor = ksize >> 1; + CV_Assert(0 <= anchor && anchor < ksize); + } - void morphoogy_caller(npp_morf_func func, const GpuMat& src, GpuMat& dst, const Mat& kernel, Point anchor, int iterations) + inline void normalizeAnchor(Point& anchor, const Size& ksize) { - CV_Assert(src.type() == CV_8U || src.type() == CV_8UC4); - CV_Assert(kernel.type() == CV_8U && (kernel.cols & 1) != 0 && (kernel.rows & 1) != 0); + normalizeAnchor(anchor.x, ksize.width); + normalizeAnchor(anchor.y, ksize.height); + } - if( anchor.x == -1 ) - anchor.x = kernel.cols / 2; - if( anchor.y == -1 ) - anchor.y = kernel.rows / 2; + inline void normalizeROI(Rect& roi, const Size& ksize, const Size& src_size) + { + if (roi == Rect(0,0,-1,-1)) + roi = Rect(ksize.width, ksize.height, src_size.width - 2 * ksize.width, src_size.height - 2 * ksize.height); - // in NPP for Cuda 3.1 only such anchor is supported. - CV_Assert(anchor.x == 0 && anchor.y == 0); + CV_Assert(roi.x >= 0 && roi.y >= 0 && roi.width <= src_size.width && roi.height <= src_size.height); + } - if (iterations == 0) + inline void normalizeKernel(const Mat& kernel, GpuMat& gpu_krnl, int type = CV_8U, int* nDivisor = 0, bool reverse = false) + { + int scale = nDivisor && (kernel.depth() == CV_32F || kernel.depth() == CV_64F) ? 256 : 1; + if (nDivisor) *nDivisor = scale; + + Mat cont_krnl = (kernel.isContinuous() ? kernel : kernel.clone()).reshape(1, 1); + Mat temp; + cont_krnl.convertTo(temp, type, scale); + + if (reverse) { - src.copyTo(dst); - return; + int count = temp.cols >> 1; + for (int i = 0; i < count; ++i) + { + std::swap(temp.at(0, i), temp.at(0, temp.cols - 1 - i)); + } } - const Mat& cont_krnl = (kernel.isContinuous() ? kernel : kernel.clone()).reshape(1, 1); - GpuMat gpu_krnl(cont_krnl); - - NppiSize sz; - sz.width = src.cols; - sz.height = src.rows; + gpu_krnl.upload(temp); + } +} - NppiSize mask_sz; - mask_sz.width = kernel.cols; - mask_sz.height = kernel.rows; +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Filter2D - NppiPoint anc; - anc.x = anchor.x; - anc.y = anchor.y; - - dst.create(src.size(), src.type()); +namespace +{ + class Filter2DEngine_GPU : public FilterEngine_GPU + { + public: + Filter2DEngine_GPU(const Ptr& filter2D_) : filter2D(filter2D_) {} + + virtual void apply(const GpuMat& src, GpuMat& dst, Rect roi = Rect(0,0,-1,-1)) + { + Size src_size = src.size(); + + dst.create(src_size, src.type()); + + normalizeROI(roi, filter2D->ksize, src_size); + + GpuMat srcROI = src(roi); + GpuMat dstROI = dst(roi); + + (*filter2D)(srcROI, dstROI); + } + + Ptr filter2D; + }; +} + +Ptr cv::gpu::createFilter2D_GPU(const Ptr filter2D) +{ + return Ptr(new Filter2DEngine_GPU(filter2D)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// SeparableFilter + +namespace +{ + class SeparableFilterEngine_GPU : public FilterEngine_GPU + { + public: + SeparableFilterEngine_GPU(const Ptr& rowFilter_, const Ptr& columnFilter_) : + rowFilter(rowFilter_), columnFilter(columnFilter_) + { + ksize = Size(rowFilter->ksize, columnFilter->ksize); + } + + virtual void apply(const GpuMat& src, GpuMat& dst, Rect roi = Rect(0,0,-1,-1)) + { + Size src_size = src.size(); + int src_type = src.type(); + + dst.create(src_size, src_type); + dstBuf.create(src_size, src_type); + + normalizeROI(roi, ksize, src_size); + + GpuMat srcROI = src(roi); + GpuMat dstROI = dst(roi); + GpuMat dstBufROI = dstBuf(roi); + + (*rowFilter)(srcROI, dstBufROI); + (*columnFilter)(dstBufROI, dstROI); + } + + Ptr rowFilter; + Ptr columnFilter; + Size ksize; GpuMat dstBuf; - if (iterations > 1) - dstBuf.create(src.size(), src.type()); + }; +} + +Ptr cv::gpu::createSeparableFilter_GPU(const Ptr& rowFilter, + const Ptr& columnFilter) +{ + return Ptr(new SeparableFilterEngine_GPU(rowFilter, columnFilter)); +} - nppSafeCall( func(src.ptr(), src.step, dst.ptr(), dst.step, sz, gpu_krnl.ptr(), mask_sz, anc) ); - for(int i = 1; i < iterations; ++i) +//////////////////////////////////////////////////////////////////////////////////////////////////// +// 1D Sum Filter + +namespace +{ + class NppRowSumFilter : public BaseRowFilter_GPU + { + public: + NppRowSumFilter(int ksize_, int anchor_) : BaseRowFilter_GPU(ksize_, anchor_) {} + + virtual void operator()(const GpuMat& src, GpuMat& dst) { - dst.swap(dstBuf); - nppSafeCall( func(dstBuf.ptr(), dstBuf.step, dst.ptr(), dst.step, sz, gpu_krnl.ptr(), mask_sz, anc) ); + NppiSize sz; + sz.width = src.cols; + sz.height = src.rows; + + nppSafeCall( nppiSumWindowRow_8u32f_C1R(src.ptr(), src.step, dst.ptr(), dst.step, sz, ksize, anchor) ); } - } + }; +} + +Ptr cv::gpu::getRowSumFilter_GPU(int srcType, int sumType, int ksize, int anchor) +{ + CV_Assert(srcType == CV_8UC1 && sumType == CV_32FC1); + + normalizeAnchor(anchor, ksize); + + return Ptr(new NppRowSumFilter(ksize, anchor)); } +namespace +{ + class NppColumnSumFilter : public BaseColumnFilter_GPU + { + public: + NppColumnSumFilter(int ksize_, int anchor_) : BaseColumnFilter_GPU(ksize_, anchor_) {} -void cv::gpu::erode( const GpuMat& src, GpuMat& dst, const Mat& kernel, Point anchor, int iterations) + virtual void operator()(const GpuMat& src, GpuMat& dst) + { + NppiSize sz; + sz.width = src.cols; + sz.height = src.rows; + + nppSafeCall( nppiSumWindowColumn_8u32f_C1R(src.ptr(), src.step, dst.ptr(), dst.step, sz, ksize, anchor) ); + } + }; +} + +Ptr cv::gpu::getColumnSumFilter_GPU(int sumType, int dstType, int ksize, int anchor) +{ + CV_Assert(sumType == CV_8UC1 && dstType == CV_32FC1); + + normalizeAnchor(anchor, ksize); + + return Ptr(new NppColumnSumFilter(ksize, anchor)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Box Filter + +namespace +{ + typedef NppStatus (*nppFilterBox_t)(const Npp8u * pSrc, Npp32s nSrcStep, Npp8u * pDst, Npp32s nDstStep, NppiSize oSizeROI, + NppiSize oMaskSize, NppiPoint oAnchor); + + class NPPBoxFilter : public BaseFilter_GPU + { + public: + NPPBoxFilter(const Size& ksize_, const Point& anchor_, nppFilterBox_t func_) : BaseFilter_GPU(ksize_, anchor_), func(func_) {} + + virtual void operator()(const GpuMat& src, GpuMat& dst) + { + NppiSize sz; + sz.width = src.cols; + sz.height = src.rows; + NppiSize oKernelSize; + oKernelSize.height = ksize.height; + oKernelSize.width = ksize.width; + NppiPoint oAnchor; + oAnchor.x = anchor.x; + oAnchor.y = anchor.y; + + nppSafeCall( func(src.ptr(), src.step, dst.ptr(), dst.step, sz, oKernelSize, oAnchor) ); + } + + nppFilterBox_t func; + }; +} + +Ptr cv::gpu::getBoxFilter_GPU(int srcType, int dstType, const Size& ksize, Point anchor) +{ + static const nppFilterBox_t nppFilterBox_callers[] = {0, nppiFilterBox_8u_C1R, 0, 0, nppiFilterBox_8u_C4R}; + + CV_Assert((srcType == CV_8UC1 || srcType == CV_8UC4) && dstType == srcType); + + normalizeAnchor(anchor, ksize); + + return Ptr(new NPPBoxFilter(ksize, anchor, nppFilterBox_callers[CV_MAT_CN(srcType)])); +} + +Ptr cv::gpu::createBoxFilter_GPU(int srcType, int dstType, const Size& ksize, const Point& anchor) +{ + Ptr boxFilter = getBoxFilter_GPU(srcType, dstType, ksize, anchor); + return createFilter2D_GPU(boxFilter); +} + +void cv::gpu::boxFilter(const GpuMat& src, GpuMat& dst, int ddepth, Size ksize, Point anchor) +{ + int sdepth = src.depth(), cn = src.channels(); + if( ddepth < 0 ) + ddepth = sdepth; + + dst.create(src.size(), CV_MAKETYPE(ddepth, cn)); + + Ptr f = createBoxFilter_GPU(src.type(), dst.type(), ksize, anchor); + f->apply(src, dst); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Morphology Filter + +namespace +{ + typedef NppStatus (*nppMorfFilter_t)(const Npp8u*, Npp32s, Npp8u*, Npp32s, NppiSize, const Npp8u*, NppiSize, NppiPoint); + + class NPPMorphFilter : public BaseFilter_GPU + { + public: + NPPMorphFilter(const Size& ksize_, const Point& anchor_, const GpuMat& kernel_, nppMorfFilter_t func_) : + BaseFilter_GPU(ksize_, anchor_), kernel(kernel_), func(func_) {} + + virtual void operator()(const GpuMat& src, GpuMat& dst) + { + NppiSize sz; + sz.width = src.cols; + sz.height = src.rows; + NppiSize oKernelSize; + oKernelSize.height = ksize.height; + oKernelSize.width = ksize.width; + NppiPoint oAnchor; + oAnchor.x = anchor.x; + oAnchor.y = anchor.y; + + nppSafeCall( func(src.ptr(), src.step, dst.ptr(), dst.step, sz, kernel.ptr(), oKernelSize, oAnchor) ); + } + + GpuMat kernel; + nppMorfFilter_t func; + }; +} + +Ptr cv::gpu::getMorphologyFilter_GPU(int op, int type, const GpuMat& kernel, const Size& ksize, Point anchor) +{ + static const nppMorfFilter_t nppMorfFilter_callers[2][5] = + { + {0, nppiErode_8u_C1R, 0, 0, nppiErode_8u_C4R }, + {0, nppiDilate_8u_C1R, 0, 0, nppiDilate_8u_C4R } + }; + + CV_Assert(op == MORPH_ERODE || op == MORPH_DILATE); + CV_Assert(type == CV_8UC1 || type == CV_8UC4); + CV_Assert(kernel.type() == CV_8UC1 && kernel.rows == 1 && kernel.cols == ksize.area()); + + normalizeAnchor(anchor, ksize); + + return Ptr(new NPPMorphFilter(ksize, anchor, kernel, nppMorfFilter_callers[op][CV_MAT_CN(type)])); +} + +namespace +{ + class MorphologyFilterEngine_GPU : public Filter2DEngine_GPU + { + public: + MorphologyFilterEngine_GPU(const Ptr& filter2D_, int iters_) : + Filter2DEngine_GPU(filter2D_), iters(iters_) {} + + virtual void apply(const GpuMat& src, GpuMat& dst, Rect roi = Rect(0,0,-1,-1)) + { + if (iters > 1) + dstBuf.create(src.size(), src.type()); + + Filter2DEngine_GPU::apply(src, dst); + for(int i = 1; i < iters; ++i) + { + dst.swap(dstBuf); + Filter2DEngine_GPU::apply(dst, dst); + } + } + + int iters; + GpuMat dstBuf; + }; +} + +Ptr cv::gpu::createMorphologyFilter_GPU(int op, int type, const Mat& kernel, const Point& anchor, int iterations) +{ + CV_Assert(iterations > 0); + + Size ksize = kernel.size(); + + GpuMat gpu_krnl; + normalizeKernel(kernel, gpu_krnl); + + Ptr filter2D = getMorphologyFilter_GPU(op, type, gpu_krnl, ksize, anchor); + + return Ptr(new MorphologyFilterEngine_GPU(filter2D, iterations)); +} + +namespace { - static npp_morf_func funcs[] = {0, nppiErode_8u_C1R, 0, 0, nppiErode_8u_C4R }; + void morphOp(int op, const GpuMat& src, GpuMat& dst, const Mat& _kernel, Point anchor, int iterations) + { + Mat kernel; + Size ksize = _kernel.data ? _kernel.size() : Size(3, 3); + + normalizeAnchor(anchor, ksize); - morphoogy_caller(funcs[src.channels()], src, dst, kernel, anchor, iterations); + if (iterations == 0 || _kernel.rows * _kernel.cols == 1) + { + src.copyTo(dst); + return; + } + + dst.create(src.size(), src.type()); + + if (!_kernel.data) + { + kernel = getStructuringElement(MORPH_RECT, Size(1 + iterations * 2, 1 + iterations * 2)); + anchor = Point(iterations, iterations); + iterations = 1; + } + else if (iterations > 1 && countNonZero(_kernel) == _kernel.rows * _kernel.cols) + { + anchor = Point(anchor.x * iterations, anchor.y * iterations); + kernel = getStructuringElement(MORPH_RECT, Size(ksize.width + iterations * (ksize.width - 1), + ksize.height + iterations * (ksize.height - 1)), anchor); + iterations = 1; + } + else + kernel = _kernel; + + Ptr f = createMorphologyFilter_GPU(op, src.type(), kernel, anchor, iterations); + + f->apply(src, dst); + } +} + +void cv::gpu::erode( const GpuMat& src, GpuMat& dst, const Mat& kernel, Point anchor, int iterations) +{ + morphOp(MORPH_ERODE, src, dst, kernel, anchor, iterations); } void cv::gpu::dilate( const GpuMat& src, GpuMat& dst, const Mat& kernel, Point anchor, int iterations) { - static npp_morf_func funcs[] = {0, nppiDilate_8u_C1R, 0, 0, nppiDilate_8u_C4R }; - morphoogy_caller(funcs[src.channels()], src, dst, kernel, anchor, iterations); + morphOp(MORPH_DILATE, src, dst, kernel, anchor, iterations); } void cv::gpu::morphologyEx( const GpuMat& src, GpuMat& dst, int op, const Mat& kernel, Point anchor, int iterations) @@ -165,195 +496,197 @@ void cv::gpu::morphologyEx( const GpuMat& src, GpuMat& dst, int op, const Mat& k } } -//////////////////////////////////////////////////////////////////////// -// boxFilter +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Linear Filter -void cv::gpu::boxFilter(const GpuMat& src, GpuMat& dst, Size ksize, Point anchor) +namespace { - CV_Assert(src.type() == CV_8UC1 || src.type() == CV_8UC4); - CV_Assert(ksize.height == 3 || ksize.height == 5 || ksize.height == 7); - CV_Assert(ksize.height == ksize.width); - - if (anchor.x == -1) - anchor.x = 0; - if (anchor.y == -1) - anchor.y = 0; + typedef NppStatus (*nppFilter2D_t)(const Npp8u * pSrc, Npp32s nSrcStep, Npp8u * pDst, Npp32s nDstStep, NppiSize oSizeROI, + const Npp32s * pKernel, NppiSize oKernelSize, NppiPoint oAnchor, Npp32s nDivisor); - CV_Assert(anchor.x == 0 && anchor.y == 0); + class NPPLinearFilter : public BaseFilter_GPU + { + public: + NPPLinearFilter(const Size& ksize_, const Point& anchor_, const GpuMat& kernel_, Npp32s nDivisor_, nppFilter2D_t func_) : + BaseFilter_GPU(ksize_, anchor_), kernel(kernel_), nDivisor(nDivisor_), func(func_) {} - dst.create(src.size(), src.type()); + virtual void operator()(const GpuMat& src, GpuMat& dst) + { + NppiSize sz; + sz.width = src.cols; + sz.height = src.rows; + NppiSize oKernelSize; + oKernelSize.height = ksize.height; + oKernelSize.width = ksize.width; + NppiPoint oAnchor; + oAnchor.x = anchor.x; + oAnchor.y = anchor.y; + + nppSafeCall( func(src.ptr(), src.step, dst.ptr(), dst.step, sz, + kernel.ptr(), oKernelSize, oAnchor, nDivisor) ); + } - NppiSize srcsz; - srcsz.height = src.rows; - srcsz.width = src.cols; - NppiSize masksz; - masksz.height = ksize.height; - masksz.width = ksize.width; - NppiPoint anc; - anc.x = anchor.x; - anc.y = anchor.y; - - if (src.type() == CV_8UC1) - { - nppSafeCall( nppiFilterBox_8u_C1R(src.ptr(), src.step, dst.ptr(), dst.step, srcsz, masksz, anc) ); - } - else - { - nppSafeCall( nppiFilterBox_8u_C4R(src.ptr(), src.step, dst.ptr(), dst.step, srcsz, masksz, anc) ); - } + GpuMat kernel; + Npp32s nDivisor; + nppFilter2D_t func; + }; } -//////////////////////////////////////////////////////////////////////// -// sumWindow Filter - -namespace +Ptr cv::gpu::getLinearFilter_GPU(int srcType, int dstType, const GpuMat& kernel, const Size& ksize, Point anchor, int nDivisor) { - typedef NppStatus (*nppSumWindow_t)(const Npp8u * pSrc, Npp32s nSrcStep, - Npp32f * pDst, Npp32s nDstStep, NppiSize oROI, - Npp32s nMaskSize, Npp32s nAnchor); - - inline void sumWindowCaller(nppSumWindow_t func, const GpuMat& src, GpuMat& dst, int ksize, int anchor) - { - CV_Assert(src.type() == CV_8UC1); - - if (anchor == -1) - anchor = ksize / 2; + static const nppFilter2D_t cppFilter2D_callers[] = {0, nppiFilter_8u_C1R, 0, 0, nppiFilter_8u_C4R}; - NppiSize sz; - sz.width = src.cols; - sz.height = src.rows; + CV_Assert((srcType == CV_8UC1 || srcType == CV_8UC4) && dstType == srcType); + CV_Assert(kernel.type() == CV_32SC1 && kernel.rows == 1 && kernel.cols == ksize.area()); - dst.create(src.size(), CV_32FC1); + normalizeAnchor(anchor, ksize); - nppSafeCall( func(src.ptr(), src.step, dst.ptr(), dst.step, sz, ksize, anchor) ); - } -} + return Ptr(new NPPLinearFilter(ksize, anchor, kernel, nDivisor, cppFilter2D_callers[CV_MAT_CN(srcType)])); +} -void cv::gpu::sumWindowColumn(const GpuMat& src, GpuMat& dst, int ksize, int anchor) +Ptr cv::gpu::createLinearFilter_GPU(int srcType, int dstType, const Mat& kernel, const Point& anchor) { - sumWindowCaller(nppiSumWindowColumn_8u32f_C1R, src, dst, ksize, anchor); + Size ksize = kernel.size(); + + GpuMat gpu_krnl; + int nDivisor; + normalizeKernel(kernel, gpu_krnl, CV_32S, &nDivisor, true); + + Ptr linearFilter = getLinearFilter_GPU(srcType, dstType, gpu_krnl, ksize, anchor, nDivisor); + + return createFilter2D_GPU(linearFilter); } -void cv::gpu::sumWindowRow(const GpuMat& src, GpuMat& dst, int ksize, int anchor) +void cv::gpu::filter2D(const GpuMat& src, GpuMat& dst, int ddepth, const Mat& kernel, Point anchor) { - sumWindowCaller(nppiSumWindowRow_8u32f_C1R, src, dst, ksize, anchor); + if( ddepth < 0 ) + ddepth = src.depth(); + + dst.create(src.size(), CV_MAKETYPE(ddepth, src.channels())); + + Ptr f = createLinearFilter_GPU(src.type(), dst.type(), kernel, anchor); + f->apply(src, dst); } -//////////////////////////////////////////////////////////////////////// -// Filter Engine +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Separable Linear Filter namespace { typedef NppStatus (*nppFilter1D_t)(const Npp8u * pSrc, Npp32s nSrcStep, Npp8u * pDst, Npp32s nDstStep, NppiSize oROI, - const Npp32s * pKernel, Npp32s nMaskSize, Npp32s nAnchor, Npp32s nDivisor); - typedef NppStatus (*nppFilter2D_t)(const Npp8u * pSrc, Npp32s nSrcStep, Npp8u * pDst, Npp32s nDstStep, NppiSize oSizeROI, - const Npp32s * pKernel, NppiSize oKernelSize, NppiPoint oAnchor, Npp32s nDivisor); + const Npp32s * pKernel, Npp32s nMaskSize, Npp32s nAnchor, Npp32s nDivisor); - void applyRowFilter(const GpuMat& src, GpuMat& dst, const GpuMat& rowKernel, Npp32s anchor = -1, Npp32s nDivisor = 1) + class NppLinearRowFilter : public BaseRowFilter_GPU { - static const nppFilter1D_t nppFilter1D_callers[] = {nppiFilterRow_8u_C1R, nppiFilterRow_8u_C4R}; + public: + NppLinearRowFilter(int ksize_, int anchor_, const GpuMat& kernel_, Npp32s nDivisor_, nppFilter1D_t func_) : + BaseRowFilter_GPU(ksize_, anchor_), kernel(kernel_), nDivisor(nDivisor_), func(func_) {} - CV_Assert(src.type() == CV_8UC1 || src.type() == CV_8UC4); + virtual void operator()(const GpuMat& src, GpuMat& dst) + { + NppiSize sz; + sz.width = src.cols; + sz.height = src.rows; - int kRowSize = rowKernel.cols; + nppSafeCall( func(src.ptr(), src.step, dst.ptr(), dst.step, sz, kernel.ptr(), ksize, anchor, nDivisor) ); + } - dst.create(src.size(), src.type()); - dst = Scalar(); + GpuMat kernel; + Npp32s nDivisor; + nppFilter1D_t func; + }; +} - NppiSize oROI; - oROI.width = src.cols - kRowSize + 1; - oROI.height = src.rows; +Ptr cv::gpu::getLinearRowFilter_GPU(int srcType, int bufType, const GpuMat& rowKernel, int anchor, int nDivisor) +{ + static const nppFilter1D_t nppFilter1D_callers[] = {0, nppiFilterRow_8u_C1R, 0, 0, nppiFilterRow_8u_C4R}; - if (anchor < 0) - anchor = kRowSize >> 1; + CV_Assert((srcType == CV_8UC1 || srcType == CV_8UC4) && bufType == srcType); + CV_Assert(rowKernel.type() == CV_32SC1 && rowKernel.rows == 1); - GpuMat srcROI = src.colRange(kRowSize-1, oROI.width); - GpuMat dstROI = dst.colRange(kRowSize-1, oROI.width); + int ksize = rowKernel.cols; - nppFilter1D_callers[src.channels() >> 2](srcROI.ptr(), srcROI.step, dstROI.ptr(), dstROI.step, oROI, - rowKernel.ptr(), kRowSize, anchor, nDivisor); - } + normalizeAnchor(anchor, ksize); + + return Ptr(new NppLinearRowFilter(ksize, anchor, rowKernel, nDivisor, nppFilter1D_callers[CV_MAT_CN(srcType)])); +} - void applyColumnFilter(const GpuMat& src, GpuMat& dst, const GpuMat& columnKernel, Npp32s anchor = -1, Npp32s nDivisor = 1) +namespace +{ + class NppLinearColumnFilter : public BaseColumnFilter_GPU { - static const nppFilter1D_t nppFilter1D_callers[] = {nppiFilterColumn_8u_C1R, nppiFilterColumn_8u_C4R}; + public: + NppLinearColumnFilter(int ksize_, int anchor_, const GpuMat& kernel_, Npp32s nDivisor_, nppFilter1D_t func_) : + BaseColumnFilter_GPU(ksize_, anchor_), kernel(kernel_), nDivisor(nDivisor_), func(func_) {} - CV_Assert(src.type() == CV_8UC1 || src.type() == CV_8UC4); + virtual void operator()(const GpuMat& src, GpuMat& dst) + { + NppiSize sz; + sz.width = src.cols; + sz.height = src.rows; - int kColSize = columnKernel.cols; + nppSafeCall( func(src.ptr(), src.step, dst.ptr(), dst.step, sz, kernel.ptr(), ksize, anchor, nDivisor) ); + } - dst.create(src.size(), src.type()); - dst = Scalar(); + GpuMat kernel; + Npp32s nDivisor; + nppFilter1D_t func; + }; +} - NppiSize oROI; - oROI.width = src.cols; - oROI.height = src.rows - kColSize + 1; +Ptr cv::gpu::getLinearColumnFilter_GPU(int bufType, int dstType, const GpuMat& columnKernel, int anchor, int nDivisor) +{ + static const nppFilter1D_t nppFilter1D_callers[] = {0, nppiFilterColumn_8u_C1R, 0, 0, nppiFilterColumn_8u_C4R}; - if (anchor < 0) - anchor = kColSize >> 1; + CV_Assert((bufType == CV_8UC1 || bufType == CV_8UC4) && dstType == bufType); + CV_Assert(columnKernel.type() == CV_32SC1 && columnKernel.rows == 1); - GpuMat srcROI = src.rowRange(kColSize-1, oROI.height); - GpuMat dstROI = dst.rowRange(kColSize-1, oROI.height); - - nppFilter1D_callers[src.channels() >> 2](srcROI.ptr(), srcROI.step, dstROI.ptr(), dstROI.step, oROI, - columnKernel.ptr(), kColSize, anchor, nDivisor); - } + int ksize = columnKernel.cols; - inline void applySeparableFilter(const GpuMat& src, GpuMat& dst, const GpuMat& rowKernel, const GpuMat& columnKernel, - const cv::Point& anchor = cv::Point(-1, -1), Npp32s nDivisor = 1) - { - GpuMat dstBuf; - applyRowFilter(src, dstBuf, rowKernel, anchor.x, nDivisor); - applyColumnFilter(dstBuf, dst, columnKernel, anchor.y, nDivisor); - } + normalizeAnchor(anchor, ksize); - void makeNppKernel(Mat kernel, GpuMat& dst) - { - kernel.convertTo(kernel, CV_32S); - kernel = kernel.t(); - int ksize = kernel.cols; - for (int i = 0; i < ksize / 2; ++i) - { - std::swap(kernel.at(0, i), kernel.at(0, ksize - 1 - i)); - } - dst.upload(kernel); - } + return Ptr(new NppLinearColumnFilter(ksize, anchor, columnKernel, nDivisor, nppFilter1D_callers[CV_MAT_CN(bufType)])); +} - void applyFilter2D(const GpuMat& src, GpuMat& dst, const GpuMat& kernel, cv::Point anchor = cv::Point(-1, -1), Npp32s nDivisor = 1) - { - static const nppFilter2D_t nppFilter2D_callers[] = {nppiFilter_8u_C1R, nppiFilter_8u_C4R}; +Ptr cv::gpu::createSeparableLinearFilter_GPU(int srcType, int dstType, const Mat& rowKernel, const Mat& columnKernel, + const Point& anchor) +{ + int sdepth = CV_MAT_DEPTH(srcType), ddepth = CV_MAT_DEPTH(dstType); + int cn = CV_MAT_CN(srcType); + int bdepth = std::max(sdepth, ddepth); + int bufType = CV_MAKETYPE(bdepth, cn); - CV_Assert(src.type() == CV_8UC1 || src.type() == CV_8UC4); + GpuMat gpu_row_krnl, gpu_col_krnl; + int nRowDivisor, nColDivisor; + normalizeKernel(rowKernel, gpu_row_krnl, CV_32S, &nRowDivisor, true); + normalizeKernel(columnKernel, gpu_col_krnl, CV_32S, &nColDivisor, true); - dst.create(src.size(), src.type()); - dst = Scalar(); - - NppiSize oROI; - oROI.width = src.cols - kernel.cols + 1; - oROI.height = src.rows - kernel.rows + 1; - - if (anchor.x < 0) - anchor.x = kernel.cols >> 1; - if (anchor.y < 0) - anchor.y = kernel.rows >> 1; - - GpuMat srcROI = src(Range(kernel.rows-1, oROI.height), Range(kernel.cols-1, oROI.width)); - GpuMat dstROI = dst(Range(kernel.rows-1, oROI.height), Range(kernel.cols-1, oROI.width)); - - NppiSize oKernelSize; - oKernelSize.height = kernel.rows; - oKernelSize.width = kernel.cols; - NppiPoint oAnchor; - oAnchor.x = anchor.x; - oAnchor.y = anchor.y; - - nppFilter2D_callers[src.channels() >> 2](srcROI.ptr(), srcROI.step, dstROI.ptr(), dstROI.step, oROI, - kernel.ptr(), oKernelSize, oAnchor, nDivisor); - } + Ptr rowFilter = getLinearRowFilter_GPU(srcType, bufType, gpu_row_krnl, anchor.x, nRowDivisor); + Ptr columnFilter = getLinearColumnFilter_GPU(bufType, dstType, gpu_col_krnl, anchor.y, nColDivisor); + + return createSeparableFilter_GPU(rowFilter, columnFilter); +} + +void cv::gpu::sepFilter2D(const GpuMat& src, GpuMat& dst, int ddepth, const Mat& kernelX, const Mat& kernelY, Point anchor) +{ + if( ddepth < 0 ) + ddepth = src.depth(); + + dst.create(src.size(), CV_MAKETYPE(ddepth, src.channels())); + + Ptr f = createSeparableLinearFilter_GPU(src.type(), dst.type(), kernelX, kernelY, anchor); + f->apply(src, dst); } -//////////////////////////////////////////////////////////////////////// -// Sobel +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Deriv Filter + +Ptr cv::gpu::createDerivFilter_GPU(int srcType, int dstType, int dx, int dy, int ksize) +{ + Mat kx, ky; + getDerivKernels(kx, ky, dx, dy, ksize, false, CV_32F); + return createSeparableLinearFilter_GPU(srcType, dstType, kx, ky); +} void cv::gpu::Sobel(const GpuMat& src, GpuMat& dst, int ddepth, int dx, int dy, int ksize, double scale) { @@ -370,55 +703,86 @@ void cv::gpu::Sobel(const GpuMat& src, GpuMat& dst, int ddepth, int dx, int dy, ky *= scale; } - GpuMat rowKernel; makeNppKernel(kx, rowKernel); - GpuMat columnKernel; makeNppKernel(ky, columnKernel); - - applySeparableFilter(src, dst, rowKernel, columnKernel); + sepFilter2D(src, dst, ddepth, kx, ky, Point(-1,-1)); } -//////////////////////////////////////////////////////////////////////// -// GaussianBlur - -void cv::gpu::GaussianBlur(const GpuMat& src, GpuMat& dst, Size ksize, double sigma1, double sigma2) +void cv::gpu::Scharr(const GpuMat& src, GpuMat& dst, int ddepth, int dx, int dy, double scale) { - if (ksize.width == 1 && ksize.height == 1) + Mat kx, ky; + getDerivKernels(kx, ky, dx, dy, -1, false, CV_32F); + + if( scale != 1 ) { - src.copyTo(dst); - return; + // usually the smoothing part is the slowest to compute, + // so try to scale it instead of the faster differenciating part + if( dx == 0 ) + kx *= scale; + else + ky *= scale; } - int depth = src.depth(); + sepFilter2D(src, dst, ddepth, kx, ky, Point(-1,-1)); +} + +void cv::gpu::Laplacian(const GpuMat& src, GpuMat& dst, int ddepth, int ksize, double scale) +{ + CV_Assert(ksize == 1 || ksize == 3); + + static const int K[2][9] = + { + {0, 1, 0, 1, -4, 1, 0, 1, 0}, + {2, 0, 2, 0, -8, 0, 2, 0, 2} + }; + Mat kernel(3, 3, CV_32S, (void*)K[ksize == 3]); + if (scale != 1) + kernel *= scale; + + filter2D(src, dst, ddepth, kernel, Point(-1,-1)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Gaussian Filter + +Ptr cv::gpu::createGaussianFilter_GPU(int type, Size ksize, double sigma1, double sigma2) +{ + int depth = CV_MAT_DEPTH(type); + if (sigma2 <= 0) sigma2 = sigma1; // automatic detection of kernel size from sigma if (ksize.width <= 0 && sigma1 > 0) - ksize.width = cvRound(sigma1 * (depth == CV_8U ? 3 : 4) * 2 + 1) | 1; + ksize.width = cvRound(sigma1 * (depth == CV_8U ? 3 : 4)*2 + 1) | 1; if (ksize.height <= 0 && sigma2 > 0) - ksize.height = cvRound(sigma2 * (depth == CV_8U ? 3 : 4) * 2 + 1) | 1; + ksize.height = cvRound(sigma2 * (depth == CV_8U ? 3 : 4)*2 + 1) | 1; - CV_Assert(ksize.width > 0 && ksize.width % 2 == 1 && ksize.height > 0 && ksize.height % 2 == 1); + CV_Assert( ksize.width > 0 && ksize.width % 2 == 1 && ksize.height > 0 && ksize.height % 2 == 1 ); sigma1 = std::max(sigma1, 0.0); sigma2 = std::max(sigma2, 0.0); - - const int scaleFactor = 256; - Mat kx = getGaussianKernel(ksize.width, sigma1, std::max(depth, CV_32F)); - kx.convertTo(kx, kx.depth(), scaleFactor); + Mat kx = getGaussianKernel( ksize.width, sigma1, std::max(depth, CV_32F) ); Mat ky; - if (ksize.height == ksize.width && std::abs(sigma1 - sigma2) < DBL_EPSILON) + if( ksize.height == ksize.width && std::abs(sigma1 - sigma2) < DBL_EPSILON ) ky = kx; else + ky = getGaussianKernel( ksize.height, sigma2, std::max(depth, CV_32F) ); + + return createSeparableLinearFilter_GPU(type, type, kx, ky); +} + +void cv::gpu::GaussianBlur(const GpuMat& src, GpuMat& dst, Size ksize, double sigma1, double sigma2) +{ + if (ksize.width == 1 && ksize.height == 1) { - ky = getGaussianKernel(ksize.height, sigma2, std::max(depth, CV_32F)); - ky.convertTo(ky, ky.depth(), scaleFactor); + src.copyTo(dst); + return; } - GpuMat rowKernel; makeNppKernel(kx, rowKernel); - GpuMat columnKernel; makeNppKernel(ky, columnKernel); - - applySeparableFilter(src, dst, rowKernel, columnKernel, cv::Point(-1, -1), scaleFactor); + dst.create(src.size(), src.type()); + + Ptr f = createGaussianFilter_GPU(src.type(), ksize, sigma1, sigma2); + f->apply(src, dst); } #endif diff --git a/modules/gpu/src/imgproc_gpu.cpp b/modules/gpu/src/imgproc_gpu.cpp index a786a620b9..9c88f3ea7a 100644 --- a/modules/gpu/src/imgproc_gpu.cpp +++ b/modules/gpu/src/imgproc_gpu.cpp @@ -992,6 +992,7 @@ void cv::gpu::integral(GpuMat& src, GpuMat& sum, GpuMat& sqsum) void cv::gpu::Canny(const GpuMat& image, GpuMat& edges, double threshold1, double threshold2, int apertureSize) { + CV_Assert(!"disabled until fix crash"); CV_Assert(image.type() == CV_8UC1); GpuMat srcDx, srcDy; diff --git a/tests/gpu/src/filters.cpp b/tests/gpu/src/filters.cpp new file mode 100644 index 0000000000..b73d0529b5 --- /dev/null +++ b/tests/gpu/src/filters.cpp @@ -0,0 +1,383 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include +#include +#include +#include "gputest.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/highgui/highgui.hpp" + +using namespace cv; +using namespace std; +using namespace gpu; + +class CV_GpuNppFilterTest : public CvTest +{ +public: + CV_GpuNppFilterTest(const char* test_name, const char* test_funcs) : CvTest(test_name, test_funcs) {} + virtual ~CV_GpuNppFilterTest() {} + +protected: + void run(int); + virtual int test(const Mat& img) = 0; + + int test8UC1(const Mat& img) + { + cv::Mat img_C1; + cvtColor(img, img_C1, CV_BGR2GRAY); + return test(img_C1); + } + + int test8UC4(const Mat& img) + { + cv::Mat img_C4; + cvtColor(img, img_C4, CV_BGR2BGRA); + return test(img_C4); + } + + int CheckNorm(const Mat& m1, const Mat& m2, const Size& ksize) + { + Rect roi = Rect(ksize.width, ksize.height, m1.cols - 2 * ksize.width, m1.rows - 2 * ksize.height); + Mat m1ROI = m1(roi); + Mat m2ROI = m2(roi); + + double res = norm(m1ROI, m2ROI, NORM_INF); + + if (res <= 1) + return CvTS::OK; + + ts->printf(CvTS::LOG, "\nNorm: %f\n", res); + return CvTS::FAIL_GENERIC; + } +}; + +void CV_GpuNppFilterTest::run( int ) +{ + cv::Mat img = cv::imread(std::string(ts->get_data_path()) + "stereobp/aloe-L.png"); + + if (img.empty()) + { + ts->set_failed_test_info(CvTS::FAIL_MISSING_TEST_DATA); + return; + } + + try + { + //run tests + int testResult = CvTS::OK; + + if (test8UC1(img) != CvTS::OK) + testResult = CvTS::FAIL_GENERIC; + + if (test8UC4(img) != CvTS::OK) + testResult = CvTS::FAIL_GENERIC; + + ts->set_failed_test_info(testResult); + } + catch(const cv::Exception& e) + { + if (!check_and_treat_gpu_exception(e, ts)) + throw; + return; + } + + ts->set_failed_test_info(CvTS::OK); +} + +//////////////////////////////////////////////////////////////////////////////// +// blur +struct CV_GpuNppImageBlurTest : public CV_GpuNppFilterTest +{ + CV_GpuNppImageBlurTest() : CV_GpuNppFilterTest( "GPU-NppImageBlur", "blur" ) {} + + int test(const Mat& img) + { + int ksizes[] = {3, 5, 7}; + int ksizes_num = sizeof(ksizes) / sizeof(int); + + int test_res = CvTS::OK; + + for (int i = 0; i < ksizes_num; ++i) + { + for (int j = 0; j < ksizes_num; ++j) + { + Size ksize(ksizes[i], ksizes[j]); + + ts->printf(CvTS::LOG, "\nksize = (%dx%d)\n", ksizes[i], ksizes[j]); + + Mat cpudst; + cv::blur(img, cpudst, ksize); + + GpuMat gpu1(img); + GpuMat gpudst; + cv::gpu::blur(gpu1, gpudst, ksize); + + if (CheckNorm(cpudst, gpudst, ksize) != CvTS::OK) + test_res = CvTS::FAIL_GENERIC; + } + } + + return test_res; + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// Sobel +struct CV_GpuNppImageSobelTest : public CV_GpuNppFilterTest +{ + CV_GpuNppImageSobelTest() : CV_GpuNppFilterTest( "GPU-NppImageSobel", "Sobel" ) {} + + int test(const Mat& img) + { + int ksizes[] = {3, 5, 7}; + int ksizes_num = sizeof(ksizes) / sizeof(int); + + int dx = 1, dy = 0; + + int test_res = CvTS::OK; + + for (int i = 0; i < ksizes_num; ++i) + { + ts->printf(CvTS::LOG, "\nksize = %d\n", ksizes[i]); + + Mat cpudst; + cv::Sobel(img, cpudst, -1, dx, dy, ksizes[i]); + + GpuMat gpu1(img); + GpuMat gpudst; + cv::gpu::Sobel(gpu1, gpudst, -1, dx, dy, ksizes[i]); + + if (CheckNorm(cpudst, gpudst, Size(ksizes[i], ksizes[i])) != CvTS::OK) + test_res = CvTS::FAIL_GENERIC; + } + + return test_res; + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// Scharr +struct CV_GpuNppImageScharrTest : public CV_GpuNppFilterTest +{ + CV_GpuNppImageScharrTest() : CV_GpuNppFilterTest( "GPU-NppImageScharr", "Scharr" ) {} + + int test(const Mat& img) + { + int dx = 1, dy = 0; + + Mat cpudst; + cv::Scharr(img, cpudst, -1, dx, dy); + + GpuMat gpu1(img); + GpuMat gpudst; + cv::gpu::Scharr(gpu1, gpudst, -1, dx, dy); + + return CheckNorm(cpudst, gpudst, Size(3, 3)); + } +}; + + +//////////////////////////////////////////////////////////////////////////////// +// GaussianBlur +struct CV_GpuNppImageGaussianBlurTest : public CV_GpuNppFilterTest +{ + CV_GpuNppImageGaussianBlurTest() : CV_GpuNppFilterTest( "GPU-NppImageGaussianBlur", "GaussianBlur" ) {} + + int test(const Mat& img) + { + int ksizes[] = {3, 5, 7}; + int ksizes_num = sizeof(ksizes) / sizeof(int); + + int test_res = CvTS::OK; + + const double sigma1 = 3.0; + + for (int i = 0; i < ksizes_num; ++i) + { + for (int j = 0; j < ksizes_num; ++j) + { + cv::Size ksize(ksizes[i], ksizes[j]); + + ts->printf(CvTS::LOG, "\nksize = (%dx%d)\n", ksizes[i], ksizes[j]); + + Mat cpudst; + cv::GaussianBlur(img, cpudst, ksize, sigma1); + + GpuMat gpu1(img); + GpuMat gpudst; + cv::gpu::GaussianBlur(gpu1, gpudst, ksize, sigma1); + + if (CheckNorm(cpudst, gpudst, ksize) != CvTS::OK) + test_res = CvTS::FAIL_GENERIC; + } + } + + return test_res; + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// Laplacian +struct CV_GpuNppImageLaplacianTest : public CV_GpuNppFilterTest +{ + CV_GpuNppImageLaplacianTest() : CV_GpuNppFilterTest( "GPU-NppImageLaplacian", "Laplacian" ) {} + + int test(const Mat& img) + { + int ksizes[] = {1, 3}; + int ksizes_num = sizeof(ksizes) / sizeof(int); + + int test_res = CvTS::OK; + + for (int i = 0; i < ksizes_num; ++i) + { + ts->printf(CvTS::LOG, "\nksize = %d\n", ksizes[i]); + + Mat cpudst; + cv::Laplacian(img, cpudst, -1, ksizes[i]); + + GpuMat gpu1(img); + GpuMat gpudst; + cv::gpu::Laplacian(gpu1, gpudst, -1, ksizes[i]); + + if (CheckNorm(cpudst, gpudst, Size(3, 3)) != CvTS::OK) + test_res = CvTS::FAIL_GENERIC; + } + + return test_res; + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// Erode +class CV_GpuErodeTest : public CV_GpuNppFilterTest +{ +public: + CV_GpuErodeTest() : CV_GpuNppFilterTest( "GPU-NppErode", "erode" ) {} + +protected: + virtual int test(const Mat& img) + { + Mat kernel(Mat::ones(3, 3, CV_8U)); + + cv::Mat cpuRes; + cv::erode(img, cpuRes, kernel); + + GpuMat gpuRes; + cv::gpu::erode(GpuMat(img), gpuRes, kernel); + + return CheckNorm(cpuRes, gpuRes, Size(3, 3)); + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// Dilate +class CV_GpuDilateTest : public CV_GpuNppFilterTest +{ +public: + CV_GpuDilateTest() : CV_GpuNppFilterTest( "GPU-NppDilate", "dilate" ) {} + +protected: + virtual int test(const Mat& img) + { + Mat kernel(Mat::ones(3, 3, CV_8U)); + + cv::Mat cpuRes; + cv::dilate(img, cpuRes, kernel); + + GpuMat gpuRes; + cv::gpu::dilate(GpuMat(img), gpuRes, kernel); + + return CheckNorm(cpuRes, gpuRes, Size(3, 3)); + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// MorphologyEx +class CV_GpuMorphExTest : public CV_GpuNppFilterTest +{ +public: + CV_GpuMorphExTest() : CV_GpuNppFilterTest( "GPU-NppMorphologyEx", "morphologyEx" ) {} + +protected: + virtual int test(const Mat& img) + { + static int ops[] = { MORPH_OPEN, CV_MOP_CLOSE, CV_MOP_GRADIENT, CV_MOP_TOPHAT, CV_MOP_BLACKHAT}; + const char *names[] = { "MORPH_OPEN", "CV_MOP_CLOSE", "CV_MOP_GRADIENT", "CV_MOP_TOPHAT", "CV_MOP_BLACKHAT"}; + int num = sizeof(ops)/sizeof(ops[0]); + + GpuMat kernel(Mat::ones(3, 3, CV_8U)); + + int res = CvTS::OK; + + for(int i = 0; i < num; ++i) + { + ts->printf(CvTS::LOG, "Tesing %s\n", names[i]); + + cv::Mat cpuRes; + cv::morphologyEx(img, cpuRes, ops[i], kernel); + + GpuMat gpuRes; + cv::gpu::morphologyEx(GpuMat(img), gpuRes, ops[i], kernel); + + if (CvTS::OK != CheckNorm(cpuRes, gpuRes, Size(3, 3))) + res = CvTS::FAIL_GENERIC; + } + return res; + } +}; + + + + +///////////////////////////////////////////////////////////////////////////// +/////////////////// tests registration ///////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// + +CV_GpuNppImageBlurTest CV_GpuNppImageBlur_test; +CV_GpuNppImageSobelTest CV_GpuNppImageSobel_test; +CV_GpuNppImageScharrTest CV_GpuNppImageScharr_test; +CV_GpuNppImageGaussianBlurTest CV_GpuNppImageGaussianBlur_test; +CV_GpuNppImageLaplacianTest CV_GpuNppImageLaplacian_test; +CV_GpuErodeTest CV_GpuErode_test; +CV_GpuDilateTest CV_GpuDilate_test; +CV_GpuMorphExTest CV_GpuMorphEx_test; \ No newline at end of file diff --git a/tests/gpu/src/gputest_main.cpp b/tests/gpu/src/gputest_main.cpp index 5012c4b419..3d547cf570 100644 --- a/tests/gpu/src/gputest_main.cpp +++ b/tests/gpu/src/gputest_main.cpp @@ -45,25 +45,27 @@ CvTS test_system; const char* blacklist[] = { - "GPU-NppImageSum", // crash "GPU-MatOperatorAsyncCall", // crash - //"GPU-NppErode", // different border interpolation - //"GPU-NppMorphologyEx", // different border interpolation + + "GPU-NppImageSum", // crash, probably npp bug + "GPU-NppImageMinNax", // npp bug - don't find min/max near right border //"GPU-NppImageDivide", // different round mode //"GPU-NppImageMeanStdDev", // different precision - //"GPU-NppImageMinNax", // npp bug - don't find min/max near right border - //"GPU-NppImageResize", // different precision in interpolation - //"GPU-NppImageWarpAffine", // different precision in interpolation - //"GPU-NppImageWarpPerspective", // different precision in interpolation - //"GPU-NppImageIntegral", // different precision - //"GPU-NppImageBlur", // different precision //"GPU-NppImageExp", // different precision //"GPU-NppImageLog", // different precision //"GPU-NppImageMagnitude", // different precision - //"GPU-NppImageSumWindow", // different border interpolation - //"GPU-NppImageSobel", // ??? - //"GPU-NppImageGaussianBlur", // different border interpolation + "GPU-NppImageCanny", // NPP_TEXTURE_BIND_ERROR + //"GPU-NppImageResize", // different precision + //"GPU-NppImageWarpAffine", // different precision + //"GPU-NppImageWarpPerspective", // different precision + //"GPU-NppImageIntegral", // different precision + + //"GPU-NppImageSobel", // ??? + //"GPU-NppImageScharr", // ??? + + //"GPU-NppImageGaussianBlur", // different precision + //"GPU-NppMorphologyEx", // different precision? 0 }; diff --git a/tests/gpu/src/imgproc_gpu.cpp b/tests/gpu/src/imgproc_gpu.cpp index 7b07312c11..b199acb82d 100644 --- a/tests/gpu/src/imgproc_gpu.cpp +++ b/tests/gpu/src/imgproc_gpu.cpp @@ -413,167 +413,6 @@ struct CV_GpuNppImageIntegralTest : public CV_GpuImageProcTest } }; -//////////////////////////////////////////////////////////////////////////////// -// blur -struct CV_GpuNppImageBlurTest : public CV_GpuImageProcTest -{ - CV_GpuNppImageBlurTest() : CV_GpuImageProcTest( "GPU-NppImageBlur", "blur" ) {} - - int test(const Mat& img) - { - if (img.type() != CV_8UC1 && img.type() != CV_8UC4) - { - ts->printf(CvTS::LOG, "\nUnsupported type\n"); - return CvTS::OK; - } - - int ksizes[] = {3, 5, 7}; - int ksizes_num = sizeof(ksizes) / sizeof(int); - - int test_res = CvTS::OK; - - for (int i = 0; i < ksizes_num; ++i) - { - ts->printf(CvTS::LOG, "\nksize = %d\n", ksizes[i]); - - Mat cpudst; - cv::blur(img, cpudst, Size(ksizes[i], ksizes[i])); - - GpuMat gpu1(img); - GpuMat gpudst; - cv::gpu::blur(gpu1, gpudst, Size(ksizes[i], ksizes[i])); - - if (CheckNorm(cpudst, gpudst) != CvTS::OK) - test_res = CvTS::FAIL_GENERIC; - } - - return test_res; - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// sumWindow -struct CV_GpuNppImageSumWindowTest : public CV_GpuImageProcTest -{ - CV_GpuNppImageSumWindowTest() : CV_GpuImageProcTest( "GPU-NppImageSumWindow", "sumWindow" ) {} - - int test(const Mat& img) - { - if (img.type() != CV_8UC1) - { - ts->printf(CvTS::LOG, "\nUnsupported type\n"); - return CvTS::OK; - } - - int ksizes[] = {3, 5, 7}; - int ksizes_num = sizeof(ksizes) / sizeof(int); - - int test_res = CvTS::OK; - - for (int i = 0; i < ksizes_num; ++i) - { - ts->printf(CvTS::LOG, "\nksize = %d\n", ksizes[i]); - - Mat cpudst(img.size(), CV_64FC1, Scalar()); - cv::Ptr ft = cv::getRowSumFilter(CV_8UC1, CV_64FC1, ksizes[i], 0); - for (int y = 0; y < img.rows; ++y) - (*ft)(img.ptr(y), cpudst.ptr(y), img.cols, 1); - cpudst.convertTo(cpudst, CV_32F); - - GpuMat gpu1(img); - GpuMat gpudst; - cv::gpu::sumWindowRow(gpu1, gpudst, ksizes[i], 0); - - if (CheckNorm(cpudst, gpudst) != CvTS::OK) - test_res = CvTS::FAIL_GENERIC; - } - - return test_res; - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// Sobel -struct CV_GpuNppImageSobelTest : public CV_GpuImageProcTest -{ - CV_GpuNppImageSobelTest() : CV_GpuImageProcTest( "GPU-NppImageSobel", "Sobel" ) {} - - int test(const Mat& img) - { - if (img.type() != CV_8UC1 && img.type() != CV_8UC4) - { - ts->printf(CvTS::LOG, "\nUnsupported type\n"); - return CvTS::OK; - } - - int ksizes[] = {3, 5, 7}; - int ksizes_num = sizeof(ksizes) / sizeof(int); - - int dx = 1, dy = 0; - - int test_res = CvTS::OK; - - for (int i = 0; i < ksizes_num; ++i) - { - ts->printf(CvTS::LOG, "\nksize = %d\n", ksizes[i]); - - Mat cpudst; - cv::Sobel(img, cpudst, -1, dx, dy, ksizes[i]); - - GpuMat gpu1(img); - GpuMat gpudst; - cv::gpu::Sobel(gpu1, gpudst, -1, dx, dy, ksizes[i]); - - if (CheckNorm(cpudst, gpudst) != CvTS::OK) - test_res = CvTS::FAIL_GENERIC; - } - - return test_res; - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// GaussianBlur -struct CV_GpuNppImageGaussianBlurTest : public CV_GpuImageProcTest -{ - CV_GpuNppImageGaussianBlurTest() : CV_GpuImageProcTest( "GPU-NppImageGaussianBlur", "GaussianBlur" ) {} - - int test(const Mat& img) - { - if (img.type() != CV_8UC1 && img.type() != CV_8UC4) - { - ts->printf(CvTS::LOG, "\nUnsupported type\n"); - return CvTS::OK; - } - - int ksizes[] = {3, 5, 7}; - int ksizes_num = sizeof(ksizes) / sizeof(int); - - int test_res = CvTS::OK; - - const double sigma1 = 3.0; - - for (int i = 0; i < ksizes_num; ++i) - { - for (int j = 0; j < ksizes_num; ++j) - { - ts->printf(CvTS::LOG, "\nksize = (%dx%d)\n", ksizes[i], ksizes[j]); - - Mat cpudst; - cv::GaussianBlur(img, cpudst, cv::Size(ksizes[i], ksizes[j]), sigma1); - - GpuMat gpu1(img); - GpuMat gpudst; - cv::gpu::GaussianBlur(gpu1, gpudst, cv::Size(ksizes[i], ksizes[j]), sigma1); - if (CheckNorm(cpudst, gpudst) != CvTS::OK) - test_res = CvTS::FAIL_GENERIC; - } - } - - return test_res; - } -}; - //////////////////////////////////////////////////////////////////////////////// // Canny struct CV_GpuNppImageCannyTest : public CV_GpuImageProcTest @@ -705,9 +544,5 @@ CV_GpuNppImageCopyMakeBorderTest CV_GpuNppImageCopyMakeBorder_test; CV_GpuNppImageWarpAffineTest CV_GpuNppImageWarpAffine_test; CV_GpuNppImageWarpPerspectiveTest CV_GpuNppImageWarpPerspective_test; CV_GpuNppImageIntegralTest CV_GpuNppImageIntegral_test; -CV_GpuNppImageBlurTest CV_GpuNppImageBlur_test; -CV_GpuNppImageSumWindowTest CV_GpuNppImageSumWindow_test; -CV_GpuNppImageSobelTest CV_GpuNppImageSobel_test; -CV_GpuNppImageGaussianBlurTest CV_GpuNppImageGaussianBlur_test; CV_GpuNppImageCannyTest CV_GpuNppImageCanny_test; CV_GpuCvtColorTest CV_GpuCvtColor_test; \ No newline at end of file diff --git a/tests/gpu/src/morf_filters.cpp b/tests/gpu/src/morf_filters.cpp deleted file mode 100644 index f27bc052bf..0000000000 --- a/tests/gpu/src/morf_filters.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#include -#include -#include -#include "gputest.hpp" -#include "opencv2/imgproc/imgproc.hpp" -#include "opencv2/highgui/highgui.hpp" - -using namespace cv; -using namespace std; -using namespace gpu; - -class CV_GpuNppMorphogyTest : public CvTest -{ -public: - CV_GpuNppMorphogyTest(const char* test_name, const char* test_funcs) : CvTest(test_name, test_funcs) {} - virtual ~CV_GpuNppMorphogyTest() {} - -protected: - void run(int); - virtual int test(const Mat& img) = 0; - - int test8UC1(const Mat& img) - { - cv::Mat img_C1; - cvtColor(img, img_C1, CV_BGR2GRAY); - return test(img_C1); - } - - int test8UC4(const Mat& img) - { - cv::Mat img_C4; - cvtColor(img, img_C4, CV_BGR2BGRA); - return test(img_C4); - } - - int CheckNorm(const Mat& m1, const Mat& m2) - { - double res = norm(m1, m2, NORM_INF); - - if (res < std::numeric_limits::epsilon()) - return CvTS::OK; - - ts->printf(CvTS::LOG, "\nNorm: %f\n", res); - return CvTS::FAIL_GENERIC; - } -}; - -void CV_GpuNppMorphogyTest::run( int ) -{ - cv::Mat img = cv::imread(std::string(ts->get_data_path()) + "stereobp/aloe-L.png"); - - if (img.empty()) - { - ts->set_failed_test_info(CvTS::FAIL_MISSING_TEST_DATA); - return; - } - - try - { - //run tests - int testResult = test8UC1(img); - if (testResult != CvTS::OK) - { - ts->set_failed_test_info(testResult); - return; - } - - testResult = test8UC4(img); - if (testResult != CvTS::OK) - { - ts->set_failed_test_info(testResult); - return; - } - } - catch(const cv::Exception& e) - { - if (!check_and_treat_gpu_exception(e, ts)) - throw; - return; - } - - ts->set_failed_test_info(CvTS::OK); -} - -//////////////////////////////////////////////////////////////////////////////// -// Erode -class CV_GpuErodeTest : public CV_GpuNppMorphogyTest -{ -public: - CV_GpuErodeTest() : CV_GpuNppMorphogyTest( "GPU-NppErode", "erode" ) {} - -protected: - virtual int test(const Mat& img) - { - GpuMat kernel(Mat::ones(3, 3, CV_8U)); - Point anchor(0, 0); - int iters = 1; - - cv::Mat cpuRes, cpuRes1; - cv::erode(img, cpuRes, kernel, anchor, iters); - - GpuMat gpuRes; - cv::gpu::erode(GpuMat(img), gpuRes, kernel, anchor, iters); - - return CheckNorm(cpuRes, gpuRes); - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// Dilate -class CV_GpuDilateTest : public CV_GpuNppMorphogyTest -{ -public: - CV_GpuDilateTest() : CV_GpuNppMorphogyTest( "GPU-NppDilate", "dilate" ) {} - -protected: - virtual int test(const Mat& img) - { - GpuMat kernel(Mat::ones(3, 3, CV_8U)); - Point anchor(0, 0); - int iters = 1; - - cv::Mat cpuRes, cpuRes1; - cv::dilate(img, cpuRes, kernel, anchor, iters); - - GpuMat gpuRes, gpuRes1; - cv::gpu::dilate(GpuMat(img), gpuRes, kernel, anchor, iters); - - return CheckNorm(cpuRes, gpuRes); - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// Dilate -class CV_GpuMorphExTest : public CV_GpuNppMorphogyTest -{ -public: - CV_GpuMorphExTest() : CV_GpuNppMorphogyTest( "GPU-NppMorphologyEx", "dmorphologyExilate" ) {} - -protected: - virtual int test(const Mat& img) - { - static int ops[] = { MORPH_OPEN, CV_MOP_CLOSE, CV_MOP_GRADIENT, CV_MOP_TOPHAT, CV_MOP_BLACKHAT}; - const char *names[] = { "MORPH_OPEN", "CV_MOP_CLOSE", "CV_MOP_GRADIENT", "CV_MOP_TOPHAT", "CV_MOP_BLACKHAT"}; - int num = sizeof(ops)/sizeof(ops[0]); - - GpuMat kernel(Mat::ones(3, 3, CV_8U)); - Point anchor(0, 0); - int iters = 1; - - for(int i = 0; i < num; ++i) - { - ts->printf(CvTS::LOG, "Tesing %s\n", names[i]); - - cv::Mat cpuRes; - cv::morphologyEx(img, cpuRes, ops[i], kernel, anchor, iters); - - GpuMat gpuRes; - cv::gpu::morphologyEx(GpuMat(img), gpuRes, ops[i], kernel, anchor, iters); - - int res = CheckNorm(cpuRes, gpuRes); - if (CvTS::OK != res) - return res; - } - return CvTS::OK; - } -}; - - - - -///////////////////////////////////////////////////////////////////////////// -/////////////////// tests registration ///////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// - -CV_GpuErodeTest CV_GpuErode_test; -CV_GpuDilateTest CV_GpuDilate_test; -CV_GpuMorphExTest CV_GpuMorphEx_test; \ No newline at end of file