From 1387bfcde0007e0d2215562dd354fa8f58268fc4 Mon Sep 17 00:00:00 2001 From: Anatoly Baksheev Date: Fri, 17 Sep 2010 15:28:59 +0000 Subject: [PATCH] added GPU implementation of morphology functions (using NPP) and tests for it. added npp_error function added check_and_treat_gpu_exception function for tests_gpu --- modules/core/include/opencv2/core/types_c.h | 3 +- modules/gpu/include/opencv2/gpu/gpu.hpp | 10 + modules/gpu/src/cuda/safe_call.hpp | 3 +- modules/gpu/src/filtering_npp.cpp | 143 +++++++++++++ modules/gpu/src/npp_error.cpp | 133 ++++++++++++ modules/gpu/src/precomp.hpp | 3 +- tests/CMakeLists.txt | 8 +- tests/gpu/src/gputest.hpp | 24 +++ tests/gpu/src/morf_filters.cpp | 214 ++++++++++++++++++++ 9 files changed, 535 insertions(+), 6 deletions(-) create mode 100644 modules/gpu/src/filtering_npp.cpp create mode 100644 modules/gpu/src/npp_error.cpp create mode 100644 tests/gpu/src/morf_filters.cpp diff --git a/modules/core/include/opencv2/core/types_c.h b/modules/core/include/opencv2/core/types_c.h index d5db6768bf..121f39c0be 100644 --- a/modules/core/include/opencv2/core/types_c.h +++ b/modules/core/include/opencv2/core/types_c.h @@ -231,7 +231,8 @@ enum { CV_StsBadMemBlock= -214, /* an allocated block has been corrupted */ CV_StsAssert= -215, /* assertion failed */ CV_GpuNotFound= -216, - CV_GpuApiCallError= -217 + CV_GpuApiCallError= -217, + CV_GpuNppCallError= -218 }; /****************************************************************************************\ diff --git a/modules/gpu/include/opencv2/gpu/gpu.hpp b/modules/gpu/include/opencv2/gpu/gpu.hpp index 47e36fd456..c7561708b6 100644 --- a/modules/gpu/include/opencv2/gpu/gpu.hpp +++ b/modules/gpu/include/opencv2/gpu/gpu.hpp @@ -437,6 +437,16 @@ namespace cv CV_EXPORTS void cvtColor(const GpuMat& src, GpuMat& dst, int code, int dcn = 0); CV_EXPORTS void cvtColor(const GpuMat& src, GpuMat& dst, int code, int dcn, const Stream& stream); + + //! erodes the image (applies the local minimum operator) + CV_EXPORTS void erode( const GpuMat& src, GpuMat& dst, const Mat& kernel, Point anchor, int iterations); + + //! dilates the image (applies the local maximum operator) + CV_EXPORTS void dilate( const GpuMat& src, GpuMat& dst, const Mat& kernel, Point anchor, int iterations); + + //! 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); + //////////////////////////////// StereoBM_GPU //////////////////////////////// class CV_EXPORTS StereoBM_GPU diff --git a/modules/gpu/src/cuda/safe_call.hpp b/modules/gpu/src/cuda/safe_call.hpp index 1e27cf3646..2cb486092e 100644 --- a/modules/gpu/src/cuda/safe_call.hpp +++ b/modules/gpu/src/cuda/safe_call.hpp @@ -59,6 +59,7 @@ namespace cv namespace gpu { extern "C" void error( const char *error_string, const char *file, const int line, const char *func = ""); + extern "C" void npp_error( int error, const char *file, const int line, const char *func = ""); static inline void ___cudaSafeCall(cudaError_t err, const char *file, const int line, const char *func = "") { @@ -69,7 +70,7 @@ namespace cv static inline void ___nppSafeCall(NppStatus err, const char *file, const int line, const char *func = "") { if (err < 0) - cv::gpu::error("NPP Error", file, line, func); + cv::gpu::npp_error(err, file, line, func); } } } diff --git a/modules/gpu/src/filtering_npp.cpp b/modules/gpu/src/filtering_npp.cpp new file mode 100644 index 0000000000..869e3307bc --- /dev/null +++ b/modules/gpu/src/filtering_npp.cpp @@ -0,0 +1,143 @@ +/*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. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., 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 the copyright holders 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 "precomp.hpp" + +using namespace cv; +using namespace cv::gpu; + + +#if !defined (HAVE_CUDA) + +void cv::gpu::erode( const GpuMat& src, GpuMat& dst, const Mat& kernel, Point anchor, int iterations) { throw_nogpu(); } +void cv::gpu::dilate( const GpuMat& src, GpuMat& dst, const Mat& kernel, Point anchor, int iterations) { throw_nogpu(); } +void morphologyEx( const GpuMat& src, GpuMat& dst, int op, const Mat& kernel, Point anchor, int iterations) { throw_nogpu(); } + +#else + +namespace +{ + typedef NppStatus (*npp_morf_func)(const Npp8u*, Npp32s, Npp8u*, Npp32s, NppiSize, const Npp8u*, NppiSize, NppiPoint); + + + void morphoogy_caller(npp_morf_func func, const GpuMat& src, GpuMat& dst, const Mat& kernel, Point anchor, int iterations) + { + CV_Assert(src.type() == CV_8U || src.type() == CV_8UC4); + CV_Assert(kernel.isContinuous() && kernel.type() == CV_8U && (kernel.cols & 1) != 0 && (kernel.rows & 1) != 0); + + // in NPP for Cuda 3.1 only such anchor is supported. + CV_Assert(anchor.x == kernel.cols/2 && anchor.y == kernel.rows/2); + + NppiSize sz; + sz.width = src.cols; + sz.height = dst.rows; + + NppiSize mask_sz; + mask_sz.width = kernel.cols; + mask_sz.height = kernel.rows; + + NppiPoint anc; + anc.x = anchor.x; + anc.y = anchor.y; + + dst.create(src.size(), src.type()); + + for(int i = 0; i < iterations; ++i) + nppSafeCall( func(src.ptr(), src.step, dst.ptr(), dst.step, sz, kernel.ptr(), mask_sz, anc) ); + } +} + + +void cv::gpu::erode( const GpuMat& src, GpuMat& dst, const Mat& kernel, Point anchor, int iterations) +{ + static npp_morf_func funcs[] = {0, nppiErode_8u_C1R, 0, 0, nppiErode_8u_C4R }; + + morphoogy_caller(funcs[src.channels()], 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); +} + +void cv::gpu::morphologyEx( const GpuMat& src, GpuMat& dst, int op, const Mat& kernel, Point anchor, int iterations) +{ + GpuMat temp; + switch( op ) + { + case MORPH_ERODE: erode( src, dst, kernel, anchor, iterations); break; + case MORPH_DILATE: dilate( src, dst, kernel, anchor, iterations); break; + case MORPH_OPEN: + erode( src, dst, kernel, anchor, iterations); + dilate( dst, dst, kernel, anchor, iterations); + break; + case CV_MOP_CLOSE: + dilate( src, dst, kernel, anchor, iterations); + erode( dst, dst, kernel, anchor, iterations); + break; + case CV_MOP_GRADIENT: + erode( src, temp, kernel, anchor, iterations); + dilate( src, dst, kernel, anchor, iterations); + subtract(dst, temp, dst); + break; + case CV_MOP_TOPHAT: + if( src.data != dst.data ) + temp = dst; + erode( src, temp, kernel, anchor, iterations); + dilate( temp, temp, kernel, anchor, iterations); + subtract(src, temp, dst); + break; + case CV_MOP_BLACKHAT: + if( src.data != dst.data ) + temp = dst; + dilate( src, temp, kernel, anchor, iterations); + erode( temp, temp, kernel, anchor, iterations); + dst = temp - src; + subtract(temp, src, dst); + break; + default: + CV_Error( CV_StsBadArg, "unknown morphological operation" ); + } +} + +#endif diff --git a/modules/gpu/src/npp_error.cpp b/modules/gpu/src/npp_error.cpp new file mode 100644 index 0000000000..df22b80c9c --- /dev/null +++ b/modules/gpu/src/npp_error.cpp @@ -0,0 +1,133 @@ +/*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. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., 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 the copyright holders 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 "precomp.hpp" + +using namespace cv; +using namespace cv::gpu; + + +#if !defined (HAVE_CUDA) + +#else /* !defined (HAVE_CUDA) */ + + +namespace +{ + struct NppError + { + int error; + const char* str; + } + npp_errors [] = + { + { NPP_NOT_SUPPORTED_MODE_ERROR, "NPP_NOT_SUPPORTED_MODE_ERROR" }, + { NPP_ROUND_MODE_NOT_SUPPORTED_ERROR, "NPP_ROUND_MODE_NOT_SUPPORTED_ERROR" }, + { NPP_RESIZE_NO_OPERATION_ERROR, "NPP_RESIZE_NO_OPERATION_ERROR" }, + { NPP_BAD_ARG_ERROR, "NPP_BAD_ARG_ERROR" }, + { NPP_LUT_NUMBER_OF_LEVELS_ERROR, "NPP_LUT_NUMBER_OF_LEVELS_ERROR" }, + { NPP_TEXTURE_BIND_ERROR, "NPP_TEXTURE_BIND_ERROR" }, + { NPP_COEFF_ERROR, "NPP_COEFF_ERROR" }, + { NPP_RECT_ERROR, "NPP_RECT_ERROR" }, + { NPP_QUAD_ERROR, "NPP_QUAD_ERROR" }, + { NPP_WRONG_INTERSECTION_ROI_ERROR, "NPP_WRONG_INTERSECTION_ROI_ERROR" }, + { NPP_NOT_EVEN_STEP_ERROR, "NPP_NOT_EVEN_STEP_ERROR" }, + { NPP_INTERPOLATION_ERROR, "NPP_INTERPOLATION_ERROR" }, + { NPP_RESIZE_FACTOR_ERROR, "NPP_RESIZE_FACTOR_ERROR" }, + { NPP_HAAR_CLASSIFIER_PIXEL_MATCH_ERROR, "NPP_HAAR_CLASSIFIER_PIXEL_MATCH_ERROR" }, + { NPP_MEMFREE_ERR, "NPP_MEMFREE_ERR" }, + { NPP_MEMSET_ERR, "NPP_MEMSET_ERR" }, + { NPP_MEMCPY_ERROR, "NPP_MEMCPY_ERROR" }, + { NPP_MEM_ALLOC_ERR, "NPP_MEM_ALLOC_ERR" }, + { NPP_HISTO_NUMBER_OF_LEVELS_ERROR, "NPP_HISTO_NUMBER_OF_LEVELS_ERROR" }, + { NPP_MIRROR_FLIP_ERR, "NPP_MIRROR_FLIP_ERR" }, + { NPP_INVALID_INPUT, "NPP_INVALID_INPUT" }, + { NPP_ALIGNMENT_ERROR, "NPP_ALIGNMENT_ERROR" }, + { NPP_STEP_ERROR, "NPP_STEP_ERROR" }, + { NPP_SIZE_ERROR, "NPP_SIZE_ERROR" }, + { NPP_POINTER_ERROR, "NPP_POINTER_ERROR" }, + { NPP_NULL_POINTER_ERROR, "NPP_NULL_POINTER_ERROR" }, + { NPP_CUDA_KERNEL_EXECUTION_ERROR, "NPP_CUDA_KERNEL_EXECUTION_ERROR" }, + { NPP_NOT_IMPLEMENTED_ERROR, "NPP_NOT_IMPLEMENTED_ERROR" }, + { NPP_ERROR, "NPP_ERROR" }, + { NPP_NO_ERROR, "NPP_NO_ERROR" }, + { NPP_SUCCESS, "NPP_SUCCESS" }, + { NPP_WARNING, "NPP_WARNING" }, + { NPP_WRONG_INTERSECTION_QUAD_WARNING, "NPP_WRONG_INTERSECTION_QUAD_WARNING" }, + { NPP_MISALIGNED_DST_ROI_WARNING, "NPP_MISALIGNED_DST_ROI_WARNING" }, + { NPP_AFFINE_QUAD_INCORRECT_WARNING, "NPP_AFFINE_QUAD_INCORRECT_WARNING" }, + { NPP_AFFINE_QUAD_CHANGED_WARNING, "NPP_AFFINE_QUAD_CHANGED_WARNING" }, + { NPP_ADJUSTED_ROI_SIZE_WARNING, "NPP_ADJUSTED_ROI_SIZE_WARNING" }, + { NPP_DOUBLE_SIZE_WARNING, "NPP_DOUBLE_SIZE_WARNING" }, + { NPP_ODD_ROI_WARNING, "NPP_ODD_ROI_WARNING" } + }; + + int error_num = sizeof(npp_errors)/sizeof(npp_errors[0]); + + struct Searcher + { + int err; + Searcher(int err_) : err(err_) {}; + bool operator()(const NppError& e) const { return e.error == err; } + }; + +} + +namespace cv +{ + namespace gpu + { + extern "C" const char* getNppErrorString( int err ) + { + int idx = std::find_if(npp_errors, npp_errors + error_num, Searcher(err)) - npp_errors; + + return (idx != error_num) ? npp_errors[idx].str : ""; + } + + extern "C" void npp_error( int err, const char *file, const int line, const char *func) + { + cv::error( cv::Exception(CV_GpuNppCallError, getNppErrorString(err), func, file, line) ); + } + } +} + +#endif \ No newline at end of file diff --git a/modules/gpu/src/precomp.hpp b/modules/gpu/src/precomp.hpp index 1c5ddbf498..43d2985f96 100644 --- a/modules/gpu/src/precomp.hpp +++ b/modules/gpu/src/precomp.hpp @@ -53,6 +53,7 @@ #include #include #include +#include #include "opencv2/gpu/gpu.hpp" #include "opencv2/imgproc/imgproc.hpp" @@ -62,7 +63,7 @@ #include "cuda_shared.hpp" #include "cuda_runtime_api.h" #include "opencv2/gpu/stream_accessor.hpp" - #include "npp.h" + #include "npp.h" #else /* defined(HAVE_CUDA) */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6ec862e282..793ff7cef6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,9 +7,11 @@ add_subdirectory(cxts) if(WITH_CUDA) set (BUILD_TESTS_GPU OFF CACHE BOOL "Build tests GPU") -endif() - -if(BUILD_TESTS_GPU AND WITH_CUDA) + + if(BUILD_TESTS_GPU AND WITH_CUDA) add_subdirectory(gpu) + endif() endif() + + diff --git a/tests/gpu/src/gputest.hpp b/tests/gpu/src/gputest.hpp index 3dbd01aeae..3ac06dfbdf 100644 --- a/tests/gpu/src/gputest.hpp +++ b/tests/gpu/src/gputest.hpp @@ -64,4 +64,28 @@ #endif /* _CXCORE_TEST_H_ */ + +inline bool check_and_treat_gpu_exception(const cv::Exception& e, CvTS* ts) +{ + switch (e.code) + { + case CV_GpuNotFound: + ts->printf(CvTS::CONSOLE, "\nGpu not found"); + break; + + case CV_GpuApiCallError: + ts->printf(CvTS::CONSOLE, "\nGPU Error: %s", e.what()); + break; + + case CV_GpuNppCallError: + ts->printf(CvTS::CONSOLE, "\nNPP Error: %s", e.what()); + break; + + default: + return false; + } + ts->set_failed_test_info(CvTS::FAIL_GENERIC); + return true; +} + /* End of file. */ diff --git a/tests/gpu/src/morf_filters.cpp b/tests/gpu/src/morf_filters.cpp new file mode 100644 index 0000000000..99d3119fa0 --- /dev/null +++ b/tests/gpu/src/morf_filters.cpp @@ -0,0 +1,214 @@ +/*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; + } + + 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) + { + Mat kernel(3, 3, CV_8U, 1); + Point anchor(1,1); + int iters = 3; + + cv::Mat cpuRes; + cv::erode(img, cpuRes, kernel, anchor, iters); + + GpuMat gpuRes; + cv::gpu::erode(GpuMat(img), gpuRes, kernel, anchor, iters); + + return CheckNorm(cpuRes, gpuRes); + } +}; + +CV_GpuErodeTest CV_GpuErode_test; + +//////////////////////////////////////////////////////////////////////////////// +// Dilate +class CV_GpuDilateTest : public CV_GpuNppMorphogyTest +{ +public: + CV_GpuDilateTest() : CV_GpuNppMorphogyTest( "GPU-NppDilate", "dilate" ) {} + +protected: + virtual int test(const Mat& img) + { + Mat kernel(3, 3, CV_8U, 1); + Point anchor(1,1); + int iters = 3; + + cv::Mat cpuRes; + cv::dilate(img, cpuRes, kernel, anchor, iters); + + GpuMat gpuRes; + cv::gpu::dilate(GpuMat(img), gpuRes, kernel, anchor, iters); + + return CheckNorm(cpuRes, gpuRes); + } +}; + +CV_GpuDilateTest CV_GpuDilate_test; + + +//////////////////////////////////////////////////////////////////////////////// +// 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]); + + Mat kernel(3, 3, CV_8U, 1); + Point anchor(1,1); + int iters = 3; + + 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; + } +}; + +CV_GpuMorphExTest CV_GpuMorphEx_test; -- 2.34.1