From 460b1dc2faf030c171fc2fd43ddb113bc800596e Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Mon, 11 Jul 2016 16:08:09 +0300 Subject: [PATCH 1/3] imgproc: Canny with custom gradient --- modules/imgproc/include/opencv2/imgproc.hpp | 13 +++ modules/imgproc/src/canny.cpp | 96 ++++++++++++++++----- 2 files changed, 87 insertions(+), 22 deletions(-) diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index 9f4763d34f..ee022476f0 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -1664,6 +1664,19 @@ CV_EXPORTS_W void Canny( InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize = 3, bool L2gradient = false ); +/** \overload + +Finds edges in an image using the Canny algorithm with custom image gradient. + +@param dx 16-bit x derivative of input image (CV_16SC1 or CV_16SC3). +@param dy 16-bit y derivative of input image (same type as dx). +@param edges,threshold1,threshold2,L2gradient See cv::Canny + */ +CV_EXPORTS_W void Canny( InputArray dx, InputArray dy, + OutputArray edges, + double threshold1, double threshold2, + bool L2gradient = false ); + /** @brief Calculates the minimal eigenvalue of gradient matrices for corner detection. The function is similar to cornerEigenValsAndVecs but it calculates and stores only the minimal diff --git a/modules/imgproc/src/canny.cpp b/modules/imgproc/src/canny.cpp index 53fb66bbbe..18f38284f5 100644 --- a/modules/imgproc/src/canny.cpp +++ b/modules/imgproc/src/canny.cpp @@ -43,6 +43,10 @@ #include "precomp.hpp" #include "opencl_kernels_imgproc.hpp" +#ifdef _MSC_VER +#pragma warning( disable: 4127 ) // conditional expression is constant +#endif + #if defined (HAVE_IPP) && (IPP_VERSION_X100 >= 700) #define USE_IPP_CANNY 1 @@ -53,6 +57,10 @@ namespace cv { + +static void CannyImpl(Mat& dx_, Mat& dy_, Mat& _dst, double low_thresh, double high_thresh, bool L2gradient); + + #ifdef HAVE_IPP static bool ippCanny(const Mat& _src, Mat& _dst, float low, float high) { @@ -585,9 +593,7 @@ private: #endif -} // namespace cv - -void cv::Canny( InputArray _src, OutputArray _dst, +void Canny( InputArray _src, OutputArray _dst, double low_thresh, double high_thresh, int aperture_size, bool L2gradient ) { @@ -683,14 +689,60 @@ while (borderPeaks.try_pop(m)) if (!m[mapstep+1]) CANNY_PUSH_SERIAL(m + mapstep + 1); } -#else +// the final pass, form the final image +const uchar* pmap = map + mapstep + 1; +uchar* pdst = dst.ptr(); +for (int i = 0; i < src.rows; i++, pmap += mapstep, pdst += dst.step) +{ + for (int j = 0; j < src.cols; j++) + pdst[j] = (uchar)-(pmap[j] >> 1); +} +#else Mat dx(src.rows, src.cols, CV_16SC(cn)); Mat dy(src.rows, src.cols, CV_16SC(cn)); Sobel(src, dx, CV_16S, 1, 0, aperture_size, 1, 0, BORDER_REPLICATE); Sobel(src, dy, CV_16S, 0, 1, aperture_size, 1, 0, BORDER_REPLICATE); + CannyImpl(dx, dy, dst, low_thresh, high_thresh, L2gradient); +#endif +} + +void Canny( InputArray _dx, InputArray _dy, OutputArray _dst, + double low_thresh, double high_thresh, + bool L2gradient ) +{ + CV_Assert(_dx.dims() == 2); + CV_Assert(_dx.type() == CV_16SC1 || _dx.type() == CV_16SC3); + CV_Assert(_dy.type() == _dx.type()); + CV_Assert(_dx.sameSize(_dy)); + + if (low_thresh > high_thresh) + std::swap(low_thresh, high_thresh); + + const int cn = _dx.channels(); + const Size size = _dx.size(); + _dst.create(size, CV_8U); + Mat dst = _dst.getMat(); + + Mat dx = _dx.getMat(); + Mat dy = _dy.getMat(); + if (cn > 1) + { + dx = dx.clone(); + dy = dy.clone(); + } + + CannyImpl(dx, dy, dst, low_thresh, high_thresh, L2gradient); +} + +static void CannyImpl(Mat& dx, Mat& dy, Mat& dst, + double low_thresh, double high_thresh, bool L2gradient) +{ + const int cn = dx.channels(); + const int cols = dx.cols, rows = dx.rows; + if (L2gradient) { low_thresh = std::min(32767.0, low_thresh); @@ -702,8 +754,8 @@ while (borderPeaks.try_pop(m)) int low = cvFloor(low_thresh); int high = cvFloor(high_thresh); - ptrdiff_t mapstep = src.cols + 2; - AutoBuffer buffer((src.cols+2)*(src.rows+2) + cn * mapstep * 3 * sizeof(int)); + ptrdiff_t mapstep = cols + 2; + AutoBuffer buffer((cols+2)*(rows+2) + cn * mapstep * 3 * sizeof(int)); int* mag_buf[3]; mag_buf[0] = (int*)(uchar*)buffer; @@ -713,9 +765,9 @@ while (borderPeaks.try_pop(m)) uchar* map = (uchar*)(mag_buf[2] + mapstep*cn); memset(map, 1, mapstep); - memset(map + mapstep*(src.rows + 1), 1, mapstep); + memset(map + mapstep*(rows + 1), 1, mapstep); - int maxsize = std::max(1 << 10, src.cols * src.rows / 10); + int maxsize = std::max(1 << 10, cols * rows / 10); std::vector stack(maxsize); uchar **stack_top = &stack[0]; uchar **stack_bottom = &stack[0]; @@ -744,17 +796,17 @@ while (borderPeaks.try_pop(m)) // 0 - the pixel might belong to an edge // 1 - the pixel can not belong to an edge // 2 - the pixel does belong to an edge - for (int i = 0; i <= src.rows; i++) + for (int i = 0; i <= rows; i++) { int* _norm = mag_buf[(i > 0) + 1] + 1; - if (i < src.rows) + if (i < rows) { short* _dx = dx.ptr(i); short* _dy = dy.ptr(i); if (!L2gradient) { - int j = 0, width = src.cols * cn; + int j = 0, width = cols * cn; #if CV_SSE2 if (haveSSE2) { @@ -788,7 +840,7 @@ while (borderPeaks.try_pop(m)) } else { - int j = 0, width = src.cols * cn; + int j = 0, width = cols * cn; #if CV_SSE2 if (haveSSE2) { @@ -824,7 +876,7 @@ while (borderPeaks.try_pop(m)) if (cn > 1) { - for(int j = 0, jn = 0; j < src.cols; ++j, jn += cn) + for(int j = 0, jn = 0; j < cols; ++j, jn += cn) { int maxIdx = jn; for(int k = 1; k < cn; ++k) @@ -834,7 +886,7 @@ while (borderPeaks.try_pop(m)) _dy[j] = _dy[maxIdx]; } } - _norm[-1] = _norm[src.cols] = 0; + _norm[-1] = _norm[cols] = 0; } else memset(_norm-1, 0, /* cn* */mapstep*sizeof(int)); @@ -845,7 +897,7 @@ while (borderPeaks.try_pop(m)) continue; uchar* _map = map + mapstep*i + 1; - _map[-1] = _map[src.cols] = 1; + _map[-1] = _map[cols] = 1; int* _mag = mag_buf[1] + 1; // take the central row ptrdiff_t magstep1 = mag_buf[2] - mag_buf[1]; @@ -854,17 +906,17 @@ while (borderPeaks.try_pop(m)) const short* _x = dx.ptr(i-1); const short* _y = dy.ptr(i-1); - if ((stack_top - stack_bottom) + src.cols > maxsize) + if ((stack_top - stack_bottom) + cols > maxsize) { int sz = (int)(stack_top - stack_bottom); - maxsize = std::max(maxsize * 3/2, sz + src.cols); + maxsize = std::max(maxsize * 3/2, sz + cols); stack.resize(maxsize); stack_bottom = &stack[0]; stack_top = stack_bottom + sz; } int prev_flag = 0; - for (int j = 0; j < src.cols; j++) + for (int j = 0; j < cols; j++) { #define CANNY_SHIFT 15 const int TG22 = (int)(0.4142135623730950488016887242097*(1<> 1); } } +} // namespace cv + void cvCanny( const CvArr* image, CvArr* edges, double threshold1, double threshold2, int aperture_size ) { From 575de89ee21f8cae9499b4305f621235591cdf5c Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Mon, 11 Jul 2016 16:34:21 +0300 Subject: [PATCH 2/3] imgproc: Canny: enable IPP & OpenCL optimization code path --- modules/imgproc/src/canny.cpp | 102 ++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 35 deletions(-) diff --git a/modules/imgproc/src/canny.cpp b/modules/imgproc/src/canny.cpp index 18f38284f5..5ba15a3ffe 100644 --- a/modules/imgproc/src/canny.cpp +++ b/modules/imgproc/src/canny.cpp @@ -62,52 +62,68 @@ static void CannyImpl(Mat& dx_, Mat& dy_, Mat& _dst, double low_thresh, double h #ifdef HAVE_IPP -static bool ippCanny(const Mat& _src, Mat& _dst, float low, float high) +template +static bool ippCanny(const Mat& _src, const Mat& dx_, const Mat& dy_, Mat& _dst, float low, float high) { #if USE_IPP_CANNY int size = 0, size1 = 0; IppiSize roi = { _src.cols, _src.rows }; -#if IPP_VERSION_X100 < 900 - if (ippiFilterSobelNegVertGetBufferSize_8u16s_C1R(roi, ippMskSize3x3, &size) < 0) - return false; - if (ippiFilterSobelHorizGetBufferSize_8u16s_C1R(roi, ippMskSize3x3, &size1) < 0) + if (ippiCannyGetSize(roi, &size) < 0) return false; + + if (!useCustomDeriv) + { +#if IPP_VERSION_X100 < 900 + if (ippiFilterSobelNegVertGetBufferSize_8u16s_C1R(roi, ippMskSize3x3, &size1) < 0) + return false; + size = std::max(size, size1); + if (ippiFilterSobelHorizGetBufferSize_8u16s_C1R(roi, ippMskSize3x3, &size1) < 0) + return false; #else - if (ippiFilterSobelNegVertBorderGetBufferSize(roi, ippMskSize3x3, ipp8u, ipp16s, 1, &size) < 0) - return false; - if (ippiFilterSobelHorizBorderGetBufferSize(roi, ippMskSize3x3, ipp8u, ipp16s, 1, &size1) < 0) - return false; + if (ippiFilterSobelNegVertBorderGetBufferSize(roi, ippMskSize3x3, ipp8u, ipp16s, 1, &size1) < 0) + return false; + size = std::max(size, size1); + if (ippiFilterSobelHorizBorderGetBufferSize(roi, ippMskSize3x3, ipp8u, ipp16s, 1, &size1) < 0) + return false; #endif - - size = std::max(size, size1); - - if (ippiCannyGetSize(roi, &size1) < 0) - return false; - size = std::max(size, size1); + size = std::max(size, size1); + } AutoBuffer buf(size + 64); uchar* buffer = alignPtr((uchar*)buf, 32); - Mat _dx(_src.rows, _src.cols, CV_16S); - if( ippiFilterSobelNegVertBorder_8u16s_C1R(_src.ptr(), (int)_src.step, - _dx.ptr(), (int)_dx.step, roi, - ippMskSize3x3, ippBorderRepl, 0, buffer) < 0 ) - return false; + Mat dx, dy; + if (!useCustomDeriv) + { + Mat _dx(_src.rows, _src.cols, CV_16S); + if( ippiFilterSobelNegVertBorder_8u16s_C1R(_src.ptr(), (int)_src.step, + _dx.ptr(), (int)_dx.step, roi, + ippMskSize3x3, ippBorderRepl, 0, buffer) < 0 ) + return false; - Mat _dy(_src.rows, _src.cols, CV_16S); - if( ippiFilterSobelHorizBorder_8u16s_C1R(_src.ptr(), (int)_src.step, - _dy.ptr(), (int)_dy.step, roi, - ippMskSize3x3, ippBorderRepl, 0, buffer) < 0 ) - return false; + Mat _dy(_src.rows, _src.cols, CV_16S); + if( ippiFilterSobelHorizBorder_8u16s_C1R(_src.ptr(), (int)_src.step, + _dy.ptr(), (int)_dy.step, roi, + ippMskSize3x3, ippBorderRepl, 0, buffer) < 0 ) + return false; - if( ippiCanny_16s8u_C1R(_dx.ptr(), (int)_dx.step, - _dy.ptr(), (int)_dy.step, + swap(dx, _dx); + swap(dy, _dy); + } + else + { + dx = dx_; + dy = dy_; + } + + if( ippiCanny_16s8u_C1R(dx.ptr(), (int)dx.step, + dy.ptr(), (int)dy.step, _dst.ptr(), (int)_dst.step, roi, low, high, buffer) < 0 ) return false; return true; #else - CV_UNUSED(_src); CV_UNUSED(_dst); CV_UNUSED(low); CV_UNUSED(high); + CV_UNUSED(_src); CV_UNUSED(dx_); CV_UNUSED(dy_); CV_UNUSED(_dst); CV_UNUSED(low); CV_UNUSED(high); return false; #endif } @@ -115,7 +131,8 @@ static bool ippCanny(const Mat& _src, Mat& _dst, float low, float high) #ifdef HAVE_OPENCL -static bool ocl_Canny(InputArray _src, OutputArray _dst, float low_thresh, float high_thresh, +template +static bool ocl_Canny(InputArray _src, const UMat& dx_, const UMat& dy_, OutputArray _dst, float low_thresh, float high_thresh, int aperture_size, bool L2gradient, int cn, const Size & size) { UMat map; @@ -148,7 +165,8 @@ static bool ocl_Canny(InputArray _src, OutputArray _dst, float low_thresh, float } int low = cvFloor(low_thresh), high = cvFloor(high_thresh); - if (aperture_size == 3 && !_src.isSubmatrix()) + if (!useCustomDeriv && + aperture_size == 3 && !_src.isSubmatrix()) { /* stage1_with_sobel: @@ -189,8 +207,16 @@ static bool ocl_Canny(InputArray _src, OutputArray _dst, float low_thresh, float Double thresholding */ UMat dx, dy; - Sobel(_src, dx, CV_16S, 1, 0, aperture_size, 1, 0, BORDER_REPLICATE); - Sobel(_src, dy, CV_16S, 0, 1, aperture_size, 1, 0, BORDER_REPLICATE); + if (!useCustomDeriv) + { + Sobel(_src, dx, CV_16S, 1, 0, aperture_size, 1, 0, BORDER_REPLICATE); + Sobel(_src, dy, CV_16S, 0, 1, aperture_size, 1, 0, BORDER_REPLICATE); + } + else + { + dx = dx_; + dy = dy_; + } ocl::Kernel without_sobel("stage1_without_sobel", ocl::imgproc::canny_oclsrc, format("-D WITHOUT_SOBEL -D cn=%d -D GRP_SIZEX=%d -D GRP_SIZEY=%d%s", @@ -617,7 +643,7 @@ void Canny( InputArray _src, OutputArray _dst, std::swap(low_thresh, high_thresh); CV_OCL_RUN(_dst.isUMat() && (cn == 1 || cn == 3), - ocl_Canny(_src, _dst, (float)low_thresh, (float)high_thresh, aperture_size, L2gradient, cn, size)) + ocl_Canny(_src, UMat(), UMat(), _dst, (float)low_thresh, (float)high_thresh, aperture_size, L2gradient, cn, size)) Mat src = _src.getMat(), dst = _dst.getMat(); @@ -626,7 +652,7 @@ void Canny( InputArray _src, OutputArray _dst, return; #endif - CV_IPP_RUN(USE_IPP_CANNY && (aperture_size == 3 && !L2gradient && 1 == cn), ippCanny(src, dst, (float)low_thresh, (float)high_thresh)) + CV_IPP_RUN(USE_IPP_CANNY && (aperture_size == 3 && !L2gradient && 1 == cn), ippCanny(src, Mat(), Mat(), dst, (float)low_thresh, (float)high_thresh)) #ifdef HAVE_TBB @@ -723,17 +749,23 @@ void Canny( InputArray _dx, InputArray _dy, OutputArray _dst, const int cn = _dx.channels(); const Size size = _dx.size(); + + CV_OCL_RUN(_dst.isUMat(), + ocl_Canny(UMat(), _dx.getUMat(), _dy.getUMat(), _dst, (float)low_thresh, (float)high_thresh, 0, L2gradient, cn, size)) + _dst.create(size, CV_8U); Mat dst = _dst.getMat(); Mat dx = _dx.getMat(); Mat dy = _dy.getMat(); + + CV_IPP_RUN(USE_IPP_CANNY && (!L2gradient && 1 == cn), ippCanny(Mat(), dx, dy, dst, (float)low_thresh, (float)high_thresh)) + if (cn > 1) { dx = dx.clone(); dy = dy.clone(); } - CannyImpl(dx, dy, dst, low_thresh, high_thresh, L2gradient); } From e20a93f7d67fdf70ab19055b5e70b0c953d0175e Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Mon, 11 Jul 2016 17:08:27 +0300 Subject: [PATCH 3/3] imgproc test: Canny with custom gradient --- modules/imgproc/test/ocl/test_canny.cpp | 37 ++++++++++++++++++---- modules/imgproc/test/test_canny.cpp | 27 ++++++++++++++-- modules/ts/include/opencv2/ts/ocl_test.hpp | 4 +-- 3 files changed, 56 insertions(+), 12 deletions(-) diff --git a/modules/imgproc/test/ocl/test_canny.cpp b/modules/imgproc/test/ocl/test_canny.cpp index 70e4bb1fcf..f9c724b049 100644 --- a/modules/imgproc/test/ocl/test_canny.cpp +++ b/modules/imgproc/test/ocl/test_canny.cpp @@ -54,13 +54,13 @@ namespace ocl { //////////////////////////////////////////////////////// // Canny -IMPLEMENT_PARAM_CLASS(AppertureSize, int) +IMPLEMENT_PARAM_CLASS(ApertureSize, int) IMPLEMENT_PARAM_CLASS(L2gradient, bool) IMPLEMENT_PARAM_CLASS(UseRoi, bool) -PARAM_TEST_CASE(Canny, Channels, AppertureSize, L2gradient, UseRoi) +PARAM_TEST_CASE(Canny, Channels, ApertureSize, L2gradient, UseRoi) { - int cn, apperture_size; + int cn, aperture_size; bool useL2gradient, use_roi; TEST_DECLARE_INPUT_PARAMETER(src); @@ -69,7 +69,7 @@ PARAM_TEST_CASE(Canny, Channels, AppertureSize, L2gradient, UseRoi) virtual void SetUp() { cn = GET_PARAM(0); - apperture_size = GET_PARAM(1); + aperture_size = GET_PARAM(1); useL2gradient = GET_PARAM(2); use_roi = GET_PARAM(3); } @@ -105,8 +105,31 @@ OCL_TEST_P(Canny, Accuracy) eps = 12e-3; #endif - OCL_OFF(cv::Canny(src_roi, dst_roi, low_thresh, high_thresh, apperture_size, useL2gradient)); - OCL_ON(cv::Canny(usrc_roi, udst_roi, low_thresh, high_thresh, apperture_size, useL2gradient)); + OCL_OFF(cv::Canny(src_roi, dst_roi, low_thresh, high_thresh, aperture_size, useL2gradient)); + OCL_ON(cv::Canny(usrc_roi, udst_roi, low_thresh, high_thresh, aperture_size, useL2gradient)); + + EXPECT_MAT_SIMILAR(dst_roi, udst_roi, eps); + EXPECT_MAT_SIMILAR(dst, udst, eps); +} + +OCL_TEST_P(Canny, AccuracyCustomGradient) +{ + generateTestData(); + + const double low_thresh = 50.0, high_thresh = 100.0; + double eps = 1e-2; +#ifdef ANDROID + if (cv::ocl::Device::getDefault().isNVidia()) + eps = 12e-3; +#endif + + OCL_OFF(cv::Canny(src_roi, dst_roi, low_thresh, high_thresh, aperture_size, useL2gradient)); + OCL_ON( + UMat dx, dy; + Sobel(usrc_roi, dx, CV_16S, 1, 0, aperture_size, 1, 0, BORDER_REPLICATE); + Sobel(usrc_roi, dy, CV_16S, 0, 1, aperture_size, 1, 0, BORDER_REPLICATE); + cv::Canny(dx, dy, udst_roi, low_thresh, high_thresh, useL2gradient); + ); EXPECT_MAT_SIMILAR(dst_roi, udst_roi, eps); EXPECT_MAT_SIMILAR(dst, udst, eps); @@ -114,7 +137,7 @@ OCL_TEST_P(Canny, Accuracy) OCL_INSTANTIATE_TEST_CASE_P(ImgProc, Canny, testing::Combine( testing::Values(1, 3), - testing::Values(AppertureSize(3), AppertureSize(5)), + testing::Values(ApertureSize(3), ApertureSize(5)), testing::Values(L2gradient(false), L2gradient(true)), testing::Values(UseRoi(false), UseRoi(true)))); diff --git a/modules/imgproc/test/test_canny.cpp b/modules/imgproc/test/test_canny.cpp index 15b9ea5b1c..db4a82bf9d 100644 --- a/modules/imgproc/test/test_canny.cpp +++ b/modules/imgproc/test/test_canny.cpp @@ -47,7 +47,7 @@ using namespace std; class CV_CannyTest : public cvtest::ArrayTest { public: - CV_CannyTest(); + CV_CannyTest(bool custom_deriv = false); protected: void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); @@ -61,10 +61,11 @@ protected: bool use_true_gradient; double threshold1, threshold2; bool test_cpp; + bool test_custom_deriv; }; -CV_CannyTest::CV_CannyTest() +CV_CannyTest::CV_CannyTest(bool custom_deriv) { test_array[INPUT].push_back(NULL); test_array[OUTPUT].push_back(NULL); @@ -75,6 +76,7 @@ CV_CannyTest::CV_CannyTest() threshold1 = threshold2 = 0; test_cpp = false; + test_custom_deriv = custom_deriv; } @@ -99,6 +101,9 @@ void CV_CannyTest::get_test_array_types_and_sizes( int test_case_idx, use_true_gradient = cvtest::randInt(rng) % 2 != 0; test_cpp = (cvtest::randInt(rng) & 256) == 0; + + ts->printf(cvtest::TS::LOG, "Canny(size = %d x %d, aperture_size = %d, threshold1 = %g, threshold2 = %g, L2 = %s) test_cpp = %s (test case #%d)\n", + sizes[0][0].width, sizes[0][0].height, aperture_size, threshold1, threshold2, use_true_gradient ? "TRUE" : "FALSE", test_cpp ? "TRUE" : "FALSE", test_case_idx); } @@ -123,9 +128,24 @@ double CV_CannyTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, void CV_CannyTest::run_func() { - if(!test_cpp) + if (test_custom_deriv) + { + cv::Mat _out = cv::cvarrToMat(test_array[OUTPUT][0]); + cv::Mat src = cv::cvarrToMat(test_array[INPUT][0]); + cv::Mat dx, dy; + int m = aperture_size; + Point anchor(m/2, m/2); + Mat dxkernel = cvtest::calcSobelKernel2D( 1, 0, m, 0 ); + Mat dykernel = cvtest::calcSobelKernel2D( 0, 1, m, 0 ); + cvtest::filter2D(src, dx, CV_16S, dxkernel, anchor, 0, BORDER_REPLICATE); + cvtest::filter2D(src, dy, CV_16S, dykernel, anchor, 0, BORDER_REPLICATE); + cv::Canny(dx, dy, _out, threshold1, threshold2, use_true_gradient); + } + else if(!test_cpp) + { cvCanny( test_array[INPUT][0], test_array[OUTPUT][0], threshold1, threshold2, aperture_size + (use_true_gradient ? CV_CANNY_L2_GRADIENT : 0)); + } else { cv::Mat _out = cv::cvarrToMat(test_array[OUTPUT][0]); @@ -283,5 +303,6 @@ int CV_CannyTest::validate_test_results( int test_case_idx ) } TEST(Imgproc_Canny, accuracy) { CV_CannyTest test; test.safe_run(); } +TEST(Imgproc_Canny, accuracy_deriv) { CV_CannyTest test(true); test.safe_run(); } /* End of file. */ diff --git a/modules/ts/include/opencv2/ts/ocl_test.hpp b/modules/ts/include/opencv2/ts/ocl_test.hpp index 2dac2110e9..2e65a365d9 100644 --- a/modules/ts/include/opencv2/ts/ocl_test.hpp +++ b/modules/ts/include/opencv2/ts/ocl_test.hpp @@ -349,8 +349,8 @@ IMPLEMENT_PARAM_CLASS(Channels, int) #define OCL_TEST_F(name, ...) typedef name OCL_##name; TEST_F(OCL_##name, __VA_ARGS__) #define OCL_TEST(name, ...) TEST(OCL_##name, __VA_ARGS__) -#define OCL_OFF(fn) cv::ocl::setUseOpenCL(false); fn -#define OCL_ON(fn) cv::ocl::setUseOpenCL(true); fn +#define OCL_OFF(...) cv::ocl::setUseOpenCL(false); __VA_ARGS__ ; +#define OCL_ON(...) cv::ocl::setUseOpenCL(true); __VA_ARGS__ ; #define OCL_ALL_DEPTHS Values(CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F) #define OCL_ALL_CHANNELS Values(1, 2, 3, 4)