From 9eea9835ab2802ae2b531c1098a44e3127f27190 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Mon, 29 Apr 2013 18:01:57 +0400 Subject: [PATCH 01/17] switched to Input/Output Array in Color Processing --- .../gpuimgproc/include/opencv2/gpuimgproc.hpp | 10 +- modules/gpuimgproc/src/color.cpp | 1069 ++++++++++------- modules/gpuoptflow/src/needle_map.cpp | 2 +- modules/superres/src/input_array_utility.cpp | 2 +- samples/gpu/brox_optical_flow.cpp | 4 +- samples/gpu/cascadeclassifier.cpp | 2 +- samples/gpu/generalized_hough.cpp | 2 +- samples/gpu/houghlines.cpp | 2 +- samples/gpu/pyrlk_optical_flow.cpp | 4 +- 9 files changed, 674 insertions(+), 423 deletions(-) diff --git a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp index 3fe9f82f4c..9f3dd96f94 100644 --- a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp +++ b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp @@ -57,7 +57,7 @@ namespace cv { namespace gpu { /////////////////////////// Color Processing /////////////////////////// //! converts image from one color space to another -CV_EXPORTS void cvtColor(const GpuMat& src, GpuMat& dst, int code, int dcn = 0, Stream& stream = Stream::Null()); +CV_EXPORTS void cvtColor(InputArray src, OutputArray dst, int code, int dcn = 0, Stream& stream = Stream::Null()); enum { @@ -77,24 +77,24 @@ enum COLOR_BayerRG2GRAY_MHT = 262, COLOR_BayerGR2GRAY_MHT = 263 }; -CV_EXPORTS void demosaicing(const GpuMat& src, GpuMat& dst, int code, int dcn = -1, Stream& stream = Stream::Null()); +CV_EXPORTS void demosaicing(InputArray src, OutputArray dst, int code, int dcn = -1, Stream& stream = Stream::Null()); //! swap channels //! dstOrder - Integer array describing how channel values are permutated. The n-th entry //! of the array contains the number of the channel that is stored in the n-th channel of //! the output image. E.g. Given an RGBA image, aDstOrder = [3,2,1,0] converts this to ABGR //! channel order. -CV_EXPORTS void swapChannels(GpuMat& image, const int dstOrder[4], Stream& stream = Stream::Null()); +CV_EXPORTS void swapChannels(InputOutputArray image, const int dstOrder[4], Stream& stream = Stream::Null()); //! Routines for correcting image color gamma -CV_EXPORTS void gammaCorrection(const GpuMat& src, GpuMat& dst, bool forward = true, Stream& stream = Stream::Null()); +CV_EXPORTS void gammaCorrection(InputArray src, OutputArray dst, bool forward = true, Stream& stream = Stream::Null()); enum { ALPHA_OVER, ALPHA_IN, ALPHA_OUT, ALPHA_ATOP, ALPHA_XOR, ALPHA_PLUS, ALPHA_OVER_PREMUL, ALPHA_IN_PREMUL, ALPHA_OUT_PREMUL, ALPHA_ATOP_PREMUL, ALPHA_XOR_PREMUL, ALPHA_PLUS_PREMUL, ALPHA_PREMUL}; //! Composite two images using alpha opacity values contained in each image //! Supports CV_8UC4, CV_16UC4, CV_32SC4 and CV_32FC4 types -CV_EXPORTS void alphaComp(const GpuMat& img1, const GpuMat& img2, GpuMat& dst, int alpha_op, Stream& stream = Stream::Null()); +CV_EXPORTS void alphaComp(InputArray img1, InputArray img2, OutputArray dst, int alpha_op, Stream& stream = Stream::Null()); ////////////////////////////// Histogram /////////////////////////////// diff --git a/modules/gpuimgproc/src/color.cpp b/modules/gpuimgproc/src/color.cpp index c1af7ce750..006274742e 100644 --- a/modules/gpuimgproc/src/color.cpp +++ b/modules/gpuimgproc/src/color.cpp @@ -47,15 +47,16 @@ using namespace cv::gpu; #if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) -void cv::gpu::cvtColor(const GpuMat&, GpuMat&, int, int, Stream&) { throw_no_cuda(); } +void cv::gpu::cvtColor(InputArray, OutputArray, int, int, Stream&) { throw_no_cuda(); } -void cv::gpu::demosaicing(const GpuMat&, GpuMat&, int, int, Stream&) { throw_no_cuda(); } +void cv::gpu::demosaicing(InputArray, OutputArray, int, int, Stream&) { throw_no_cuda(); } -void cv::gpu::swapChannels(GpuMat&, const int[], Stream&) { throw_no_cuda(); } +void cv::gpu::swapChannels(InputOutputArray, const int[], Stream&) { throw_no_cuda(); } -void cv::gpu::gammaCorrection(const GpuMat&, GpuMat&, bool, Stream&) { throw_no_cuda(); } +void cv::gpu::gammaCorrection(InputArray, OutputArray, bool, Stream&) { throw_no_cuda(); } + +void cv::gpu::alphaComp(InputArray, InputArray, OutputArray, int, Stream&) { throw_no_cuda(); } -void cv::gpu::alphaComp(const GpuMat&, const GpuMat&, GpuMat&, int, Stream&) { throw_no_cuda(); } #else /* !defined (HAVE_CUDA) */ @@ -80,363 +81,459 @@ namespace { typedef void (*gpu_func_t)(PtrStepSzb src, PtrStepSzb dst, cudaStream_t stream); - void bgr_to_rgb(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgr_to_rgb(InputArray _src, OutputArray _dst, int, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[] = {bgr_to_rgb_8u, 0, bgr_to_rgb_16u, 0, 0, bgr_to_rgb_32f}; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), 3)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), 3)); + GpuMat dst = _dst.getGpuMat(); funcs[src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void bgr_to_bgra(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgr_to_bgra(InputArray _src, OutputArray _dst, int, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[] = {bgr_to_bgra_8u, 0, bgr_to_bgra_16u, 0, 0, bgr_to_bgra_32f}; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), 4)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), 4)); + GpuMat dst = _dst.getGpuMat(); funcs[src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void bgr_to_rgba(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgr_to_rgba(InputArray _src, OutputArray _dst, int, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[] = {bgr_to_rgba_8u, 0, bgr_to_rgba_16u, 0, 0, bgr_to_rgba_32f}; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKETYPE(src.depth(), 4)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), 4)); + GpuMat dst = _dst.getGpuMat(); funcs[src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void bgra_to_bgr(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgra_to_bgr(InputArray _src, OutputArray _dst, int, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[] = {bgra_to_bgr_8u, 0, bgra_to_bgr_16u, 0, 0, bgra_to_bgr_32f}; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), 3)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), 3)); + GpuMat dst = _dst.getGpuMat(); funcs[src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void bgra_to_rgb(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgra_to_rgb(InputArray _src, OutputArray _dst, int, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[] = {bgra_to_rgb_8u, 0, bgra_to_rgb_16u, 0, 0, bgra_to_rgb_32f}; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKETYPE(src.depth(), 3)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), 3)); + GpuMat dst = _dst.getGpuMat(); funcs[src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void bgra_to_rgba(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgra_to_rgba(InputArray _src, OutputArray _dst, int, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[] = {bgra_to_rgba_8u, 0, bgra_to_rgba_16u, 0, 0, bgra_to_rgba_32f}; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), 4)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), 4)); + GpuMat dst = _dst.getGpuMat(); funcs[src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void bgr_to_bgr555(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgr_to_bgr555(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 3); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_8UC2); + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 3 ); + + _dst.create(src.size(), CV_8UC2); + GpuMat dst = _dst.getGpuMat(); cudev::bgr_to_bgr555(src, dst, StreamAccessor::getStream(stream)); } - void bgr_to_bgr565(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgr_to_bgr565(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 3); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 3 ); - dst.create(src.size(), CV_8UC2); + _dst.create(src.size(), CV_8UC2); + GpuMat dst = _dst.getGpuMat(); cudev::bgr_to_bgr565(src, dst, StreamAccessor::getStream(stream)); } - void rgb_to_bgr555(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void rgb_to_bgr555(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 3); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_8UC2); + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 3 ); + + _dst.create(src.size(), CV_8UC2); + GpuMat dst = _dst.getGpuMat(); cudev::rgb_to_bgr555(src, dst, StreamAccessor::getStream(stream)); } - void rgb_to_bgr565(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void rgb_to_bgr565(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 3); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 3 ); - dst.create(src.size(), CV_8UC2); + _dst.create(src.size(), CV_8UC2); + GpuMat dst = _dst.getGpuMat(); cudev::rgb_to_bgr565(src, dst, StreamAccessor::getStream(stream)); } - void bgra_to_bgr555(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgra_to_bgr555(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_8UC2); + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 4 ); + + _dst.create(src.size(), CV_8UC2); + GpuMat dst = _dst.getGpuMat(); cudev::bgra_to_bgr555(src, dst, StreamAccessor::getStream(stream)); } - void bgra_to_bgr565(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgra_to_bgr565(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 4 ); - dst.create(src.size(), CV_8UC2); + _dst.create(src.size(), CV_8UC2); + GpuMat dst = _dst.getGpuMat(); cudev::bgra_to_bgr565(src, dst, StreamAccessor::getStream(stream)); } - void rgba_to_bgr555(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void rgba_to_bgr555(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_8UC2); + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 4 ); + + _dst.create(src.size(), CV_8UC2); + GpuMat dst = _dst.getGpuMat(); cudev::rgba_to_bgr555(src, dst, StreamAccessor::getStream(stream)); } - void rgba_to_bgr565(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void rgba_to_bgr565(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 4 ); - dst.create(src.size(), CV_8UC2); + _dst.create(src.size(), CV_8UC2); + GpuMat dst = _dst.getGpuMat(); cudev::rgba_to_bgr565(src, dst, StreamAccessor::getStream(stream)); } - void bgr555_to_rgb(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgr555_to_rgb(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 2); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_8UC3); + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 2 ); + + _dst.create(src.size(), CV_8UC3); + GpuMat dst = _dst.getGpuMat(); cudev::bgr555_to_rgb(src, dst, StreamAccessor::getStream(stream)); } - void bgr565_to_rgb(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgr565_to_rgb(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 2); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 2 ); - dst.create(src.size(), CV_8UC3); + _dst.create(src.size(), CV_8UC3); + GpuMat dst = _dst.getGpuMat(); cudev::bgr565_to_rgb(src, dst, StreamAccessor::getStream(stream)); } - void bgr555_to_bgr(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgr555_to_bgr(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 2); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_8UC3); + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 2 ); + + _dst.create(src.size(), CV_8UC3); + GpuMat dst = _dst.getGpuMat(); cudev::bgr555_to_bgr(src, dst, StreamAccessor::getStream(stream)); } - void bgr565_to_bgr(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgr565_to_bgr(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 2); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 2 ); - dst.create(src.size(), CV_8UC3); + _dst.create(src.size(), CV_8UC3); + GpuMat dst = _dst.getGpuMat(); cudev::bgr565_to_bgr(src, dst, StreamAccessor::getStream(stream)); } - void bgr555_to_rgba(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgr555_to_rgba(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 2); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 2 ); - dst.create(src.size(), CV_8UC4); + _dst.create(src.size(), CV_8UC4); + GpuMat dst = _dst.getGpuMat(); cudev::bgr555_to_rgba(src, dst, StreamAccessor::getStream(stream)); } - void bgr565_to_rgba(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgr565_to_rgba(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 2); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_8UC4); + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 2 ); + + _dst.create(src.size(), CV_8UC4); + GpuMat dst = _dst.getGpuMat(); cudev::bgr565_to_rgba(src, dst, StreamAccessor::getStream(stream)); } - void bgr555_to_bgra(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgr555_to_bgra(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 2); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 2 ); - dst.create(src.size(), CV_8UC4); + _dst.create(src.size(), CV_8UC4); + GpuMat dst = _dst.getGpuMat(); cudev::bgr555_to_bgra(src, dst, StreamAccessor::getStream(stream)); } - void bgr565_to_bgra(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgr565_to_bgra(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 2); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_8UC4); + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 2 ); + + _dst.create(src.size(), CV_8UC4); + GpuMat dst = _dst.getGpuMat(); cudev::bgr565_to_bgra(src, dst, StreamAccessor::getStream(stream)); } - void gray_to_bgr(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void gray_to_bgr(InputArray _src, OutputArray _dst, int, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[] = {gray_to_bgr_8u, 0, gray_to_bgr_16u, 0, 0, gray_to_bgr_32f}; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 1); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 1 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), 3)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), 3)); + GpuMat dst = _dst.getGpuMat(); funcs[src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void gray_to_bgra(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void gray_to_bgra(InputArray _src, OutputArray _dst, int, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[] = {gray_to_bgra_8u, 0, gray_to_bgra_16u, 0, 0, gray_to_bgra_32f}; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 1); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKETYPE(src.depth(), 4)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 1 ); + + _dst.create(src.size(), CV_MAKETYPE(src.depth(), 4)); + GpuMat dst = _dst.getGpuMat(); funcs[src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void gray_to_bgr555(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void gray_to_bgr555(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 1); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 1 ); - dst.create(src.size(), CV_8UC2); + _dst.create(src.size(), CV_8UC2); + GpuMat dst = _dst.getGpuMat(); cudev::gray_to_bgr555(src, dst, StreamAccessor::getStream(stream)); } - void gray_to_bgr565(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void gray_to_bgr565(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 1); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_8UC2); + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 1 ); + + _dst.create(src.size(), CV_8UC2); + GpuMat dst = _dst.getGpuMat(); cudev::gray_to_bgr565(src, dst, StreamAccessor::getStream(stream)); } - void bgr555_to_gray(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgr555_to_gray(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 2); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 2 ); - dst.create(src.size(), CV_8UC1); + _dst.create(src.size(), CV_8UC1); + GpuMat dst = _dst.getGpuMat(); cudev::bgr555_to_gray(src, dst, StreamAccessor::getStream(stream)); } - void bgr565_to_gray(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgr565_to_gray(InputArray _src, OutputArray _dst, int, Stream& stream) { - CV_Assert(src.depth() == CV_8U); - CV_Assert(src.channels() == 2); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_8UC1); + CV_Assert( src.depth() == CV_8U ); + CV_Assert( src.channels() == 2 ); + + _dst.create(src.size(), CV_8UC1); + GpuMat dst = _dst.getGpuMat(); cudev::bgr565_to_gray(src, dst, StreamAccessor::getStream(stream)); } - void rgb_to_gray(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void rgb_to_gray(InputArray _src, OutputArray _dst, int, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[] = {rgb_to_gray_8u, 0, rgb_to_gray_16u, 0, 0, rgb_to_gray_32f}; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), 1)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), 1)); + GpuMat dst = _dst.getGpuMat(); funcs[src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void bgr_to_gray(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgr_to_gray(InputArray _src, OutputArray _dst, int, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[] = {bgr_to_gray_8u, 0, bgr_to_gray_16u, 0, 0, bgr_to_gray_32f}; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKETYPE(src.depth(), 1)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), 1)); + GpuMat dst = _dst.getGpuMat(); funcs[src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void rgba_to_gray(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void rgba_to_gray(InputArray _src, OutputArray _dst, int, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[] = {rgba_to_gray_8u, 0, rgba_to_gray_16u, 0, 0, rgba_to_gray_32f}; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), 1)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), 1)); + GpuMat dst = _dst.getGpuMat(); funcs[src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void bgra_to_gray(const GpuMat& src, GpuMat& dst, int, Stream& stream) + void bgra_to_gray(InputArray _src, OutputArray _dst, int, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[] = {bgra_to_gray_8u, 0, bgra_to_gray_16u, 0, 0, bgra_to_gray_32f}; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKETYPE(src.depth(), 1)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), 1)); + GpuMat dst = _dst.getGpuMat(); funcs[src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void rgb_to_yuv(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void rgb_to_yuv(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -453,16 +550,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void bgr_to_yuv(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void bgr_to_yuv(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -479,16 +579,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void yuv_to_rgb(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void yuv_to_rgb(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -505,16 +608,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void yuv_to_bgr(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void yuv_to_bgr(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -531,16 +637,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void rgb_to_YCrCb(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void rgb_to_YCrCb(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -557,16 +666,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void bgr_to_YCrCb(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void bgr_to_YCrCb(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -583,16 +695,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void YCrCb_to_rgb(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void YCrCb_to_rgb(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -609,16 +724,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void YCrCb_to_bgr(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void YCrCb_to_bgr(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -635,16 +753,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void rgb_to_xyz(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void rgb_to_xyz(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -661,16 +782,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void bgr_to_xyz(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void bgr_to_xyz(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -687,16 +811,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void xyz_to_rgb(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void xyz_to_rgb(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -713,16 +840,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void xyz_to_bgr(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void xyz_to_bgr(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -739,16 +869,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_16U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void rgb_to_hsv(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void rgb_to_hsv(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -765,16 +898,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void bgr_to_hsv(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void bgr_to_hsv(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -791,16 +927,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void hsv_to_rgb(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void hsv_to_rgb(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -817,16 +956,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void hsv_to_bgr(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void hsv_to_bgr(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -843,16 +985,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void rgb_to_hls(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void rgb_to_hls(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -869,16 +1014,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void bgr_to_hls(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void bgr_to_hls(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -895,16 +1043,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void hls_to_rgb(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void hls_to_rgb(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -921,16 +1072,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void hls_to_bgr(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void hls_to_bgr(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -947,16 +1101,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void rgb_to_hsv_full(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void rgb_to_hsv_full(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -973,16 +1130,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void bgr_to_hsv_full(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void bgr_to_hsv_full(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -999,16 +1159,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void hsv_to_rgb_full(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void hsv_to_rgb_full(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -1025,16 +1188,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void hsv_to_bgr_full(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void hsv_to_bgr_full(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -1051,16 +1217,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void rgb_to_hls_full(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void rgb_to_hls_full(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -1077,16 +1246,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void bgr_to_hls_full(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void bgr_to_hls_full(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -1103,16 +1275,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void hls_to_rgb_full(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void hls_to_rgb_full(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -1129,16 +1304,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void hls_to_bgr_full(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void hls_to_bgr_full(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][6] = @@ -1155,16 +1333,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth()](src, dst, StreamAccessor::getStream(stream)); } - void bgr_to_lab(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void bgr_to_lab(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][2] = @@ -1181,16 +1362,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth() == CV_32F](src, dst, StreamAccessor::getStream(stream)); } - void rgb_to_lab(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void rgb_to_lab(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][2] = @@ -1207,16 +1391,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth() == CV_32F](src, dst, StreamAccessor::getStream(stream)); } - void lbgr_to_lab(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void lbgr_to_lab(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][2] = @@ -1233,16 +1420,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth() == CV_32F](src, dst, StreamAccessor::getStream(stream)); } - void lrgb_to_lab(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void lrgb_to_lab(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][2] = @@ -1259,16 +1449,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth() == CV_32F](src, dst, StreamAccessor::getStream(stream)); } - void lab_to_bgr(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void lab_to_bgr(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][2] = @@ -1285,16 +1478,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth() == CV_32F](src, dst, StreamAccessor::getStream(stream)); } - void lab_to_rgb(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void lab_to_rgb(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][2] = @@ -1311,16 +1507,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth() == CV_32F](src, dst, StreamAccessor::getStream(stream)); } - void lab_to_lbgr(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void lab_to_lbgr(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][2] = @@ -1337,16 +1536,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth() == CV_32F](src, dst, StreamAccessor::getStream(stream)); } - void lab_to_lrgb(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void lab_to_lrgb(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][2] = @@ -1363,16 +1565,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth() == CV_32F](src, dst, StreamAccessor::getStream(stream)); } - void bgr_to_luv(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void bgr_to_luv(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][2] = @@ -1389,16 +1594,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth() == CV_32F](src, dst, StreamAccessor::getStream(stream)); } - void rgb_to_luv(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void rgb_to_luv(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][2] = @@ -1415,16 +1623,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth() == CV_32F](src, dst, StreamAccessor::getStream(stream)); } - void lbgr_to_luv(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void lbgr_to_luv(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][2] = @@ -1441,16 +1652,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth() == CV_32F](src, dst, StreamAccessor::getStream(stream)); } - void lrgb_to_luv(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void lrgb_to_luv(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][2] = @@ -1467,16 +1681,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth() == CV_32F](src, dst, StreamAccessor::getStream(stream)); } - void luv_to_bgr(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void luv_to_bgr(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][2] = @@ -1493,16 +1710,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth() == CV_32F](src, dst, StreamAccessor::getStream(stream)); } - void luv_to_rgb(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void luv_to_rgb(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][2] = @@ -1519,16 +1739,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth() == CV_32F](src, dst, StreamAccessor::getStream(stream)); } - void luv_to_lbgr(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void luv_to_lbgr(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][2] = @@ -1545,16 +1768,19 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth() == CV_32F](src, dst, StreamAccessor::getStream(stream)); } - void luv_to_lrgb(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void luv_to_lrgb(InputArray _src, OutputArray _dst, int dcn, Stream& stream) { using namespace cv::gpu::cudev; static const gpu_func_t funcs[2][2][2] = @@ -1571,28 +1797,34 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F); - CV_Assert(src.channels() == 3 || src.channels() == 4); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + CV_Assert( src.depth() == CV_8U || src.depth() == CV_32F ); + CV_Assert( src.channels() == 3 || src.channels() == 4 ); + CV_Assert( dcn == 3 || dcn == 4 ); + + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[dcn == 4][src.channels() == 4][src.depth() == CV_32F](src, dst, StreamAccessor::getStream(stream)); } - void rgba_to_mbgra(const GpuMat& src, GpuMat& dst, int, Stream& st) + void rgba_to_mbgra(InputArray _src, OutputArray _dst, int, Stream& _stream) { #if (CUDA_VERSION < 5000) - (void)src; - (void)dst; - (void)st; + (void) _src; + (void) _dst; + (void) _stream; CV_Error( Error::StsBadFlag, "Unknown/unsupported color conversion code" ); #else - CV_Assert(src.type() == CV_8UC4 || src.type() == CV_16UC4); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), src.type()); + CV_Assert( src.type() == CV_8UC4 || src.type() == CV_16UC4 ); - cudaStream_t stream = StreamAccessor::getStream(st); + _dst.create(src.size(), src.type()); + GpuMat dst = _dst.getGpuMat(); + + cudaStream_t stream = StreamAccessor::getStream(_stream); NppStreamHandler h(stream); NppiSize oSizeROI; @@ -1609,7 +1841,7 @@ namespace #endif } - void bayer_to_bgr(const GpuMat& src, GpuMat& dst, int dcn, bool blue_last, bool start_with_green, Stream& stream) + void bayer_to_bgr(InputArray _src, OutputArray _dst, int dcn, bool blue_last, bool start_with_green, Stream& stream) { typedef void (*func_t)(PtrStepSzb src, PtrStepSzb dst, bool blue_last, bool start_with_green, cudaStream_t stream); static const func_t funcs[3][4] = @@ -1621,32 +1853,35 @@ namespace if (dcn <= 0) dcn = 3; - CV_Assert(src.type() == CV_8UC1 || src.type() == CV_16UC1); - CV_Assert(src.rows > 2 && src.cols > 2); - CV_Assert(dcn == 3 || dcn == 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.type() == CV_8UC1 || src.type() == CV_16UC1 ); + CV_Assert( src.rows > 2 && src.cols > 2 ); + CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), dcn)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), dcn)); + GpuMat dst = _dst.getGpuMat(); funcs[src.depth()][dcn - 1](src, dst, blue_last, start_with_green, StreamAccessor::getStream(stream)); } - void bayerBG_to_bgr(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void bayerBG_to_bgr(InputArray src, OutputArray dst, int dcn, Stream& stream) { bayer_to_bgr(src, dst, dcn, false, false, stream); } - void bayerGB_to_bgr(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void bayerGB_to_bgr(InputArray src, OutputArray dst, int dcn, Stream& stream) { bayer_to_bgr(src, dst, dcn, false, true, stream); } - void bayerRG_to_bgr(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void bayerRG_to_bgr(InputArray src, OutputArray dst, int dcn, Stream& stream) { bayer_to_bgr(src, dst, dcn, true, false, stream); } - void bayerGR_to_bgr(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream) + void bayerGR_to_bgr(InputArray src, OutputArray dst, int dcn, Stream& stream) { bayer_to_bgr(src, dst, dcn, true, true, stream); } - void bayer_to_gray(const GpuMat& src, GpuMat& dst, bool blue_last, bool start_with_green, Stream& stream) + void bayer_to_gray(InputArray _src, OutputArray _dst, bool blue_last, bool start_with_green, Stream& stream) { typedef void (*func_t)(PtrStepSzb src, PtrStepSzb dst, bool blue_last, bool start_with_green, cudaStream_t stream); static const func_t funcs[3] = @@ -1656,26 +1891,29 @@ namespace Bayer2BGR_16u_gpu<1>, }; - CV_Assert(src.type() == CV_8UC1 || src.type() == CV_16UC1); - CV_Assert(src.rows > 2 && src.cols > 2); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.type() == CV_8UC1 || src.type() == CV_16UC1 ); + CV_Assert( src.rows > 2 && src.cols > 2 ); - dst.create(src.size(), CV_MAKETYPE(src.depth(), 1)); + _dst.create(src.size(), CV_MAKE_TYPE(src.depth(), 1)); + GpuMat dst = _dst.getGpuMat(); funcs[src.depth()](src, dst, blue_last, start_with_green, StreamAccessor::getStream(stream)); } - void bayerBG_to_gray(const GpuMat& src, GpuMat& dst, int /*dcn*/, Stream& stream) + void bayerBG_to_gray(InputArray src, OutputArray dst, int /*dcn*/, Stream& stream) { bayer_to_gray(src, dst, false, false, stream); } - void bayerGB_to_gray(const GpuMat& src, GpuMat& dst, int /*dcn*/, Stream& stream) + void bayerGB_to_gray(InputArray src, OutputArray dst, int /*dcn*/, Stream& stream) { bayer_to_gray(src, dst, false, true, stream); } - void bayerRG_to_gray(const GpuMat& src, GpuMat& dst, int /*dcn*/, Stream& stream) + void bayerRG_to_gray(InputArray src, OutputArray dst, int /*dcn*/, Stream& stream) { bayer_to_gray(src, dst, true, false, stream); } - void bayerGR_to_gray(const GpuMat& src, GpuMat& dst, int /*dcn*/, Stream& stream) + void bayerGR_to_gray(InputArray src, OutputArray dst, int /*dcn*/, Stream& stream) { bayer_to_gray(src, dst, true, true, stream); } @@ -1684,9 +1922,9 @@ namespace //////////////////////////////////////////////////////////////////////// // cvtColor -void cv::gpu::cvtColor(const GpuMat& src, GpuMat& dst, int code, int dcn, Stream& stream) +void cv::gpu::cvtColor(InputArray src, OutputArray dst, int code, int dcn, Stream& stream) { - typedef void (*func_t)(const GpuMat& src, GpuMat& dst, int dcn, Stream& stream); + typedef void (*func_t)(InputArray src, OutputArray dst, int dcn, Stream& stream); static const func_t funcs[] = { bgr_to_bgra, // CV_BGR2BGRA =0 @@ -1857,12 +2095,12 @@ void cv::gpu::cvtColor(const GpuMat& src, GpuMat& dst, int code, int dcn, Stream 0, // CV_COLORCVT_MAX = 127 }; - CV_Assert(code < 128); + CV_Assert( code < 128 ); func_t func = funcs[code]; if (func == 0) - CV_Error( cv::Error::StsBadFlag, "Unknown/unsupported color conversion code" ); + CV_Error(Error::StsBadFlag, "Unknown/unsupported color conversion code"); func(src, dst, dcn, stream); } @@ -1870,32 +2108,33 @@ void cv::gpu::cvtColor(const GpuMat& src, GpuMat& dst, int code, int dcn, Stream //////////////////////////////////////////////////////////////////////// // demosaicing -void cv::gpu::demosaicing(const GpuMat& src, GpuMat& dst, int code, int dcn, Stream& stream) +void cv::gpu::demosaicing(InputArray _src, OutputArray _dst, int code, int dcn, Stream& stream) { - const int depth = src.depth(); - - CV_Assert( src.channels() == 1 ); - switch (code) { case cv::COLOR_BayerBG2GRAY: case cv::COLOR_BayerGB2GRAY: case cv::COLOR_BayerRG2GRAY: case cv::COLOR_BayerGR2GRAY: - bayer_to_gray(src, dst, code == cv::COLOR_BayerBG2GRAY || code == cv::COLOR_BayerGB2GRAY, code == cv::COLOR_BayerGB2GRAY || code == cv::COLOR_BayerGR2GRAY, stream); + bayer_to_gray(_src, _dst, code == cv::COLOR_BayerBG2GRAY || code == cv::COLOR_BayerGB2GRAY, code == cv::COLOR_BayerGB2GRAY || code == cv::COLOR_BayerGR2GRAY, stream); break; case cv::COLOR_BayerBG2BGR: case cv::COLOR_BayerGB2BGR: case cv::COLOR_BayerRG2BGR: case cv::COLOR_BayerGR2BGR: - bayer_to_bgr(src, dst, dcn, code == cv::COLOR_BayerBG2BGR || code == cv::COLOR_BayerGB2BGR, code == cv::COLOR_BayerGB2BGR || code == cv::COLOR_BayerGR2BGR, stream); + bayer_to_bgr(_src, _dst, dcn, code == cv::COLOR_BayerBG2BGR || code == cv::COLOR_BayerGB2BGR, code == cv::COLOR_BayerGB2BGR || code == cv::COLOR_BayerGR2BGR, stream); break; case COLOR_BayerBG2BGR_MHT: case COLOR_BayerGB2BGR_MHT: case COLOR_BayerRG2BGR_MHT: case COLOR_BayerGR2BGR_MHT: { - if (dcn <= 0) - dcn = 3; + if (dcn <= 0) dcn = 3; + + GpuMat src = _src.getGpuMat(); + const int depth = _src.depth(); CV_Assert( depth == CV_8U ); + CV_Assert( src.channels() == 1 ); CV_Assert( dcn == 3 || dcn == 4 ); - dst.create(src.size(), CV_MAKETYPE(depth, dcn)); - dst.setTo(Scalar::all(0)); + _dst.create(_src.size(), CV_MAKE_TYPE(depth, dcn)); + GpuMat dst = _dst.getGpuMat(); + + dst.setTo(Scalar::all(0), stream); Size wholeSize; Point ofs; @@ -1915,10 +2154,15 @@ void cv::gpu::demosaicing(const GpuMat& src, GpuMat& dst, int code, int dcn, Str case COLOR_BayerBG2GRAY_MHT: case COLOR_BayerGB2GRAY_MHT: case COLOR_BayerRG2GRAY_MHT: case COLOR_BayerGR2GRAY_MHT: { + GpuMat src = _src.getGpuMat(); + const int depth = _src.depth(); + CV_Assert( depth == CV_8U ); - dst.create(src.size(), CV_MAKETYPE(depth, 1)); - dst.setTo(Scalar::all(0)); + _dst.create(_src.size(), CV_MAKE_TYPE(depth, 1)); + GpuMat dst = _dst.getGpuMat(); + + dst.setTo(Scalar::all(0), stream); Size wholeSize; Point ofs; @@ -1934,19 +2178,20 @@ void cv::gpu::demosaicing(const GpuMat& src, GpuMat& dst, int code, int dcn, Str } default: - CV_Error( cv::Error::StsBadFlag, "Unknown / unsupported color conversion code" ); + CV_Error(Error::StsBadFlag, "Unknown / unsupported color conversion code"); } } //////////////////////////////////////////////////////////////////////// // swapChannels -void cv::gpu::swapChannels(GpuMat& image, const int dstOrder[4], Stream& s) +void cv::gpu::swapChannels(InputOutputArray _image, const int dstOrder[4], Stream& _stream) { - CV_Assert(image.type() == CV_8UC4); + GpuMat image = _image.getGpuMat(); - cudaStream_t stream = StreamAccessor::getStream(s); + CV_Assert( image.type() == CV_8UC4 ); + cudaStream_t stream = StreamAccessor::getStream(_stream); NppStreamHandler h(stream); NppiSize sz; @@ -1962,14 +2207,14 @@ void cv::gpu::swapChannels(GpuMat& image, const int dstOrder[4], Stream& s) //////////////////////////////////////////////////////////////////////// // gammaCorrection -void cv::gpu::gammaCorrection(const GpuMat& src, GpuMat& dst, bool forward, Stream& stream) +void cv::gpu::gammaCorrection(InputArray _src, OutputArray _dst, bool forward, Stream& stream) { #if (CUDA_VERSION < 5000) - (void)src; - (void)dst; - (void)forward; - (void)stream; - CV_Error( cv::Error::StsNotImplemented, "This function works only with CUDA 5.0 or higher" ); + (void) _src; + (void) _dst; + (void) forward; + (void) stream; + CV_Error(Error::StsNotImplemented, "This function works only with CUDA 5.0 or higher"); #else typedef NppStatus (*func_t)(const Npp8u* pSrc, int nSrcStep, Npp8u* pDst, int nDstStep, NppiSize oSizeROI); typedef NppStatus (*func_inplace_t)(Npp8u* pSrcDst, int nSrcDstStep, NppiSize oSizeROI); @@ -1985,9 +2230,12 @@ void cv::gpu::gammaCorrection(const GpuMat& src, GpuMat& dst, bool forward, Stre {0, 0, 0, nppiGammaFwd_8u_C3IR, nppiGammaFwd_8u_AC4IR} }; - CV_Assert(src.type() == CV_8UC3 || src.type() == CV_8UC4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.type() == CV_8UC3 || src.type() == CV_8UC4 ); - dst.create(src.size(), src.type()); + _dst.create(src.size(), src.type()); + GpuMat dst = _dst.getGpuMat(); NppStreamHandler h(StreamAccessor::getStream(stream)); @@ -2036,7 +2284,7 @@ namespace }; } -void cv::gpu::alphaComp(const GpuMat& img1, const GpuMat& img2, GpuMat& dst, int alpha_op, Stream& stream) +void cv::gpu::alphaComp(InputArray _img1, InputArray _img2, OutputArray _dst, int alpha_op, Stream& stream) { static const NppiAlphaOp npp_alpha_ops[] = { NPPI_OP_ALPHA_OVER, @@ -2055,7 +2303,6 @@ void cv::gpu::alphaComp(const GpuMat& img1, const GpuMat& img2, GpuMat& dst, int }; typedef void (*func_t)(const GpuMat& img1, const GpuMat& img2, GpuMat& dst, NppiAlphaOp eAlphaOp, cudaStream_t stream); - static const func_t funcs[] = { NppAlphaComp::call, @@ -2066,10 +2313,14 @@ void cv::gpu::alphaComp(const GpuMat& img1, const GpuMat& img2, GpuMat& dst, int NppAlphaComp::call }; + GpuMat img1 = _img1.getGpuMat(); + GpuMat img2 = _img2.getGpuMat(); + CV_Assert( img1.type() == CV_8UC4 || img1.type() == CV_16UC4 || img1.type() == CV_32SC4 || img1.type() == CV_32FC4 ); CV_Assert( img1.size() == img2.size() && img1.type() == img2.type() ); - dst.create(img1.size(), img1.type()); + _dst.create(img1.size(), img1.type()); + GpuMat dst = _dst.getGpuMat(); const func_t func = funcs[img1.depth()]; diff --git a/modules/gpuoptflow/src/needle_map.cpp b/modules/gpuoptflow/src/needle_map.cpp index 1fdc162628..9ca8fe5e44 100644 --- a/modules/gpuoptflow/src/needle_map.cpp +++ b/modules/gpuoptflow/src/needle_map.cpp @@ -94,7 +94,7 @@ void cv::gpu::createOpticalFlowNeedleMap(const GpuMat& u, const GpuMat& v, GpuMa CreateOpticalFlowNeedleMap_gpu(u_avg, v_avg, vertex.ptr(), colors.ptr(), max_flow, 1.0f / u.cols, 1.0f / u.rows); - cvtColor(colors, colors, COLOR_HSV2RGB); + gpu::cvtColor(colors, colors, COLOR_HSV2RGB); } #endif /* HAVE_CUDA */ diff --git a/modules/superres/src/input_array_utility.cpp b/modules/superres/src/input_array_utility.cpp index e749050895..3de3e1e5a8 100644 --- a/modules/superres/src/input_array_utility.cpp +++ b/modules/superres/src/input_array_utility.cpp @@ -169,7 +169,7 @@ namespace break; default: - cvtColor(src, dst, code, cn); + cv::cvtColor(src, dst, code, cn); break; } } diff --git a/samples/gpu/brox_optical_flow.cpp b/samples/gpu/brox_optical_flow.cpp index 1d92e4b3ff..1fb85c9038 100644 --- a/samples/gpu/brox_optical_flow.cpp +++ b/samples/gpu/brox_optical_flow.cpp @@ -85,8 +85,8 @@ int main(int argc, const char* argv[]) Mat frame0Gray, frame1Gray; - cvtColor(frame0Color, frame0Gray, COLOR_BGR2GRAY); - cvtColor(frame1Color, frame1Gray, COLOR_BGR2GRAY); + cv::cvtColor(frame0Color, frame0Gray, COLOR_BGR2GRAY); + cv::cvtColor(frame1Color, frame1Gray, COLOR_BGR2GRAY); GpuMat d_frame0(frame0Gray); GpuMat d_frame1(frame1Gray); diff --git a/samples/gpu/cascadeclassifier.cpp b/samples/gpu/cascadeclassifier.cpp index 942a964d5a..929fd3085e 100644 --- a/samples/gpu/cascadeclassifier.cpp +++ b/samples/gpu/cascadeclassifier.cpp @@ -294,7 +294,7 @@ int main(int argc, const char *argv[]) } cout << endl; - cvtColor(resized_cpu, frameDisp, COLOR_GRAY2BGR); + cv::cvtColor(resized_cpu, frameDisp, COLOR_GRAY2BGR); displayState(frameDisp, helpScreen, useGPU, findLargestObject, filterRects, fps); imshow("result", frameDisp); diff --git a/samples/gpu/generalized_hough.cpp b/samples/gpu/generalized_hough.cpp index c8fae7c411..a8f7cc67cc 100644 --- a/samples/gpu/generalized_hough.cpp +++ b/samples/gpu/generalized_hough.cpp @@ -181,7 +181,7 @@ int main(int argc, const char* argv[]) cout << "Detection time : " << tm.getTimeMilli() << " ms" << endl; Mat out; - cvtColor(image, out, COLOR_GRAY2BGR); + cv::cvtColor(image, out, COLOR_GRAY2BGR); for (size_t i = 0; i < position.size(); ++i) { diff --git a/samples/gpu/houghlines.cpp b/samples/gpu/houghlines.cpp index f53724eccf..299fa47cb4 100644 --- a/samples/gpu/houghlines.cpp +++ b/samples/gpu/houghlines.cpp @@ -34,7 +34,7 @@ int main(int argc, const char* argv[]) Canny(src, mask, 100, 200, 3); Mat dst_cpu; - cvtColor(mask, dst_cpu, COLOR_GRAY2BGR); + cv::cvtColor(mask, dst_cpu, COLOR_GRAY2BGR); Mat dst_gpu = dst_cpu.clone(); vector lines_cpu; diff --git a/samples/gpu/pyrlk_optical_flow.cpp b/samples/gpu/pyrlk_optical_flow.cpp index 95170cc7e9..2edb9746c6 100644 --- a/samples/gpu/pyrlk_optical_flow.cpp +++ b/samples/gpu/pyrlk_optical_flow.cpp @@ -170,9 +170,9 @@ int main(int argc, const char* argv[]) cout << endl; Mat frame0Gray; - cvtColor(frame0, frame0Gray, COLOR_BGR2GRAY); + cv::cvtColor(frame0, frame0Gray, COLOR_BGR2GRAY); Mat frame1Gray; - cvtColor(frame1, frame1Gray, COLOR_BGR2GRAY); + cv::cvtColor(frame1, frame1Gray, COLOR_BGR2GRAY); // goodFeaturesToTrack From fc8476544c7404bbc9fea06df6252e4ccf8d0366 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 30 Apr 2013 10:59:13 +0400 Subject: [PATCH 02/17] switched to Input/Output Array in Histogram Processing --- .../gpuimgproc/include/opencv2/gpuimgproc.hpp | 73 ++- modules/gpuimgproc/perf/perf_histogram.cpp | 3 +- modules/gpuimgproc/src/histogram.cpp | 537 +++++++++--------- samples/gpu/performance/tests.cpp | 5 +- 4 files changed, 320 insertions(+), 298 deletions(-) diff --git a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp index 9f3dd96f94..f880b6cab9 100644 --- a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp +++ b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp @@ -98,54 +98,77 @@ CV_EXPORTS void alphaComp(InputArray img1, InputArray img2, OutputArray dst, int ////////////////////////////// Histogram /////////////////////////////// +//! Calculates histogram for 8u one channel image +//! Output hist will have one row, 256 cols and CV32SC1 type. +CV_EXPORTS void calcHist(InputArray src, OutputArray hist, Stream& stream = Stream::Null()); + +//! normalizes the grayscale image brightness and contrast by normalizing its histogram +CV_EXPORTS void equalizeHist(InputArray src, OutputArray dst, InputOutputArray buf, Stream& stream = Stream::Null()); + +static inline void equalizeHist(InputArray src, OutputArray dst, Stream& stream = Stream::Null()) +{ + GpuMat buf; + gpu::equalizeHist(src, dst, buf, stream); +} + +class CV_EXPORTS CLAHE : public cv::CLAHE +{ +public: + using cv::CLAHE::apply; + virtual void apply(InputArray src, OutputArray dst, Stream& stream) = 0; +}; +CV_EXPORTS Ptr createCLAHE(double clipLimit = 40.0, Size tileGridSize = Size(8, 8)); + //! Compute levels with even distribution. levels will have 1 row and nLevels cols and CV_32SC1 type. -CV_EXPORTS void evenLevels(GpuMat& levels, int nLevels, int lowerLevel, int upperLevel); +CV_EXPORTS void evenLevels(OutputArray levels, int nLevels, int lowerLevel, int upperLevel); //! Calculates histogram with evenly distributed bins for signle channel source. //! Supports CV_8UC1, CV_16UC1 and CV_16SC1 source types. //! Output hist will have one row and histSize cols and CV_32SC1 type. -CV_EXPORTS void histEven(const GpuMat& src, GpuMat& hist, int histSize, int lowerLevel, int upperLevel, Stream& stream = Stream::Null()); -CV_EXPORTS void histEven(const GpuMat& src, GpuMat& hist, GpuMat& buf, int histSize, int lowerLevel, int upperLevel, Stream& stream = Stream::Null()); +CV_EXPORTS void histEven(InputArray src, OutputArray hist, InputOutputArray buf, int histSize, int lowerLevel, int upperLevel, Stream& stream = Stream::Null()); + +static inline void histEven(InputArray src, OutputArray hist, int histSize, int lowerLevel, int upperLevel, Stream& stream = Stream::Null()) +{ + GpuMat buf; + gpu::histEven(src, hist, buf, histSize, lowerLevel, upperLevel, stream); +} //! Calculates histogram with evenly distributed bins for four-channel source. //! All channels of source are processed separately. //! Supports CV_8UC4, CV_16UC4 and CV_16SC4 source types. //! Output hist[i] will have one row and histSize[i] cols and CV_32SC1 type. -CV_EXPORTS void histEven(const GpuMat& src, GpuMat hist[4], int histSize[4], int lowerLevel[4], int upperLevel[4], Stream& stream = Stream::Null()); -CV_EXPORTS void histEven(const GpuMat& src, GpuMat hist[4], GpuMat& buf, int histSize[4], int lowerLevel[4], int upperLevel[4], Stream& stream = Stream::Null()); +CV_EXPORTS void histEven(InputArray src, GpuMat hist[4], InputOutputArray buf, int histSize[4], int lowerLevel[4], int upperLevel[4], Stream& stream = Stream::Null()); + +static inline void histEven(InputArray src, GpuMat hist[4], int histSize[4], int lowerLevel[4], int upperLevel[4], Stream& stream = Stream::Null()) +{ + GpuMat buf; + gpu::histEven(src, hist, buf, histSize, lowerLevel, upperLevel, stream); +} //! Calculates histogram with bins determined by levels array. //! levels must have one row and CV_32SC1 type if source has integer type or CV_32FC1 otherwise. //! Supports CV_8UC1, CV_16UC1, CV_16SC1 and CV_32FC1 source types. //! Output hist will have one row and (levels.cols-1) cols and CV_32SC1 type. -CV_EXPORTS void histRange(const GpuMat& src, GpuMat& hist, const GpuMat& levels, Stream& stream = Stream::Null()); -CV_EXPORTS void histRange(const GpuMat& src, GpuMat& hist, const GpuMat& levels, GpuMat& buf, Stream& stream = Stream::Null()); +CV_EXPORTS void histRange(InputArray src, OutputArray hist, InputArray levels, InputOutputArray buf, Stream& stream = Stream::Null()); + +static inline void histRange(InputArray src, OutputArray hist, InputArray levels, Stream& stream = Stream::Null()) +{ + GpuMat buf; + gpu::histRange(src, hist, levels, buf, stream); +} //! Calculates histogram with bins determined by levels array. //! All levels must have one row and CV_32SC1 type if source has integer type or CV_32FC1 otherwise. //! All channels of source are processed separately. //! Supports CV_8UC4, CV_16UC4, CV_16SC4 and CV_32FC4 source types. //! Output hist[i] will have one row and (levels[i].cols-1) cols and CV_32SC1 type. -CV_EXPORTS void histRange(const GpuMat& src, GpuMat hist[4], const GpuMat levels[4], Stream& stream = Stream::Null()); -CV_EXPORTS void histRange(const GpuMat& src, GpuMat hist[4], const GpuMat levels[4], GpuMat& buf, Stream& stream = Stream::Null()); - -//! Calculates histogram for 8u one channel image -//! Output hist will have one row, 256 cols and CV32SC1 type. -CV_EXPORTS void calcHist(const GpuMat& src, GpuMat& hist, Stream& stream = Stream::Null()); -CV_EXPORTS void calcHist(const GpuMat& src, GpuMat& hist, GpuMat& buf, Stream& stream = Stream::Null()); +CV_EXPORTS void histRange(InputArray src, GpuMat hist[4], const GpuMat levels[4], InputOutputArray buf, Stream& stream = Stream::Null()); -//! normalizes the grayscale image brightness and contrast by normalizing its histogram -CV_EXPORTS void equalizeHist(const GpuMat& src, GpuMat& dst, Stream& stream = Stream::Null()); -CV_EXPORTS void equalizeHist(const GpuMat& src, GpuMat& dst, GpuMat& hist, Stream& stream = Stream::Null()); -CV_EXPORTS void equalizeHist(const GpuMat& src, GpuMat& dst, GpuMat& hist, GpuMat& buf, Stream& stream = Stream::Null()); - -class CV_EXPORTS CLAHE : public cv::CLAHE +static inline void histRange(InputArray src, GpuMat hist[4], const GpuMat levels[4], Stream& stream = Stream::Null()) { -public: - using cv::CLAHE::apply; - virtual void apply(InputArray src, OutputArray dst, Stream& stream) = 0; -}; -CV_EXPORTS Ptr createCLAHE(double clipLimit = 40.0, Size tileGridSize = Size(8, 8)); + GpuMat buf; + gpu::histRange(src, hist, levels, buf, stream); +} //////////////////////////////// Canny //////////////////////////////// diff --git a/modules/gpuimgproc/perf/perf_histogram.cpp b/modules/gpuimgproc/perf/perf_histogram.cpp index 51f7416f91..d8def54ff1 100644 --- a/modules/gpuimgproc/perf/perf_histogram.cpp +++ b/modules/gpuimgproc/perf/perf_histogram.cpp @@ -167,10 +167,9 @@ PERF_TEST_P(Sz, EqualizeHist, { const cv::gpu::GpuMat d_src(src); cv::gpu::GpuMat dst; - cv::gpu::GpuMat d_hist; cv::gpu::GpuMat d_buf; - TEST_CYCLE() cv::gpu::equalizeHist(d_src, dst, d_hist, d_buf); + TEST_CYCLE() cv::gpu::equalizeHist(d_src, dst, d_buf); GPU_SANITY_CHECK(dst); } diff --git a/modules/gpuimgproc/src/histogram.cpp b/modules/gpuimgproc/src/histogram.cpp index 3227dac6c7..e54b33727a 100644 --- a/modules/gpuimgproc/src/histogram.cpp +++ b/modules/gpuimgproc/src/histogram.cpp @@ -47,27 +47,219 @@ using namespace cv::gpu; #if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) -void cv::gpu::evenLevels(GpuMat&, int, int, int) { throw_no_cuda(); } +void cv::gpu::calcHist(InputArray, OutputArray, Stream&) { throw_no_cuda(); } -void cv::gpu::histEven(const GpuMat&, GpuMat&, int, int, int, Stream&) { throw_no_cuda(); } -void cv::gpu::histEven(const GpuMat&, GpuMat&, GpuMat&, int, int, int, Stream&) { throw_no_cuda(); } -void cv::gpu::histEven(const GpuMat&, GpuMat*, int*, int*, int*, Stream&) { throw_no_cuda(); } -void cv::gpu::histEven(const GpuMat&, GpuMat*, GpuMat&, int*, int*, int*, Stream&) { throw_no_cuda(); } +void cv::gpu::equalizeHist(InputArray, OutputArray, InputOutputArray, Stream&) { throw_no_cuda(); } -void cv::gpu::histRange(const GpuMat&, GpuMat&, const GpuMat&, Stream&) { throw_no_cuda(); } -void cv::gpu::histRange(const GpuMat&, GpuMat&, const GpuMat&, GpuMat&, Stream&) { throw_no_cuda(); } -void cv::gpu::histRange(const GpuMat&, GpuMat*, const GpuMat*, Stream&) { throw_no_cuda(); } -void cv::gpu::histRange(const GpuMat&, GpuMat*, const GpuMat*, GpuMat&, Stream&) { throw_no_cuda(); } +cv::Ptr cv::gpu::createCLAHE(double, cv::Size) { throw_no_cuda(); return cv::Ptr(); } -void cv::gpu::calcHist(const GpuMat&, GpuMat&, Stream&) { throw_no_cuda(); } +void cv::gpu::evenLevels(OutputArray, int, int, int) { throw_no_cuda(); } -void cv::gpu::equalizeHist(const GpuMat&, GpuMat&, Stream&) { throw_no_cuda(); } -void cv::gpu::equalizeHist(const GpuMat&, GpuMat&, GpuMat&, GpuMat&, Stream&) { throw_no_cuda(); } +void cv::gpu::histEven(InputArray, OutputArray, InputOutputArray, int, int, int, Stream&) { throw_no_cuda(); } +void cv::gpu::histEven(InputArray, GpuMat*, InputOutputArray, int*, int*, int*, Stream&) { throw_no_cuda(); } -cv::Ptr cv::gpu::createCLAHE(double, cv::Size) { throw_no_cuda(); return cv::Ptr(); } +void cv::gpu::histRange(InputArray, OutputArray, InputArray, InputOutputArray, Stream&) { throw_no_cuda(); } +void cv::gpu::histRange(InputArray, GpuMat*, const GpuMat*, InputOutputArray, Stream&) { throw_no_cuda(); } #else /* !defined (HAVE_CUDA) */ +//////////////////////////////////////////////////////////////////////// +// calcHist + +namespace hist +{ + void histogram256(PtrStepSzb src, int* hist, cudaStream_t stream); +} + +void cv::gpu::calcHist(InputArray _src, OutputArray _hist, Stream& stream) +{ + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.type() == CV_8UC1 ); + + _hist.create(1, 256, CV_32SC1); + GpuMat hist = _hist.getGpuMat(); + + hist.setTo(Scalar::all(0), stream); + + hist::histogram256(src, hist.ptr(), StreamAccessor::getStream(stream)); +} + +//////////////////////////////////////////////////////////////////////// +// equalizeHist + +namespace hist +{ + void equalizeHist(PtrStepSzb src, PtrStepSzb dst, const int* lut, cudaStream_t stream); +} + +void cv::gpu::equalizeHist(InputArray _src, OutputArray _dst, InputOutputArray _buf, Stream& _stream) +{ + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.type() == CV_8UC1 ); + + _dst.create(src.size(), src.type()); + GpuMat dst = _dst.getGpuMat(); + + int intBufSize; + nppSafeCall( nppsIntegralGetBufferSize_32s(256, &intBufSize) ); + + size_t bufSize = intBufSize + 2 * 256 * sizeof(int); + + ensureSizeIsEnough(1, static_cast(bufSize), CV_8UC1, _buf); + GpuMat buf = _buf.getGpuMat(); + + GpuMat hist(1, 256, CV_32SC1, buf.data); + GpuMat lut(1, 256, CV_32SC1, buf.data + 256 * sizeof(int)); + GpuMat intBuf(1, intBufSize, CV_8UC1, buf.data + 2 * 256 * sizeof(int)); + + gpu::calcHist(src, hist, _stream); + + cudaStream_t stream = StreamAccessor::getStream(_stream); + NppStreamHandler h(stream); + + nppSafeCall( nppsIntegral_32s(hist.ptr(), lut.ptr(), 256, intBuf.ptr()) ); + + hist::equalizeHist(src, dst, lut.ptr(), stream); +} + +//////////////////////////////////////////////////////////////////////// +// CLAHE + +namespace clahe +{ + void calcLut(PtrStepSzb src, PtrStepb lut, int tilesX, int tilesY, int2 tileSize, int clipLimit, float lutScale, cudaStream_t stream); + void transform(PtrStepSzb src, PtrStepSzb dst, PtrStepb lut, int tilesX, int tilesY, int2 tileSize, cudaStream_t stream); +} + +namespace +{ + class CLAHE_Impl : public cv::gpu::CLAHE + { + public: + CLAHE_Impl(double clipLimit = 40.0, int tilesX = 8, int tilesY = 8); + + cv::AlgorithmInfo* info() const; + + void apply(cv::InputArray src, cv::OutputArray dst); + void apply(InputArray src, OutputArray dst, Stream& stream); + + void setClipLimit(double clipLimit); + double getClipLimit() const; + + void setTilesGridSize(cv::Size tileGridSize); + cv::Size getTilesGridSize() const; + + void collectGarbage(); + + private: + double clipLimit_; + int tilesX_; + int tilesY_; + + GpuMat srcExt_; + GpuMat lut_; + }; + + CLAHE_Impl::CLAHE_Impl(double clipLimit, int tilesX, int tilesY) : + clipLimit_(clipLimit), tilesX_(tilesX), tilesY_(tilesY) + { + } + + CV_INIT_ALGORITHM(CLAHE_Impl, "CLAHE_GPU", + obj.info()->addParam(obj, "clipLimit", obj.clipLimit_); + obj.info()->addParam(obj, "tilesX", obj.tilesX_); + obj.info()->addParam(obj, "tilesY", obj.tilesY_)) + + void CLAHE_Impl::apply(cv::InputArray _src, cv::OutputArray _dst) + { + apply(_src, _dst, Stream::Null()); + } + + void CLAHE_Impl::apply(InputArray _src, OutputArray _dst, Stream& s) + { + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.type() == CV_8UC1 ); + + _dst.create( src.size(), src.type() ); + GpuMat dst = _dst.getGpuMat(); + + const int histSize = 256; + + ensureSizeIsEnough(tilesX_ * tilesY_, histSize, CV_8UC1, lut_); + + cudaStream_t stream = StreamAccessor::getStream(s); + + cv::Size tileSize; + GpuMat srcForLut; + + if (src.cols % tilesX_ == 0 && src.rows % tilesY_ == 0) + { + tileSize = cv::Size(src.cols / tilesX_, src.rows / tilesY_); + srcForLut = src; + } + else + { +#ifndef HAVE_OPENCV_GPUARITHM + throw_no_cuda(); +#else + cv::gpu::copyMakeBorder(src, srcExt_, 0, tilesY_ - (src.rows % tilesY_), 0, tilesX_ - (src.cols % tilesX_), cv::BORDER_REFLECT_101, cv::Scalar(), s); +#endif + + tileSize = cv::Size(srcExt_.cols / tilesX_, srcExt_.rows / tilesY_); + srcForLut = srcExt_; + } + + const int tileSizeTotal = tileSize.area(); + const float lutScale = static_cast(histSize - 1) / tileSizeTotal; + + int clipLimit = 0; + if (clipLimit_ > 0.0) + { + clipLimit = static_cast(clipLimit_ * tileSizeTotal / histSize); + clipLimit = std::max(clipLimit, 1); + } + + clahe::calcLut(srcForLut, lut_, tilesX_, tilesY_, make_int2(tileSize.width, tileSize.height), clipLimit, lutScale, stream); + + clahe::transform(src, dst, lut_, tilesX_, tilesY_, make_int2(tileSize.width, tileSize.height), stream); + } + + void CLAHE_Impl::setClipLimit(double clipLimit) + { + clipLimit_ = clipLimit; + } + + double CLAHE_Impl::getClipLimit() const + { + return clipLimit_; + } + + void CLAHE_Impl::setTilesGridSize(cv::Size tileGridSize) + { + tilesX_ = tileGridSize.width; + tilesY_ = tileGridSize.height; + } + + cv::Size CLAHE_Impl::getTilesGridSize() const + { + return cv::Size(tilesX_, tilesY_); + } + + void CLAHE_Impl::collectGarbage() + { + srcExt_.release(); + lut_.release(); + } +} + +cv::Ptr cv::gpu::createCLAHE(double clipLimit, cv::Size tileGridSize) +{ + return new CLAHE_Impl(clipLimit, tileGridSize.width, tileGridSize.height); +} + //////////////////////////////////////////////////////////////////////// // NPP Histogram @@ -96,10 +288,12 @@ namespace { typedef typename NppHistogramEvenFuncC1::src_t src_t; - static void hist(const GpuMat& src, GpuMat& hist, GpuMat& buffer, int histSize, int lowerLevel, int upperLevel, cudaStream_t stream) + static void hist(const GpuMat& src, OutputArray _hist, InputOutputArray _buf, int histSize, int lowerLevel, int upperLevel, cudaStream_t stream) { - int levels = histSize + 1; - hist.create(1, histSize, CV_32S); + const int levels = histSize + 1; + + _hist.create(1, histSize, CV_32S); + GpuMat hist = _hist.getGpuMat(); NppiSize sz; sz.width = src.cols; @@ -108,12 +302,13 @@ namespace int buf_size; get_buf_size(sz, levels, &buf_size); - ensureSizeIsEnough(1, buf_size, CV_8U, buffer); + ensureSizeIsEnough(1, buf_size, CV_8UC1, _buf); + GpuMat buf = _buf.getGpuMat(); NppStreamHandler h(stream); nppSafeCall( func(src.ptr(), static_cast(src.step), sz, hist.ptr(), levels, - lowerLevel, upperLevel, buffer.ptr()) ); + lowerLevel, upperLevel, buf.ptr()) ); if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); @@ -124,7 +319,7 @@ namespace { typedef typename NppHistogramEvenFuncC4::src_t src_t; - static void hist(const GpuMat& src, GpuMat hist[4], GpuMat& buffer, int histSize[4], int lowerLevel[4], int upperLevel[4], cudaStream_t stream) + static void hist(const GpuMat& src, GpuMat hist[4],InputOutputArray _buf, int histSize[4], int lowerLevel[4], int upperLevel[4], cudaStream_t stream) { int levels[] = {histSize[0] + 1, histSize[1] + 1, histSize[2] + 1, histSize[3] + 1}; hist[0].create(1, histSize[0], CV_32S); @@ -141,11 +336,12 @@ namespace int buf_size; get_buf_size(sz, levels, &buf_size); - ensureSizeIsEnough(1, buf_size, CV_8U, buffer); + ensureSizeIsEnough(1, buf_size, CV_8U, _buf); + GpuMat buf = _buf.getGpuMat(); NppStreamHandler h(stream); - nppSafeCall( func(src.ptr(), static_cast(src.step), sz, pHist, levels, lowerLevel, upperLevel, buffer.ptr()) ); + nppSafeCall( func(src.ptr(), static_cast(src.step), sz, pHist, levels, lowerLevel, upperLevel, buf.ptr()) ); if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); @@ -196,11 +392,12 @@ namespace typedef typename NppHistogramRangeFuncC1::level_t level_t; enum {LEVEL_TYPE_CODE=NppHistogramRangeFuncC1::LEVEL_TYPE_CODE}; - static void hist(const GpuMat& src, GpuMat& hist, const GpuMat& levels, GpuMat& buffer, cudaStream_t stream) + static void hist(const GpuMat& src, OutputArray _hist, const GpuMat& levels, InputOutputArray _buf, cudaStream_t stream) { - CV_Assert(levels.type() == LEVEL_TYPE_CODE && levels.rows == 1); + CV_Assert( levels.type() == LEVEL_TYPE_CODE && levels.rows == 1 ); - hist.create(1, levels.cols - 1, CV_32S); + _hist.create(1, levels.cols - 1, CV_32S); + GpuMat hist = _hist.getGpuMat(); NppiSize sz; sz.width = src.cols; @@ -209,11 +406,12 @@ namespace int buf_size; get_buf_size(sz, levels.cols, &buf_size); - ensureSizeIsEnough(1, buf_size, CV_8U, buffer); + ensureSizeIsEnough(1, buf_size, CV_8U, _buf); + GpuMat buf = _buf.getGpuMat(); NppStreamHandler h(stream); - nppSafeCall( func(src.ptr(), static_cast(src.step), sz, hist.ptr(), levels.ptr(), levels.cols, buffer.ptr()) ); + nppSafeCall( func(src.ptr(), static_cast(src.step), sz, hist.ptr(), levels.ptr(), levels.cols, buf.ptr()) ); if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); @@ -226,12 +424,12 @@ namespace typedef typename NppHistogramRangeFuncC1::level_t level_t; enum {LEVEL_TYPE_CODE=NppHistogramRangeFuncC1::LEVEL_TYPE_CODE}; - static void hist(const GpuMat& src, GpuMat hist[4], const GpuMat levels[4], GpuMat& buffer, cudaStream_t stream) + static void hist(const GpuMat& src, GpuMat hist[4], const GpuMat levels[4],InputOutputArray _buf, cudaStream_t stream) { - CV_Assert(levels[0].type() == LEVEL_TYPE_CODE && levels[0].rows == 1); - CV_Assert(levels[1].type() == LEVEL_TYPE_CODE && levels[1].rows == 1); - CV_Assert(levels[2].type() == LEVEL_TYPE_CODE && levels[2].rows == 1); - CV_Assert(levels[3].type() == LEVEL_TYPE_CODE && levels[3].rows == 1); + CV_Assert( levels[0].type() == LEVEL_TYPE_CODE && levels[0].rows == 1 ); + CV_Assert( levels[1].type() == LEVEL_TYPE_CODE && levels[1].rows == 1 ); + CV_Assert( levels[2].type() == LEVEL_TYPE_CODE && levels[2].rows == 1 ); + CV_Assert( levels[3].type() == LEVEL_TYPE_CODE && levels[3].rows == 1 ); hist[0].create(1, levels[0].cols - 1, CV_32S); hist[1].create(1, levels[1].cols - 1, CV_32S); @@ -249,11 +447,12 @@ namespace int buf_size; get_buf_size(sz, nLevels, &buf_size); - ensureSizeIsEnough(1, buf_size, CV_8U, buffer); + ensureSizeIsEnough(1, buf_size, CV_8U, _buf); + GpuMat buf = _buf.getGpuMat(); NppStreamHandler h(stream); - nppSafeCall( func(src.ptr(), static_cast(src.step), sz, pHist, pLevels, nLevels, buffer.ptr()) ); + nppSafeCall( func(src.ptr(), static_cast(src.step), sz, pHist, pLevels, nLevels, buf.ptr()) ); if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); @@ -261,24 +460,27 @@ namespace }; } -void cv::gpu::evenLevels(GpuMat& levels, int nLevels, int lowerLevel, int upperLevel) +void cv::gpu::evenLevels(OutputArray _levels, int nLevels, int lowerLevel, int upperLevel) { - Mat host_levels(1, nLevels, CV_32SC1); + const int kind = _levels.kind(); + + _levels.create(1, nLevels, CV_32SC1); + + Mat host_levels; + if (kind == _InputArray::GPU_MAT) + host_levels.create(1, nLevels, CV_32SC1); + else + host_levels = _levels.getMat(); + nppSafeCall( nppiEvenLevelsHost_32s(host_levels.ptr(), nLevels, lowerLevel, upperLevel) ); - levels.upload(host_levels); -} -void cv::gpu::histEven(const GpuMat& src, GpuMat& hist, int histSize, int lowerLevel, int upperLevel, Stream& stream) -{ - GpuMat buf; - histEven(src, hist, buf, histSize, lowerLevel, upperLevel, stream); + if (kind == _InputArray::GPU_MAT) + _levels.getGpuMatRef().upload(host_levels); } -void cv::gpu::histEven(const GpuMat& src, GpuMat& hist, GpuMat& buf, int histSize, int lowerLevel, int upperLevel, Stream& stream) +void cv::gpu::histEven(InputArray _src, OutputArray hist, InputOutputArray buf, int histSize, int lowerLevel, int upperLevel, Stream& stream) { - CV_Assert(src.type() == CV_8UC1 || src.type() == CV_16UC1 || src.type() == CV_16SC1 ); - - typedef void (*hist_t)(const GpuMat& src, GpuMat& hist, GpuMat& buf, int levels, int lowerLevel, int upperLevel, cudaStream_t stream); + typedef void (*hist_t)(const GpuMat& src, OutputArray hist, InputOutputArray buf, int levels, int lowerLevel, int upperLevel, cudaStream_t stream); static const hist_t hist_callers[] = { NppHistogramEvenC1::hist, @@ -287,20 +489,16 @@ void cv::gpu::histEven(const GpuMat& src, GpuMat& hist, GpuMat& buf, int histSiz NppHistogramEvenC1::hist }; - hist_callers[src.depth()](src, hist, buf, histSize, lowerLevel, upperLevel, StreamAccessor::getStream(stream)); -} + GpuMat src = _src.getGpuMat(); -void cv::gpu::histEven(const GpuMat& src, GpuMat hist[4], int histSize[4], int lowerLevel[4], int upperLevel[4], Stream& stream) -{ - GpuMat buf; - histEven(src, hist, buf, histSize, lowerLevel, upperLevel, stream); + CV_Assert( src.type() == CV_8UC1 || src.type() == CV_16UC1 || src.type() == CV_16SC1 ); + + hist_callers[src.depth()](src, hist, buf, histSize, lowerLevel, upperLevel, StreamAccessor::getStream(stream)); } -void cv::gpu::histEven(const GpuMat& src, GpuMat hist[4], GpuMat& buf, int histSize[4], int lowerLevel[4], int upperLevel[4], Stream& stream) +void cv::gpu::histEven(InputArray _src, GpuMat hist[4], InputOutputArray buf, int histSize[4], int lowerLevel[4], int upperLevel[4], Stream& stream) { - CV_Assert(src.type() == CV_8UC4 || src.type() == CV_16UC4 || src.type() == CV_16SC4 ); - - typedef void (*hist_t)(const GpuMat& src, GpuMat hist[4], GpuMat& buf, int levels[4], int lowerLevel[4], int upperLevel[4], cudaStream_t stream); + typedef void (*hist_t)(const GpuMat& src, GpuMat hist[4], InputOutputArray buf, int levels[4], int lowerLevel[4], int upperLevel[4], cudaStream_t stream); static const hist_t hist_callers[] = { NppHistogramEvenC4::hist, @@ -309,20 +507,16 @@ void cv::gpu::histEven(const GpuMat& src, GpuMat hist[4], GpuMat& buf, int histS NppHistogramEvenC4::hist }; - hist_callers[src.depth()](src, hist, buf, histSize, lowerLevel, upperLevel, StreamAccessor::getStream(stream)); -} + GpuMat src = _src.getGpuMat(); -void cv::gpu::histRange(const GpuMat& src, GpuMat& hist, const GpuMat& levels, Stream& stream) -{ - GpuMat buf; - histRange(src, hist, levels, buf, stream); + CV_Assert( src.type() == CV_8UC4 || src.type() == CV_16UC4 || src.type() == CV_16SC4 ); + + hist_callers[src.depth()](src, hist, buf, histSize, lowerLevel, upperLevel, StreamAccessor::getStream(stream)); } -void cv::gpu::histRange(const GpuMat& src, GpuMat& hist, const GpuMat& levels, GpuMat& buf, Stream& stream) +void cv::gpu::histRange(InputArray _src, OutputArray hist, InputArray _levels, InputOutputArray buf, Stream& stream) { - CV_Assert(src.type() == CV_8UC1 || src.type() == CV_16UC1 || src.type() == CV_16SC1 || src.type() == CV_32FC1); - - typedef void (*hist_t)(const GpuMat& src, GpuMat& hist, const GpuMat& levels, GpuMat& buf, cudaStream_t stream); + typedef void (*hist_t)(const GpuMat& src, OutputArray hist, const GpuMat& levels, InputOutputArray buf, cudaStream_t stream); static const hist_t hist_callers[] = { NppHistogramRangeC1::hist, @@ -333,20 +527,17 @@ void cv::gpu::histRange(const GpuMat& src, GpuMat& hist, const GpuMat& levels, G NppHistogramRangeC1::hist }; - hist_callers[src.depth()](src, hist, levels, buf, StreamAccessor::getStream(stream)); -} + GpuMat src = _src.getGpuMat(); + GpuMat levels = _levels.getGpuMat(); -void cv::gpu::histRange(const GpuMat& src, GpuMat hist[4], const GpuMat levels[4], Stream& stream) -{ - GpuMat buf; - histRange(src, hist, levels, buf, stream); + CV_Assert( src.type() == CV_8UC1 || src.type() == CV_16UC1 || src.type() == CV_16SC1 || src.type() == CV_32FC1 ); + + hist_callers[src.depth()](src, hist, levels, buf, StreamAccessor::getStream(stream)); } -void cv::gpu::histRange(const GpuMat& src, GpuMat hist[4], const GpuMat levels[4], GpuMat& buf, Stream& stream) +void cv::gpu::histRange(InputArray _src, GpuMat hist[4], const GpuMat levels[4], InputOutputArray buf, Stream& stream) { - CV_Assert(src.type() == CV_8UC4 || src.type() == CV_16UC4 || src.type() == CV_16SC4 || src.type() == CV_32FC4); - - typedef void (*hist_t)(const GpuMat& src, GpuMat hist[4], const GpuMat levels[4], GpuMat& buf, cudaStream_t stream); + typedef void (*hist_t)(const GpuMat& src, GpuMat hist[4], const GpuMat levels[4], InputOutputArray buf, cudaStream_t stream); static const hist_t hist_callers[] = { NppHistogramRangeC4::hist, @@ -357,201 +548,11 @@ void cv::gpu::histRange(const GpuMat& src, GpuMat hist[4], const GpuMat levels[4 NppHistogramRangeC4::hist }; - hist_callers[src.depth()](src, hist, levels, buf, StreamAccessor::getStream(stream)); -} - -//////////////////////////////////////////////////////////////////////// -// calcHist - -namespace hist -{ - void histogram256(PtrStepSzb src, int* hist, cudaStream_t stream); -} - -void cv::gpu::calcHist(const GpuMat& src, GpuMat& hist, Stream& stream) -{ - CV_Assert(src.type() == CV_8UC1); - - hist.create(1, 256, CV_32SC1); - hist.setTo(Scalar::all(0)); - - hist::histogram256(src, hist.ptr(), StreamAccessor::getStream(stream)); -} - -//////////////////////////////////////////////////////////////////////// -// equalizeHist - -namespace hist -{ - void equalizeHist(PtrStepSzb src, PtrStepSzb dst, const int* lut, cudaStream_t stream); -} - -void cv::gpu::equalizeHist(const GpuMat& src, GpuMat& dst, Stream& stream) -{ - GpuMat hist; - GpuMat buf; - equalizeHist(src, dst, hist, buf, stream); -} - -void cv::gpu::equalizeHist(const GpuMat& src, GpuMat& dst, GpuMat& hist, GpuMat& buf, Stream& s) -{ - CV_Assert(src.type() == CV_8UC1); - - dst.create(src.size(), src.type()); - - int intBufSize; - nppSafeCall( nppsIntegralGetBufferSize_32s(256, &intBufSize) ); - - ensureSizeIsEnough(1, intBufSize + 256 * sizeof(int), CV_8UC1, buf); - - GpuMat intBuf(1, intBufSize, CV_8UC1, buf.ptr()); - GpuMat lut(1, 256, CV_32S, buf.ptr() + intBufSize); + GpuMat src = _src.getGpuMat(); - calcHist(src, hist, s); + CV_Assert( src.type() == CV_8UC4 || src.type() == CV_16UC4 || src.type() == CV_16SC4 || src.type() == CV_32FC4 ); - cudaStream_t stream = StreamAccessor::getStream(s); - - NppStreamHandler h(stream); - - nppSafeCall( nppsIntegral_32s(hist.ptr(), lut.ptr(), 256, intBuf.ptr()) ); - - hist::equalizeHist(src, dst, lut.ptr(), stream); -} - -//////////////////////////////////////////////////////////////////////// -// CLAHE - -namespace clahe -{ - void calcLut(PtrStepSzb src, PtrStepb lut, int tilesX, int tilesY, int2 tileSize, int clipLimit, float lutScale, cudaStream_t stream); - void transform(PtrStepSzb src, PtrStepSzb dst, PtrStepb lut, int tilesX, int tilesY, int2 tileSize, cudaStream_t stream); -} - -namespace -{ - class CLAHE_Impl : public cv::gpu::CLAHE - { - public: - CLAHE_Impl(double clipLimit = 40.0, int tilesX = 8, int tilesY = 8); - - cv::AlgorithmInfo* info() const; - - void apply(cv::InputArray src, cv::OutputArray dst); - void apply(InputArray src, OutputArray dst, Stream& stream); - - void setClipLimit(double clipLimit); - double getClipLimit() const; - - void setTilesGridSize(cv::Size tileGridSize); - cv::Size getTilesGridSize() const; - - void collectGarbage(); - - private: - double clipLimit_; - int tilesX_; - int tilesY_; - - GpuMat srcExt_; - GpuMat lut_; - }; - - CLAHE_Impl::CLAHE_Impl(double clipLimit, int tilesX, int tilesY) : - clipLimit_(clipLimit), tilesX_(tilesX), tilesY_(tilesY) - { - } - - CV_INIT_ALGORITHM(CLAHE_Impl, "CLAHE_GPU", - obj.info()->addParam(obj, "clipLimit", obj.clipLimit_); - obj.info()->addParam(obj, "tilesX", obj.tilesX_); - obj.info()->addParam(obj, "tilesY", obj.tilesY_)) - - void CLAHE_Impl::apply(cv::InputArray _src, cv::OutputArray _dst) - { - apply(_src, _dst, Stream::Null()); - } - - void CLAHE_Impl::apply(InputArray _src, OutputArray _dst, Stream& s) - { - GpuMat src = _src.getGpuMat(); - - CV_Assert( src.type() == CV_8UC1 ); - - _dst.create( src.size(), src.type() ); - GpuMat dst = _dst.getGpuMat(); - - const int histSize = 256; - - ensureSizeIsEnough(tilesX_ * tilesY_, histSize, CV_8UC1, lut_); - - cudaStream_t stream = StreamAccessor::getStream(s); - - cv::Size tileSize; - GpuMat srcForLut; - - if (src.cols % tilesX_ == 0 && src.rows % tilesY_ == 0) - { - tileSize = cv::Size(src.cols / tilesX_, src.rows / tilesY_); - srcForLut = src; - } - else - { -#ifndef HAVE_OPENCV_GPUARITHM - throw_no_cuda(); -#else - cv::gpu::copyMakeBorder(src, srcExt_, 0, tilesY_ - (src.rows % tilesY_), 0, tilesX_ - (src.cols % tilesX_), cv::BORDER_REFLECT_101, cv::Scalar(), s); -#endif - - tileSize = cv::Size(srcExt_.cols / tilesX_, srcExt_.rows / tilesY_); - srcForLut = srcExt_; - } - - const int tileSizeTotal = tileSize.area(); - const float lutScale = static_cast(histSize - 1) / tileSizeTotal; - - int clipLimit = 0; - if (clipLimit_ > 0.0) - { - clipLimit = static_cast(clipLimit_ * tileSizeTotal / histSize); - clipLimit = std::max(clipLimit, 1); - } - - clahe::calcLut(srcForLut, lut_, tilesX_, tilesY_, make_int2(tileSize.width, tileSize.height), clipLimit, lutScale, stream); - - clahe::transform(src, dst, lut_, tilesX_, tilesY_, make_int2(tileSize.width, tileSize.height), stream); - } - - void CLAHE_Impl::setClipLimit(double clipLimit) - { - clipLimit_ = clipLimit; - } - - double CLAHE_Impl::getClipLimit() const - { - return clipLimit_; - } - - void CLAHE_Impl::setTilesGridSize(cv::Size tileGridSize) - { - tilesX_ = tileGridSize.width; - tilesY_ = tileGridSize.height; - } - - cv::Size CLAHE_Impl::getTilesGridSize() const - { - return cv::Size(tilesX_, tilesY_); - } - - void CLAHE_Impl::collectGarbage() - { - srcExt_.release(); - lut_.release(); - } -} - -cv::Ptr cv::gpu::createCLAHE(double clipLimit, cv::Size tileGridSize) -{ - return new CLAHE_Impl(clipLimit, tileGridSize.width, tileGridSize.height); + hist_callers[src.depth()](src, hist, levels, buf, StreamAccessor::getStream(stream)); } #endif /* !defined (HAVE_CUDA) */ diff --git a/samples/gpu/performance/tests.cpp b/samples/gpu/performance/tests.cpp index 4333b76257..7193ee93ae 100644 --- a/samples/gpu/performance/tests.cpp +++ b/samples/gpu/performance/tests.cpp @@ -1047,13 +1047,12 @@ TEST(equalizeHist) gpu::GpuMat d_src(src); gpu::GpuMat d_dst; - gpu::GpuMat d_hist; gpu::GpuMat d_buf; - gpu::equalizeHist(d_src, d_dst, d_hist, d_buf); + gpu::equalizeHist(d_src, d_dst, d_buf); GPU_ON; - gpu::equalizeHist(d_src, d_dst, d_hist, d_buf); + gpu::equalizeHist(d_src, d_dst, d_buf); GPU_OFF; } } From 48fb8c4f8a767d50cec47d2fb380b737e97c2bce Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 30 Apr 2013 11:47:33 +0400 Subject: [PATCH 03/17] refactored gpu::Canny (converted it into Algorithm) --- .../gpuimgproc/include/opencv2/gpuimgproc.hpp | 65 ++++-- modules/gpuimgproc/perf/perf_canny.cpp | 5 +- modules/gpuimgproc/src/canny.cpp | 215 ++++++++++-------- modules/gpuimgproc/src/hough.cpp | 43 +++- modules/gpuimgproc/test/test_canny.cpp | 27 +-- samples/gpu/houghlines.cpp | 2 +- samples/gpu/performance/tests.cpp | 7 +- 7 files changed, 226 insertions(+), 138 deletions(-) diff --git a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp index f880b6cab9..ea68590b51 100644 --- a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp +++ b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp @@ -48,9 +48,18 @@ #endif #include "opencv2/core/gpu.hpp" -#include "opencv2/core/base.hpp" #include "opencv2/imgproc.hpp" -#include "opencv2/gpufilters.hpp" + +#if defined __GNUC__ + #define __OPENCV_GPUIMGPROC_DEPR_BEFORE__ + #define __OPENCV_GPUIMGPROC_DEPR_AFTER__ __attribute__ ((deprecated)) +#elif (defined WIN32 || defined _WIN32) + #define __OPENCV_GPUIMGPROC_DEPR_BEFORE__ __declspec(deprecated) + #define __OPENCV_GPUIMGPROC_DEPR_AFTER__ +#else + #define __OPENCV_GPUIMGPROC_DEPR_BEFORE__ + #define __OPENCV_GPUIMGPROC_DEPR_AFTER__ +#endif namespace cv { namespace gpu { @@ -172,22 +181,42 @@ static inline void histRange(InputArray src, GpuMat hist[4], const GpuMat levels //////////////////////////////// Canny //////////////////////////////// -struct CV_EXPORTS CannyBuf +class CV_EXPORTS CannyEdgeDetector : public Algorithm { - void create(const Size& image_size, int apperture_size = 3); - void release(); +public: + virtual void detect(InputArray image, OutputArray edges) = 0; + virtual void detect(InputArray dx, InputArray dy, OutputArray edges) = 0; - GpuMat dx, dy; - GpuMat mag; - GpuMat map; - GpuMat st1, st2; - Ptr filterDX, filterDY; + virtual void setLowThreshold(double low_thresh) = 0; + virtual double getLowThreshold() const = 0; + + virtual void setHighThreshold(double high_thresh) = 0; + virtual double getHighThreshold() const = 0; + + virtual void setAppertureSize(int apperture_size) = 0; + virtual int getAppertureSize() const = 0; + + virtual void setL2Gradient(bool L2gradient) = 0; + virtual bool getL2Gradient() const = 0; }; -CV_EXPORTS void Canny(const GpuMat& image, GpuMat& edges, double low_thresh, double high_thresh, int apperture_size = 3, bool L2gradient = false); -CV_EXPORTS void Canny(const GpuMat& image, CannyBuf& buf, GpuMat& edges, double low_thresh, double high_thresh, int apperture_size = 3, bool L2gradient = false); -CV_EXPORTS void Canny(const GpuMat& dx, const GpuMat& dy, GpuMat& edges, double low_thresh, double high_thresh, bool L2gradient = false); -CV_EXPORTS void Canny(const GpuMat& dx, const GpuMat& dy, CannyBuf& buf, GpuMat& edges, double low_thresh, double high_thresh, bool L2gradient = false); +CV_EXPORTS Ptr createCannyEdgeDetector(double low_thresh, double high_thresh, int apperture_size = 3, bool L2gradient = false); + +// obsolete + +__OPENCV_GPUIMGPROC_DEPR_BEFORE__ void Canny(InputArray image, OutputArray edges, + double low_thresh, double high_thresh, int apperture_size = 3, bool L2gradient = false) __OPENCV_GPUIMGPROC_DEPR_AFTER__; +inline void Canny(InputArray image, OutputArray edges, double low_thresh, double high_thresh, int apperture_size, bool L2gradient) +{ + gpu::createCannyEdgeDetector(low_thresh, high_thresh, apperture_size, L2gradient)->detect(image, edges); +} + +__OPENCV_GPUIMGPROC_DEPR_BEFORE__ void Canny(InputArray dx, InputArray dy, OutputArray edges, + double low_thresh, double high_thresh, bool L2gradient = false) __OPENCV_GPUIMGPROC_DEPR_AFTER__; +inline void Canny(InputArray dx, InputArray dy, OutputArray edges, double low_thresh, double high_thresh, bool L2gradient) +{ + gpu::createCannyEdgeDetector(low_thresh, high_thresh, 3, L2gradient)->detect(dx, dy, edges); +} /////////////////////////// Hough Transform //////////////////////////// @@ -209,7 +238,7 @@ struct HoughCirclesBuf GpuMat edges; GpuMat accum; GpuMat list; - CannyBuf cannyBuf; + Ptr canny; }; CV_EXPORTS void HoughCircles(const GpuMat& src, GpuMat& circles, int method, float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles = 4096); @@ -224,6 +253,7 @@ class CV_EXPORTS GeneralizedHough_GPU : public cv::Algorithm public: static Ptr create(int method); + GeneralizedHough_GPU(); virtual ~GeneralizedHough_GPU(); //! set template to search @@ -245,7 +275,7 @@ protected: private: GpuMat edges_; - CannyBuf cannyBuf_; + Ptr canny_; }; ////////////////////////// Corners Detection /////////////////////////// @@ -359,4 +389,7 @@ CV_EXPORTS void blendLinear(const GpuMat& img1, const GpuMat& img2, const GpuMat }} // namespace cv { namespace gpu { +#undef __OPENCV_GPUIMGPROC_DEPR_BEFORE__ +#undef __OPENCV_GPUIMGPROC_DEPR_AFTER__ + #endif /* __OPENCV_GPUIMGPROC_HPP__ */ diff --git a/modules/gpuimgproc/perf/perf_canny.cpp b/modules/gpuimgproc/perf/perf_canny.cpp index ce6db2bb34..2bbf70a496 100644 --- a/modules/gpuimgproc/perf/perf_canny.cpp +++ b/modules/gpuimgproc/perf/perf_canny.cpp @@ -70,9 +70,10 @@ PERF_TEST_P(Image_AppertureSz_L2gradient, Canny, { const cv::gpu::GpuMat d_image(image); cv::gpu::GpuMat dst; - cv::gpu::CannyBuf d_buf; - TEST_CYCLE() cv::gpu::Canny(d_image, d_buf, dst, low_thresh, high_thresh, apperture_size, useL2gradient); + cv::Ptr canny = cv::gpu::createCannyEdgeDetector(low_thresh, high_thresh, apperture_size, useL2gradient); + + TEST_CYCLE() canny->detect(d_image, dst); GPU_SANITY_CHECK(dst); } diff --git a/modules/gpuimgproc/src/canny.cpp b/modules/gpuimgproc/src/canny.cpp index 9a33575648..888a224d75 100644 --- a/modules/gpuimgproc/src/canny.cpp +++ b/modules/gpuimgproc/src/canny.cpp @@ -47,46 +47,10 @@ using namespace cv::gpu; #if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) -void cv::gpu::Canny(const GpuMat&, GpuMat&, double, double, int, bool) { throw_no_cuda(); } -void cv::gpu::Canny(const GpuMat&, CannyBuf&, GpuMat&, double, double, int, bool) { throw_no_cuda(); } -void cv::gpu::Canny(const GpuMat&, const GpuMat&, GpuMat&, double, double, bool) { throw_no_cuda(); } -void cv::gpu::Canny(const GpuMat&, const GpuMat&, CannyBuf&, GpuMat&, double, double, bool) { throw_no_cuda(); } -void cv::gpu::CannyBuf::create(const Size&, int) { throw_no_cuda(); } -void cv::gpu::CannyBuf::release() { throw_no_cuda(); } +Ptr cv::gpu::createCannyEdgeDetector(double, double, int, bool) { throw_no_cuda(); return Ptr(); } #else /* !defined (HAVE_CUDA) */ -void cv::gpu::CannyBuf::create(const Size& image_size, int apperture_size) -{ - if (apperture_size > 0) - { - ensureSizeIsEnough(image_size, CV_32SC1, dx); - ensureSizeIsEnough(image_size, CV_32SC1, dy); - - if (apperture_size != 3) - { - filterDX = createDerivFilter(CV_8UC1, CV_32S, 1, 0, apperture_size, false, 1, BORDER_REPLICATE); - filterDY = createDerivFilter(CV_8UC1, CV_32S, 0, 1, apperture_size, false, 1, BORDER_REPLICATE); - } - } - - ensureSizeIsEnough(image_size, CV_32FC1, mag); - ensureSizeIsEnough(image_size, CV_32SC1, map); - - ensureSizeIsEnough(1, image_size.area(), CV_16UC2, st1); - ensureSizeIsEnough(1, image_size.area(), CV_16UC2, st2); -} - -void cv::gpu::CannyBuf::release() -{ - dx.release(); - dy.release(); - mag.release(); - map.release(); - st1.release(); - st2.release(); -} - namespace canny { void calcMagnitude(PtrStepSzb srcWhole, int xoff, int yoff, PtrStepSzi dx, PtrStepSzi dy, PtrStepSzf mag, bool L2Grad); @@ -103,84 +67,157 @@ namespace canny namespace { - void CannyCaller(const GpuMat& dx, const GpuMat& dy, CannyBuf& buf, GpuMat& dst, float low_thresh, float high_thresh) + class CannyImpl : public CannyEdgeDetector { - using namespace canny; + public: + CannyImpl(double low_thresh, double high_thresh, int apperture_size, bool L2gradient) : + low_thresh_(low_thresh), high_thresh_(high_thresh), apperture_size_(apperture_size), L2gradient_(L2gradient) + { + old_apperture_size_ = -1; + } - buf.map.setTo(Scalar::all(0)); - calcMap(dx, dy, buf.mag, buf.map, low_thresh, high_thresh); + void detect(InputArray image, OutputArray edges); + void detect(InputArray dx, InputArray dy, OutputArray edges); - edgesHysteresisLocal(buf.map, buf.st1.ptr()); + void setLowThreshold(double low_thresh) { low_thresh_ = low_thresh; } + double getLowThreshold() const { return low_thresh_; } - edgesHysteresisGlobal(buf.map, buf.st1.ptr(), buf.st2.ptr()); + void setHighThreshold(double high_thresh) { high_thresh_ = high_thresh; } + double getHighThreshold() const { return high_thresh_; } - getEdges(buf.map, dst); - } -} + void setAppertureSize(int apperture_size) { apperture_size_ = apperture_size; } + int getAppertureSize() const { return apperture_size_; } -void cv::gpu::Canny(const GpuMat& src, GpuMat& dst, double low_thresh, double high_thresh, int apperture_size, bool L2gradient) -{ - CannyBuf buf; - Canny(src, buf, dst, low_thresh, high_thresh, apperture_size, L2gradient); -} + void setL2Gradient(bool L2gradient) { L2gradient_ = L2gradient; } + bool getL2Gradient() const { return L2gradient_; } -void cv::gpu::Canny(const GpuMat& src, CannyBuf& buf, GpuMat& dst, double low_thresh, double high_thresh, int apperture_size, bool L2gradient) -{ - using namespace canny; + void write(FileStorage& fs) const + { + fs << "name" << "Canny_GPU" + << "low_thresh" << low_thresh_ + << "high_thresh" << high_thresh_ + << "apperture_size" << apperture_size_ + << "L2gradient" << L2gradient_; + } - CV_Assert(src.type() == CV_8UC1); + void read(const FileNode& fn) + { + CV_Assert( String(fn["name"]) == "Canny_GPU" ); + low_thresh_ = (double)fn["low_thresh"]; + high_thresh_ = (double)fn["high_thresh"]; + apperture_size_ = (int)fn["apperture_size"]; + L2gradient_ = (int)fn["L2gradient"] != 0; + } - if (!deviceSupports(SHARED_ATOMICS)) - CV_Error(cv::Error::StsNotImplemented, "The device doesn't support shared atomics"); + private: + void createBuf(Size image_size); + void CannyCaller(GpuMat& edges); - if( low_thresh > high_thresh ) - std::swap( low_thresh, high_thresh); + double low_thresh_; + double high_thresh_; + int apperture_size_; + bool L2gradient_; - dst.create(src.size(), CV_8U); - buf.create(src.size(), apperture_size); + GpuMat dx_, dy_; + GpuMat mag_; + GpuMat map_; + GpuMat st1_, st2_; + Ptr filterDX_, filterDY_; + int old_apperture_size_; + }; - if (apperture_size == 3) + void CannyImpl::detect(InputArray _image, OutputArray _edges) { - Size wholeSize; - Point ofs; - src.locateROI(wholeSize, ofs); - GpuMat srcWhole(wholeSize, src.type(), src.datastart, src.step); + GpuMat image = _image.getGpuMat(); + + CV_Assert( image.type() == CV_8UC1 ); + CV_Assert( deviceSupports(SHARED_ATOMICS) ); + + if (low_thresh_ > high_thresh_) + std::swap(low_thresh_, high_thresh_); + + createBuf(image.size()); - calcMagnitude(srcWhole, ofs.x, ofs.y, buf.dx, buf.dy, buf.mag, L2gradient); + _edges.create(image.size(), CV_8UC1); + GpuMat edges = _edges.getGpuMat(); + + if (apperture_size_ == 3) + { + Size wholeSize; + Point ofs; + image.locateROI(wholeSize, ofs); + GpuMat srcWhole(wholeSize, image.type(), image.datastart, image.step); + + canny::calcMagnitude(srcWhole, ofs.x, ofs.y, dx_, dy_, mag_, L2gradient_); + } + else + { + filterDX_->apply(image, dx_); + filterDY_->apply(image, dy_); + + canny::calcMagnitude(dx_, dy_, mag_, L2gradient_); + } + + CannyCaller(edges); } - else + + void CannyImpl::detect(InputArray _dx, InputArray _dy, OutputArray _edges) { - buf.filterDX->apply(src, buf.dx); - buf.filterDY->apply(src, buf.dy); + GpuMat dx = _dx.getGpuMat(); + GpuMat dy = _dy.getGpuMat(); + + CV_Assert( dx.type() == CV_32SC1 ); + CV_Assert( dy.type() == dx.type() && dy.size() == dx.size() ); + CV_Assert( deviceSupports(SHARED_ATOMICS) ); + + if (low_thresh_ > high_thresh_) + std::swap(low_thresh_, high_thresh_); + + createBuf(dx.size()); + + _edges.create(dx.size(), CV_8UC1); + GpuMat edges = _edges.getGpuMat(); + + canny::calcMagnitude(dx_, dy_, mag_, L2gradient_); - calcMagnitude(buf.dx, buf.dy, buf.mag, L2gradient); + CannyCaller(edges); } - CannyCaller(buf.dx, buf.dy, buf, dst, static_cast(low_thresh), static_cast(high_thresh)); -} + void CannyImpl::createBuf(Size image_size) + { + ensureSizeIsEnough(image_size, CV_32SC1, dx_); + ensureSizeIsEnough(image_size, CV_32SC1, dy_); -void cv::gpu::Canny(const GpuMat& dx, const GpuMat& dy, GpuMat& dst, double low_thresh, double high_thresh, bool L2gradient) -{ - CannyBuf buf; - Canny(dx, dy, buf, dst, low_thresh, high_thresh, L2gradient); -} + if (apperture_size_ != 3 && apperture_size_ != old_apperture_size_) + { + filterDX_ = gpu::createDerivFilter(CV_8UC1, CV_32S, 1, 0, apperture_size_, false, 1, BORDER_REPLICATE); + filterDY_ = gpu::createDerivFilter(CV_8UC1, CV_32S, 0, 1, apperture_size_, false, 1, BORDER_REPLICATE); + old_apperture_size_ = apperture_size_; + } -void cv::gpu::Canny(const GpuMat& dx, const GpuMat& dy, CannyBuf& buf, GpuMat& dst, double low_thresh, double high_thresh, bool L2gradient) -{ - using namespace canny; + ensureSizeIsEnough(image_size, CV_32FC1, mag_); + ensureSizeIsEnough(image_size, CV_32SC1, map_); - CV_Assert(TargetArchs::builtWith(SHARED_ATOMICS) && DeviceInfo().supports(SHARED_ATOMICS)); - CV_Assert(dx.type() == CV_32SC1 && dy.type() == CV_32SC1 && dx.size() == dy.size()); + ensureSizeIsEnough(1, image_size.area(), CV_16UC2, st1_); + ensureSizeIsEnough(1, image_size.area(), CV_16UC2, st2_); + } + + void CannyImpl::CannyCaller(GpuMat& edges) + { + map_.setTo(Scalar::all(0)); + canny::calcMap(dx_, dy_, mag_, map_, static_cast(low_thresh_), static_cast(high_thresh_)); - if( low_thresh > high_thresh ) - std::swap( low_thresh, high_thresh); + canny::edgesHysteresisLocal(map_, st1_.ptr()); - dst.create(dx.size(), CV_8U); - buf.create(dx.size(), -1); + canny::edgesHysteresisGlobal(map_, st1_.ptr(), st2_.ptr()); - calcMagnitude(dx, dy, buf.mag, L2gradient); + canny::getEdges(map_, edges); + } +} - CannyCaller(dx, dy, buf, dst, static_cast(low_thresh), static_cast(high_thresh)); +Ptr cv::gpu::createCannyEdgeDetector(double low_thresh, double high_thresh, int apperture_size, bool L2gradient) +{ + return new CannyImpl(low_thresh, high_thresh, apperture_size, L2gradient); } #endif /* !defined (HAVE_CUDA) */ diff --git a/modules/gpuimgproc/src/hough.cpp b/modules/gpuimgproc/src/hough.cpp index 15e5297623..a91725fff4 100644 --- a/modules/gpuimgproc/src/hough.cpp +++ b/modules/gpuimgproc/src/hough.cpp @@ -244,7 +244,8 @@ void cv::gpu::HoughCircles(const GpuMat& src, GpuMat& circles, HoughCirclesBuf& const float idp = 1.0f / dp; - cv::gpu::Canny(src, buf.cannyBuf, buf.edges, std::max(cannyThreshold / 2, 1), cannyThreshold); + buf.canny = gpu::createCannyEdgeDetector(std::max(cannyThreshold / 2, 1), cannyThreshold); + buf.canny->detect(src, buf.edges); ensureSizeIsEnough(2, src.size().area(), CV_32SC1, buf.list); unsigned int* srcPoints = buf.list.ptr(0); @@ -260,7 +261,13 @@ void cv::gpu::HoughCircles(const GpuMat& src, GpuMat& circles, HoughCirclesBuf& ensureSizeIsEnough(cvCeil(src.rows * idp) + 2, cvCeil(src.cols * idp) + 2, CV_32SC1, buf.accum); buf.accum.setTo(Scalar::all(0)); - circlesAccumCenters_gpu(srcPoints, pointsCount, buf.cannyBuf.dx, buf.cannyBuf.dy, buf.accum, minRadius, maxRadius, idp); + Ptr filterDX = gpu::createSobelFilter(CV_8UC1, CV_32S, 1, 0); + Ptr filterDY = gpu::createSobelFilter(CV_8UC1, CV_32S, 0, 1); + GpuMat dx, dy; + filterDX->apply(src, dx); + filterDY->apply(src, dy); + + circlesAccumCenters_gpu(srcPoints, pointsCount, dx, dy, buf.accum, minRadius, maxRadius, idp); int centersCount = buildCentersList_gpu(buf.accum, centers, votesThreshold); if (centersCount == 0) @@ -1355,6 +1362,11 @@ Ptr cv::gpu::GeneralizedHough_GPU::create(int method) return Ptr(); } +cv::gpu::GeneralizedHough_GPU::GeneralizedHough_GPU() +{ + canny_ = gpu::createCannyEdgeDetector(50, 100); +} + cv::gpu::GeneralizedHough_GPU::~GeneralizedHough_GPU() { } @@ -1365,12 +1377,21 @@ void cv::gpu::GeneralizedHough_GPU::setTemplate(const GpuMat& templ, int cannyTh CV_Assert(cannyThreshold > 0); ensureSizeIsEnough(templ.size(), CV_8UC1, edges_); - Canny(templ, cannyBuf_, edges_, cannyThreshold / 2, cannyThreshold); + + canny_->setLowThreshold(cannyThreshold / 2); + canny_->setHighThreshold(cannyThreshold); + canny_->detect(templ, edges_); if (templCenter == Point(-1, -1)) templCenter = Point(templ.cols / 2, templ.rows / 2); - setTemplateImpl(edges_, cannyBuf_.dx, cannyBuf_.dy, templCenter); + Ptr filterDX = gpu::createSobelFilter(CV_8UC1, CV_32S, 1, 0); + Ptr filterDY = gpu::createSobelFilter(CV_8UC1, CV_32S, 0, 1); + GpuMat dx, dy; + filterDX->apply(templ, dx); + filterDY->apply(templ, dy); + + setTemplateImpl(edges_, dx, dy, templCenter); } void cv::gpu::GeneralizedHough_GPU::setTemplate(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, Point templCenter) @@ -1387,9 +1408,18 @@ void cv::gpu::GeneralizedHough_GPU::detect(const GpuMat& image, GpuMat& position CV_Assert(cannyThreshold > 0); ensureSizeIsEnough(image.size(), CV_8UC1, edges_); - Canny(image, cannyBuf_, edges_, cannyThreshold / 2, cannyThreshold); - detectImpl(edges_, cannyBuf_.dx, cannyBuf_.dy, positions); + canny_->setLowThreshold(cannyThreshold / 2); + canny_->setHighThreshold(cannyThreshold); + canny_->detect(image, edges_); + + Ptr filterDX = gpu::createSobelFilter(CV_8UC1, CV_32S, 1, 0); + Ptr filterDY = gpu::createSobelFilter(CV_8UC1, CV_32S, 0, 1); + GpuMat dx, dy; + filterDX->apply(image, dx); + filterDY->apply(image, dy); + + detectImpl(edges_, dx, dy, positions); } void cv::gpu::GeneralizedHough_GPU::detect(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, GpuMat& positions) @@ -1425,7 +1455,6 @@ void cv::gpu::GeneralizedHough_GPU::download(const GpuMat& d_positions, OutputAr void cv::gpu::GeneralizedHough_GPU::release() { edges_.release(); - cannyBuf_.release(); releaseImpl(); } diff --git a/modules/gpuimgproc/test/test_canny.cpp b/modules/gpuimgproc/test/test_canny.cpp index b3ab5addc6..3d9d350165 100644 --- a/modules/gpuimgproc/test/test_canny.cpp +++ b/modules/gpuimgproc/test/test_canny.cpp @@ -81,28 +81,15 @@ GPU_TEST_P(Canny, Accuracy) double low_thresh = 50.0; double high_thresh = 100.0; - if (!supportFeature(devInfo, cv::gpu::SHARED_ATOMICS)) - { - try - { - cv::gpu::GpuMat edges; - cv::gpu::Canny(loadMat(img), edges, low_thresh, high_thresh, apperture_size, useL2gradient); - } - catch (const cv::Exception& e) - { - ASSERT_EQ(cv::Error::StsNotImplemented, e.code); - } - } - else - { - cv::gpu::GpuMat edges; - cv::gpu::Canny(loadMat(img, useRoi), edges, low_thresh, high_thresh, apperture_size, useL2gradient); + cv::Ptr canny = cv::gpu::createCannyEdgeDetector(low_thresh, high_thresh, apperture_size, useL2gradient); - cv::Mat edges_gold; - cv::Canny(img, edges_gold, low_thresh, high_thresh, apperture_size, useL2gradient); + cv::gpu::GpuMat edges; + canny->detect(loadMat(img, useRoi), edges); - EXPECT_MAT_SIMILAR(edges_gold, edges, 2e-2); - } + cv::Mat edges_gold; + cv::Canny(img, edges_gold, low_thresh, high_thresh, apperture_size, useL2gradient); + + EXPECT_MAT_SIMILAR(edges_gold, edges, 2e-2); } INSTANTIATE_TEST_CASE_P(GPU_ImgProc, Canny, testing::Combine( diff --git a/samples/gpu/houghlines.cpp b/samples/gpu/houghlines.cpp index 299fa47cb4..38d9c8298e 100644 --- a/samples/gpu/houghlines.cpp +++ b/samples/gpu/houghlines.cpp @@ -31,7 +31,7 @@ int main(int argc, const char* argv[]) } Mat mask; - Canny(src, mask, 100, 200, 3); + cv::Canny(src, mask, 100, 200, 3); Mat dst_cpu; cv::cvtColor(mask, dst_cpu, COLOR_GRAY2BGR); diff --git a/samples/gpu/performance/tests.cpp b/samples/gpu/performance/tests.cpp index 7193ee93ae..99ba56cddb 100644 --- a/samples/gpu/performance/tests.cpp +++ b/samples/gpu/performance/tests.cpp @@ -1072,12 +1072,13 @@ TEST(Canny) gpu::GpuMat d_img(img); gpu::GpuMat d_edges; - gpu::CannyBuf d_buf; - gpu::Canny(d_img, d_buf, d_edges, 50.0, 100.0); + Ptr canny = gpu::createCannyEdgeDetector(50.0, 100.0); + + canny->detect(d_img, d_edges); GPU_ON; - gpu::Canny(d_img, d_buf, d_edges, 50.0, 100.0); + canny->detect(d_img, d_edges); GPU_OFF; } From 1652540a1fe74f120eae506737fd35bd5bd786a3 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 30 Apr 2013 12:51:33 +0400 Subject: [PATCH 04/17] refactored HoughLines (converted it into Algorithm) --- modules/gpu/perf4au/main.cpp | 7 +- .../gpuimgproc/include/opencv2/gpuimgproc.hpp | 81 ++++- modules/gpuimgproc/perf/perf_hough.cpp | 10 +- modules/gpuimgproc/src/hough.cpp | 292 +++++++++++++----- modules/gpuimgproc/test/test_hough.cpp | 6 +- samples/gpu/houghlines.cpp | 7 +- 6 files changed, 305 insertions(+), 98 deletions(-) diff --git a/modules/gpu/perf4au/main.cpp b/modules/gpu/perf4au/main.cpp index d86f7b8f3c..df8a793ac5 100644 --- a/modules/gpu/perf4au/main.cpp +++ b/modules/gpu/perf4au/main.cpp @@ -86,13 +86,14 @@ PERF_TEST_P(Image, HoughLinesP, testing::Values(std::string("im1_1280x800.jpg")) { cv::gpu::GpuMat d_image(image); cv::gpu::GpuMat d_lines; - cv::gpu::HoughLinesBuf d_buf; - cv::gpu::HoughLinesP(d_image, d_lines, d_buf, rho, theta, minLineLenght, maxLineGap); + cv::Ptr hough = cv::gpu::createHoughSegmentDetector(rho, theta, minLineLenght, maxLineGap); + + hough->detect(d_image, d_lines); TEST_CYCLE() { - cv::gpu::HoughLinesP(d_image, d_lines, d_buf, rho, theta, minLineLenght, maxLineGap); + hough->detect(d_image, d_lines); } } else diff --git a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp index ea68590b51..d9b9d2703d 100644 --- a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp +++ b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp @@ -220,18 +220,82 @@ inline void Canny(InputArray dx, InputArray dy, OutputArray edges, double low_th /////////////////////////// Hough Transform //////////////////////////// -struct HoughLinesBuf +////////////////////////////////////// +// HoughLines + +class CV_EXPORTS HoughLinesDetector : public Algorithm { - GpuMat accum; - GpuMat list; +public: + virtual void detect(InputArray src, OutputArray lines) = 0; + virtual void downloadResults(InputArray d_lines, OutputArray h_lines, OutputArray h_votes = noArray()) = 0; + + virtual void setRho(float rho) = 0; + virtual float getRho() const = 0; + + virtual void setTheta(float theta) = 0; + virtual float getTheta() const = 0; + + virtual void setThreshold(int threshold) = 0; + virtual int getThreshold() const = 0; + + virtual void setDoSort(bool doSort) = 0; + virtual bool getDoSort() const = 0; + + virtual void setMaxLines(int maxLines) = 0; + virtual int getMaxLines() const = 0; }; -CV_EXPORTS void HoughLines(const GpuMat& src, GpuMat& lines, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096); -CV_EXPORTS void HoughLines(const GpuMat& src, GpuMat& lines, HoughLinesBuf& buf, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096); -CV_EXPORTS void HoughLinesDownload(const GpuMat& d_lines, OutputArray h_lines, OutputArray h_votes = noArray()); +CV_EXPORTS Ptr createHoughLinesDetector(float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096); + +// obsolete + +__OPENCV_GPUIMGPROC_DEPR_BEFORE__ void HoughLines(InputArray src, OutputArray lines, float rho, float theta, int threshold, + bool doSort = false, int maxLines = 4096) __OPENCV_GPUIMGPROC_DEPR_AFTER__; + +inline void HoughLines(InputArray src, OutputArray lines, float rho, float theta, int threshold, bool doSort, int maxLines) +{ + gpu::createHoughLinesDetector(rho, theta, threshold, doSort, maxLines)->detect(src, lines); +} + +////////////////////////////////////// +// HoughLinesP //! finds line segments in the black-n-white image using probabalistic Hough transform -CV_EXPORTS void HoughLinesP(const GpuMat& image, GpuMat& lines, HoughLinesBuf& buf, float rho, float theta, int minLineLength, int maxLineGap, int maxLines = 4096); +class CV_EXPORTS HoughSegmentDetector : public Algorithm +{ +public: + virtual void detect(InputArray src, OutputArray lines) = 0; + + virtual void setRho(float rho) = 0; + virtual float getRho() const = 0; + + virtual void setTheta(float theta) = 0; + virtual float getTheta() const = 0; + + virtual void setMinLineLength(int minLineLength) = 0; + virtual int getMinLineLength() const = 0; + + virtual void setMaxLineGap(int maxLineGap) = 0; + virtual int getMaxLineGap() const = 0; + + virtual void setMaxLines(int maxLines) = 0; + virtual int getMaxLines() const = 0; +}; + +CV_EXPORTS Ptr createHoughSegmentDetector(float rho, float theta, int minLineLength, int maxLineGap, int maxLines = 4096); + +// obsolete + +__OPENCV_GPUIMGPROC_DEPR_BEFORE__ void HoughLinesP(InputArray src, OutputArray lines, + float rho, float theta, int minLineLength, int maxLineGap, int maxLines = 4096) __OPENCV_GPUIMGPROC_DEPR_AFTER__; + +inline void HoughLinesP(InputArray src, OutputArray lines, float rho, float theta, int minLineLength, int maxLineGap, int maxLines) +{ + gpu::createHoughSegmentDetector(rho, theta, minLineLength, maxLineGap, maxLines)->detect(src, lines); +} + +////////////////////////////////////// +// HoughCircles struct HoughCirclesBuf { @@ -245,6 +309,9 @@ CV_EXPORTS void HoughCircles(const GpuMat& src, GpuMat& circles, int method, flo CV_EXPORTS void HoughCircles(const GpuMat& src, GpuMat& circles, HoughCirclesBuf& buf, int method, float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles = 4096); CV_EXPORTS void HoughCirclesDownload(const GpuMat& d_circles, OutputArray h_circles); +////////////////////////////////////// +// GeneralizedHough + //! finds arbitrary template in the grayscale image using Generalized Hough Transform //! Ballard, D.H. (1981). Generalizing the Hough transform to detect arbitrary shapes. Pattern Recognition 13 (2): 111-122. //! Guil, N., González-Linares, J.M. and Zapata, E.L. (1999). Bidimensional shape detection using an invariant approach. Pattern Recognition 32 (6): 1025-1038. diff --git a/modules/gpuimgproc/perf/perf_hough.cpp b/modules/gpuimgproc/perf/perf_hough.cpp index a4aac0d02b..f589402878 100644 --- a/modules/gpuimgproc/perf/perf_hough.cpp +++ b/modules/gpuimgproc/perf/perf_hough.cpp @@ -103,9 +103,10 @@ PERF_TEST_P(Sz, HoughLines, { const cv::gpu::GpuMat d_src(src); cv::gpu::GpuMat d_lines; - cv::gpu::HoughLinesBuf d_buf; - TEST_CYCLE() cv::gpu::HoughLines(d_src, d_lines, d_buf, rho, theta, threshold); + cv::Ptr hough = cv::gpu::createHoughLinesDetector(rho, theta, threshold); + + TEST_CYCLE() hough->detect(d_src, d_lines); cv::Mat gpu_lines(d_lines.row(0)); cv::Vec2f* begin = gpu_lines.ptr(0); @@ -151,9 +152,10 @@ PERF_TEST_P(Image, HoughLinesP, { const cv::gpu::GpuMat d_mask(mask); cv::gpu::GpuMat d_lines; - cv::gpu::HoughLinesBuf d_buf; - TEST_CYCLE() cv::gpu::HoughLinesP(d_mask, d_lines, d_buf, rho, theta, minLineLenght, maxLineGap); + cv::Ptr hough = cv::gpu::createHoughSegmentDetector(rho, theta, minLineLenght, maxLineGap); + + TEST_CYCLE() hough->detect(d_mask, d_lines); cv::Mat gpu_lines(d_lines); cv::Vec4i* begin = gpu_lines.ptr(); diff --git a/modules/gpuimgproc/src/hough.cpp b/modules/gpuimgproc/src/hough.cpp index a91725fff4..0e5b255b71 100644 --- a/modules/gpuimgproc/src/hough.cpp +++ b/modules/gpuimgproc/src/hough.cpp @@ -47,11 +47,9 @@ using namespace cv::gpu; #if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) -void cv::gpu::HoughLines(const GpuMat&, GpuMat&, float, float, int, bool, int) { throw_no_cuda(); } -void cv::gpu::HoughLines(const GpuMat&, GpuMat&, HoughLinesBuf&, float, float, int, bool, int) { throw_no_cuda(); } -void cv::gpu::HoughLinesDownload(const GpuMat&, OutputArray, OutputArray) { throw_no_cuda(); } +Ptr cv::gpu::createHoughLinesDetector(float, float, int, bool, int) { throw_no_cuda(); return Ptr(); } -void cv::gpu::HoughLinesP(const GpuMat&, GpuMat&, HoughLinesBuf&, float, float, int, int, int) { throw_no_cuda(); } +Ptr cv::gpu::createHoughSegmentDetector(float, float, int, int, int) { throw_no_cuda(); return Ptr(); } void cv::gpu::HoughCircles(const GpuMat&, GpuMat&, int, float, float, int, int, int, int, int) { throw_no_cuda(); } void cv::gpu::HoughCircles(const GpuMat&, GpuMat&, HoughCirclesBuf&, int, float, float, int, int, int, int, int) { throw_no_cuda(); } @@ -79,7 +77,7 @@ namespace cv { namespace gpu { namespace cudev }}} ////////////////////////////////////////////////////////// -// HoughLines +// HoughLinesDetector namespace cv { namespace gpu { namespace cudev { @@ -90,74 +88,139 @@ namespace cv { namespace gpu { namespace cudev } }}} -void cv::gpu::HoughLines(const GpuMat& src, GpuMat& lines, float rho, float theta, int threshold, bool doSort, int maxLines) +namespace { - HoughLinesBuf buf; - HoughLines(src, lines, buf, rho, theta, threshold, doSort, maxLines); -} + class HoughLinesDetectorImpl : public HoughLinesDetector + { + public: + HoughLinesDetectorImpl(float rho, float theta, int threshold, bool doSort, int maxLines) : + rho_(rho), theta_(theta), threshold_(threshold), doSort_(doSort), maxLines_(maxLines) + { + } -void cv::gpu::HoughLines(const GpuMat& src, GpuMat& lines, HoughLinesBuf& buf, float rho, float theta, int threshold, bool doSort, int maxLines) -{ - using namespace cv::gpu::cudev::hough; + void detect(InputArray src, OutputArray lines); + void downloadResults(InputArray d_lines, OutputArray h_lines, OutputArray h_votes = noArray()); - CV_Assert(src.type() == CV_8UC1); - CV_Assert(src.cols < std::numeric_limits::max()); - CV_Assert(src.rows < std::numeric_limits::max()); + void setRho(float rho) { rho_ = rho; } + float getRho() const { return rho_; } - ensureSizeIsEnough(1, src.size().area(), CV_32SC1, buf.list); - unsigned int* srcPoints = buf.list.ptr(); + void setTheta(float theta) { theta_ = theta; } + float getTheta() const { return theta_; } - const int pointsCount = buildPointList_gpu(src, srcPoints); - if (pointsCount == 0) - { - lines.release(); - return; - } + void setThreshold(int threshold) { threshold_ = threshold; } + int getThreshold() const { return threshold_; } - const int numangle = cvRound(CV_PI / theta); - const int numrho = cvRound(((src.cols + src.rows) * 2 + 1) / rho); - CV_Assert(numangle > 0 && numrho > 0); + void setDoSort(bool doSort) { doSort_ = doSort; } + bool getDoSort() const { return doSort_; } - ensureSizeIsEnough(numangle + 2, numrho + 2, CV_32SC1, buf.accum); - buf.accum.setTo(Scalar::all(0)); + void setMaxLines(int maxLines) { maxLines_ = maxLines; } + int getMaxLines() const { return maxLines_; } - DeviceInfo devInfo; - linesAccum_gpu(srcPoints, pointsCount, buf.accum, rho, theta, devInfo.sharedMemPerBlock(), devInfo.supports(FEATURE_SET_COMPUTE_20)); + void write(FileStorage& fs) const + { + fs << "name" << "HoughLinesDetector_GPU" + << "rho" << rho_ + << "theta" << theta_ + << "threshold" << threshold_ + << "doSort" << doSort_ + << "maxLines" << maxLines_; + } - ensureSizeIsEnough(2, maxLines, CV_32FC2, lines); + void read(const FileNode& fn) + { + CV_Assert( String(fn["name"]) == "HoughLinesDetector_GPU" ); + rho_ = (float)fn["rho"]; + theta_ = (float)fn["theta"]; + threshold_ = (int)fn["threshold"]; + doSort_ = (int)fn["doSort"] != 0; + maxLines_ = (int)fn["maxLines"]; + } - int linesCount = linesGetResult_gpu(buf.accum, lines.ptr(0), lines.ptr(1), maxLines, rho, theta, threshold, doSort); - if (linesCount > 0) - lines.cols = linesCount; - else - lines.release(); -} + private: + float rho_; + float theta_; + int threshold_; + bool doSort_; + int maxLines_; -void cv::gpu::HoughLinesDownload(const GpuMat& d_lines, OutputArray h_lines_, OutputArray h_votes_) -{ - if (d_lines.empty()) + GpuMat accum_; + GpuMat list_; + GpuMat result_; + }; + + void HoughLinesDetectorImpl::detect(InputArray _src, OutputArray lines) { - h_lines_.release(); - if (h_votes_.needed()) - h_votes_.release(); - return; - } + using namespace cv::gpu::cudev::hough; - CV_Assert(d_lines.rows == 2 && d_lines.type() == CV_32FC2); + GpuMat src = _src.getGpuMat(); - h_lines_.create(1, d_lines.cols, CV_32FC2); - Mat h_lines = h_lines_.getMat(); - d_lines.row(0).download(h_lines); + CV_Assert( src.type() == CV_8UC1 ); + CV_Assert( src.cols < std::numeric_limits::max() ); + CV_Assert( src.rows < std::numeric_limits::max() ); - if (h_votes_.needed()) + ensureSizeIsEnough(1, src.size().area(), CV_32SC1, list_); + unsigned int* srcPoints = list_.ptr(); + + const int pointsCount = buildPointList_gpu(src, srcPoints); + if (pointsCount == 0) + { + lines.release(); + return; + } + + const int numangle = cvRound(CV_PI / theta_); + const int numrho = cvRound(((src.cols + src.rows) * 2 + 1) / rho_); + CV_Assert( numangle > 0 && numrho > 0 ); + + ensureSizeIsEnough(numangle + 2, numrho + 2, CV_32SC1, accum_); + accum_.setTo(Scalar::all(0)); + + DeviceInfo devInfo; + linesAccum_gpu(srcPoints, pointsCount, accum_, rho_, theta_, devInfo.sharedMemPerBlock(), devInfo.supports(FEATURE_SET_COMPUTE_20)); + + ensureSizeIsEnough(2, maxLines_, CV_32FC2, result_); + + int linesCount = linesGetResult_gpu(accum_, result_.ptr(0), result_.ptr(1), maxLines_, rho_, theta_, threshold_, doSort_); + + if (linesCount == 0) + { + lines.release(); + return; + } + + result_.cols = linesCount; + result_.copyTo(lines); + } + + void HoughLinesDetectorImpl::downloadResults(InputArray _d_lines, OutputArray h_lines, OutputArray h_votes) { - h_votes_.create(1, d_lines.cols, CV_32SC1); - Mat h_votes = h_votes_.getMat(); - GpuMat d_votes(1, d_lines.cols, CV_32SC1, const_cast(d_lines.ptr(1))); - d_votes.download(h_votes); + GpuMat d_lines = _d_lines.getGpuMat(); + + if (d_lines.empty()) + { + h_lines.release(); + if (h_votes.needed()) + h_votes.release(); + return; + } + + CV_Assert( d_lines.rows == 2 && d_lines.type() == CV_32FC2 ); + + d_lines.row(0).download(h_lines); + + if (h_votes.needed()) + { + GpuMat d_votes(1, d_lines.cols, CV_32SC1, d_lines.ptr(1)); + d_votes.download(h_votes); + } } } +Ptr cv::gpu::createHoughLinesDetector(float rho, float theta, int threshold, bool doSort, int maxLines) +{ + return new HoughLinesDetectorImpl(rho, theta, threshold, doSort, maxLines); +} + ////////////////////////////////////////////////////////// // HoughLinesP @@ -169,42 +232,113 @@ namespace cv { namespace gpu { namespace cudev } }}} -void cv::gpu::HoughLinesP(const GpuMat& src, GpuMat& lines, HoughLinesBuf& buf, float rho, float theta, int minLineLength, int maxLineGap, int maxLines) +namespace { - using namespace cv::gpu::cudev::hough; + class PHoughLinesDetectorImpl : public HoughSegmentDetector + { + public: + PHoughLinesDetectorImpl(float rho, float theta, int minLineLength, int maxLineGap, int maxLines) : + rho_(rho), theta_(theta), minLineLength_(minLineLength), maxLineGap_(maxLineGap), maxLines_(maxLines) + { + } - CV_Assert( src.type() == CV_8UC1 ); - CV_Assert( src.cols < std::numeric_limits::max() ); - CV_Assert( src.rows < std::numeric_limits::max() ); + void detect(InputArray src, OutputArray lines); - ensureSizeIsEnough(1, src.size().area(), CV_32SC1, buf.list); - unsigned int* srcPoints = buf.list.ptr(); + void setRho(float rho) { rho_ = rho; } + float getRho() const { return rho_; } - const int pointsCount = buildPointList_gpu(src, srcPoints); - if (pointsCount == 0) + void setTheta(float theta) { theta_ = theta; } + float getTheta() const { return theta_; } + + void setMinLineLength(int minLineLength) { minLineLength_ = minLineLength; } + int getMinLineLength() const { return minLineLength_; } + + void setMaxLineGap(int maxLineGap) { maxLineGap_ = maxLineGap; } + int getMaxLineGap() const { return maxLineGap_; } + + void setMaxLines(int maxLines) { maxLines_ = maxLines; } + int getMaxLines() const { return maxLines_; } + + void write(FileStorage& fs) const + { + fs << "name" << "PHoughLinesDetector_GPU" + << "rho" << rho_ + << "theta" << theta_ + << "minLineLength" << minLineLength_ + << "maxLineGap" << maxLineGap_ + << "maxLines" << maxLines_; + } + + void read(const FileNode& fn) + { + CV_Assert( String(fn["name"]) == "PHoughLinesDetector_GPU" ); + rho_ = (float)fn["rho"]; + theta_ = (float)fn["theta"]; + minLineLength_ = (int)fn["minLineLength"]; + maxLineGap_ = (int)fn["maxLineGap"]; + maxLines_ = (int)fn["maxLines"]; + } + + private: + float rho_; + float theta_; + int minLineLength_; + int maxLineGap_; + int maxLines_; + + GpuMat accum_; + GpuMat list_; + GpuMat result_; + }; + + void PHoughLinesDetectorImpl::detect(InputArray _src, OutputArray lines) { - lines.release(); - return; - } + using namespace cv::gpu::cudev::hough; - const int numangle = cvRound(CV_PI / theta); - const int numrho = cvRound(((src.cols + src.rows) * 2 + 1) / rho); - CV_Assert( numangle > 0 && numrho > 0 ); + GpuMat src = _src.getGpuMat(); - ensureSizeIsEnough(numangle + 2, numrho + 2, CV_32SC1, buf.accum); - buf.accum.setTo(Scalar::all(0)); + CV_Assert( src.type() == CV_8UC1 ); + CV_Assert( src.cols < std::numeric_limits::max() ); + CV_Assert( src.rows < std::numeric_limits::max() ); + + ensureSizeIsEnough(1, src.size().area(), CV_32SC1, list_); + unsigned int* srcPoints = list_.ptr(); + + const int pointsCount = buildPointList_gpu(src, srcPoints); + if (pointsCount == 0) + { + lines.release(); + return; + } - DeviceInfo devInfo; - linesAccum_gpu(srcPoints, pointsCount, buf.accum, rho, theta, devInfo.sharedMemPerBlock(), devInfo.supports(FEATURE_SET_COMPUTE_20)); + const int numangle = cvRound(CV_PI / theta_); + const int numrho = cvRound(((src.cols + src.rows) * 2 + 1) / rho_); + CV_Assert( numangle > 0 && numrho > 0 ); - ensureSizeIsEnough(1, maxLines, CV_32SC4, lines); + ensureSizeIsEnough(numangle + 2, numrho + 2, CV_32SC1, accum_); + accum_.setTo(Scalar::all(0)); - int linesCount = houghLinesProbabilistic_gpu(src, buf.accum, lines.ptr(), maxLines, rho, theta, maxLineGap, minLineLength); + DeviceInfo devInfo; + linesAccum_gpu(srcPoints, pointsCount, accum_, rho_, theta_, devInfo.sharedMemPerBlock(), devInfo.supports(FEATURE_SET_COMPUTE_20)); - if (linesCount > 0) - lines.cols = linesCount; - else - lines.release(); + ensureSizeIsEnough(1, maxLines_, CV_32SC4, result_); + + int linesCount = houghLinesProbabilistic_gpu(src, accum_, result_.ptr(), maxLines_, rho_, theta_, maxLineGap_, minLineLength_); + + if (linesCount == 0) + { + lines.release(); + return; + } + + result_.cols = linesCount; + result_.copyTo(lines); + } +} + +Ptr cv::gpu::createHoughSegmentDetector(float rho, float theta, int minLineLength, int maxLineGap, int maxLines) +{ + return new PHoughLinesDetectorImpl(rho, theta, minLineLength, maxLineGap, maxLines); } ////////////////////////////////////////////////////////// diff --git a/modules/gpuimgproc/test/test_hough.cpp b/modules/gpuimgproc/test/test_hough.cpp index a044901041..6e03eaad2c 100644 --- a/modules/gpuimgproc/test/test_hough.cpp +++ b/modules/gpuimgproc/test/test_hough.cpp @@ -94,11 +94,13 @@ GPU_TEST_P(HoughLines, Accuracy) cv::Mat src(size, CV_8UC1); generateLines(src); + cv::Ptr hough = cv::gpu::createHoughLinesDetector(rho, theta, threshold); + cv::gpu::GpuMat d_lines; - cv::gpu::HoughLines(loadMat(src, useRoi), d_lines, rho, theta, threshold); + hough->detect(loadMat(src, useRoi), d_lines); std::vector lines; - cv::gpu::HoughLinesDownload(d_lines, lines); + hough->downloadResults(d_lines, lines); cv::Mat dst(size, CV_8UC1); drawLines(dst, lines); diff --git a/samples/gpu/houghlines.cpp b/samples/gpu/houghlines.cpp index 38d9c8298e..4ede50b708 100644 --- a/samples/gpu/houghlines.cpp +++ b/samples/gpu/houghlines.cpp @@ -41,7 +41,7 @@ int main(int argc, const char* argv[]) { const int64 start = getTickCount(); - HoughLinesP(mask, lines_cpu, 1, CV_PI / 180, 50, 60, 5); + cv::HoughLinesP(mask, lines_cpu, 1, CV_PI / 180, 50, 60, 5); const double timeSec = (getTickCount() - start) / getTickFrequency(); cout << "CPU Time : " << timeSec * 1000 << " ms" << endl; @@ -56,11 +56,12 @@ int main(int argc, const char* argv[]) GpuMat d_src(mask); GpuMat d_lines; - HoughLinesBuf d_buf; { const int64 start = getTickCount(); - gpu::HoughLinesP(d_src, d_lines, d_buf, 1.0f, (float) (CV_PI / 180.0f), 50, 5); + Ptr hough = gpu::createHoughSegmentDetector(1.0f, (float) (CV_PI / 180.0f), 50, 5); + + hough->detect(d_src, d_lines); const double timeSec = (getTickCount() - start) / getTickFrequency(); cout << "GPU Time : " << timeSec * 1000 << " ms" << endl; From 4087a45e7325f77655357afef232996309abd0b6 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 30 Apr 2013 13:33:44 +0400 Subject: [PATCH 05/17] refactored HoughCircles (converted it into Algorithm) --- .../gpuimgproc/include/opencv2/gpuimgproc.hpp | 45 ++- modules/gpuimgproc/perf/perf_hough.cpp | 5 +- modules/gpuimgproc/src/canny.cpp | 3 + modules/gpuimgproc/src/hough.cpp | 288 +++++++++++------- modules/gpuimgproc/test/test_hough.cpp | 6 +- 5 files changed, 226 insertions(+), 121 deletions(-) diff --git a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp index d9b9d2703d..a4ed11e6f9 100644 --- a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp +++ b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp @@ -297,17 +297,46 @@ inline void HoughLinesP(InputArray src, OutputArray lines, float rho, float thet ////////////////////////////////////// // HoughCircles -struct HoughCirclesBuf +class CV_EXPORTS HoughCirclesDetector : public Algorithm { - GpuMat edges; - GpuMat accum; - GpuMat list; - Ptr canny; +public: + virtual void detect(InputArray src, OutputArray circles) = 0; + + virtual void setDp(float dp) = 0; + virtual float getDp() const = 0; + + virtual void setMinDist(float minDist) = 0; + virtual float getMinDist() const = 0; + + virtual void setCannyThreshold(int cannyThreshold) = 0; + virtual int getCannyThreshold() const = 0; + + virtual void setVotesThreshold(int votesThreshold) = 0; + virtual int getVotesThreshold() const = 0; + + virtual void setMinRadius(int minRadius) = 0; + virtual int getMinRadius() const = 0; + + virtual void setMaxRadius(int maxRadius) = 0; + virtual int getMaxRadius() const = 0; + + virtual void setMaxCircles(int maxCircles) = 0; + virtual int getMaxCircles() const = 0; }; -CV_EXPORTS void HoughCircles(const GpuMat& src, GpuMat& circles, int method, float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles = 4096); -CV_EXPORTS void HoughCircles(const GpuMat& src, GpuMat& circles, HoughCirclesBuf& buf, int method, float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles = 4096); -CV_EXPORTS void HoughCirclesDownload(const GpuMat& d_circles, OutputArray h_circles); +CV_EXPORTS Ptr createHoughCirclesDetector(float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles = 4096); + +// obsolete + +__OPENCV_GPUIMGPROC_DEPR_BEFORE__ void HoughCircles(InputArray src, OutputArray circles, + int method, float dp, float minDist, int cannyThreshold, int votesThreshold, + int minRadius, int maxRadius, int maxCircles = 4096) __OPENCV_GPUIMGPROC_DEPR_AFTER__; + +inline void HoughCircles(InputArray src, OutputArray circles, int /*method*/, float dp, float minDist, + int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles) +{ + gpu::createHoughCirclesDetector(dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius, maxCircles)->detect(src, circles); +} ////////////////////////////////////// // GeneralizedHough diff --git a/modules/gpuimgproc/perf/perf_hough.cpp b/modules/gpuimgproc/perf/perf_hough.cpp index f589402878..b0f41e5783 100644 --- a/modules/gpuimgproc/perf/perf_hough.cpp +++ b/modules/gpuimgproc/perf/perf_hough.cpp @@ -203,9 +203,10 @@ PERF_TEST_P(Sz_Dp_MinDist, HoughCircles, { const cv::gpu::GpuMat d_src(src); cv::gpu::GpuMat d_circles; - cv::gpu::HoughCirclesBuf d_buf; - TEST_CYCLE() cv::gpu::HoughCircles(d_src, d_circles, d_buf, cv::HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius); + cv::Ptr houghCircles = cv::gpu::createHoughCirclesDetector(dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius); + + TEST_CYCLE() houghCircles->detect(d_src, d_circles); cv::Mat gpu_circles(d_circles); cv::Vec3f* begin = gpu_circles.ptr(0); diff --git a/modules/gpuimgproc/src/canny.cpp b/modules/gpuimgproc/src/canny.cpp index 888a224d75..3976bbd671 100644 --- a/modules/gpuimgproc/src/canny.cpp +++ b/modules/gpuimgproc/src/canny.cpp @@ -170,6 +170,9 @@ namespace CV_Assert( dy.type() == dx.type() && dy.size() == dx.size() ); CV_Assert( deviceSupports(SHARED_ATOMICS) ); + dx.copyTo(dx_); + dy.copyTo(dy_); + if (low_thresh_ > high_thresh_) std::swap(low_thresh_, high_thresh_); diff --git a/modules/gpuimgproc/src/hough.cpp b/modules/gpuimgproc/src/hough.cpp index 0e5b255b71..67d6e383c0 100644 --- a/modules/gpuimgproc/src/hough.cpp +++ b/modules/gpuimgproc/src/hough.cpp @@ -51,9 +51,7 @@ Ptr cv::gpu::createHoughLinesDetector(float, float, int Ptr cv::gpu::createHoughSegmentDetector(float, float, int, int, int) { throw_no_cuda(); return Ptr(); } -void cv::gpu::HoughCircles(const GpuMat&, GpuMat&, int, float, float, int, int, int, int, int) { throw_no_cuda(); } -void cv::gpu::HoughCircles(const GpuMat&, GpuMat&, HoughCirclesBuf&, int, float, float, int, int, int, int, int) { throw_no_cuda(); } -void cv::gpu::HoughCirclesDownload(const GpuMat&, OutputArray) { throw_no_cuda(); } +Ptr cv::gpu::createHoughCirclesDetector(float, float, int, int, int, int, int) { throw_no_cuda(); return Ptr(); } Ptr cv::gpu::GeneralizedHough_GPU::create(int) { throw_no_cuda(); return Ptr(); } cv::gpu::GeneralizedHough_GPU::~GeneralizedHough_GPU() {} @@ -355,158 +353,230 @@ namespace cv { namespace gpu { namespace cudev } }}} -void cv::gpu::HoughCircles(const GpuMat& src, GpuMat& circles, int method, float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles) +namespace { - HoughCirclesBuf buf; - HoughCircles(src, circles, buf, method, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius, maxCircles); -} + class HoughCirclesDetectorImpl : public HoughCirclesDetector + { + public: + HoughCirclesDetectorImpl(float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles); -void cv::gpu::HoughCircles(const GpuMat& src, GpuMat& circles, HoughCirclesBuf& buf, int method, - float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles) -{ - using namespace cv::gpu::cudev::hough; - - CV_Assert(src.type() == CV_8UC1); - CV_Assert(src.cols < std::numeric_limits::max()); - CV_Assert(src.rows < std::numeric_limits::max()); - CV_Assert(method == cv::HOUGH_GRADIENT); - CV_Assert(dp > 0); - CV_Assert(minRadius > 0 && maxRadius > minRadius); - CV_Assert(cannyThreshold > 0); - CV_Assert(votesThreshold > 0); - CV_Assert(maxCircles > 0); + void detect(InputArray src, OutputArray circles); - const float idp = 1.0f / dp; + void setDp(float dp) { dp_ = dp; } + float getDp() const { return dp_; } - buf.canny = gpu::createCannyEdgeDetector(std::max(cannyThreshold / 2, 1), cannyThreshold); - buf.canny->detect(src, buf.edges); + void setMinDist(float minDist) { minDist_ = minDist; } + float getMinDist() const { return minDist_; } - ensureSizeIsEnough(2, src.size().area(), CV_32SC1, buf.list); - unsigned int* srcPoints = buf.list.ptr(0); - unsigned int* centers = buf.list.ptr(1); + void setCannyThreshold(int cannyThreshold) { cannyThreshold_ = cannyThreshold; } + int getCannyThreshold() const { return cannyThreshold_; } - const int pointsCount = buildPointList_gpu(buf.edges, srcPoints); - if (pointsCount == 0) - { - circles.release(); - return; - } + void setVotesThreshold(int votesThreshold) { votesThreshold_ = votesThreshold; } + int getVotesThreshold() const { return votesThreshold_; } - ensureSizeIsEnough(cvCeil(src.rows * idp) + 2, cvCeil(src.cols * idp) + 2, CV_32SC1, buf.accum); - buf.accum.setTo(Scalar::all(0)); + void setMinRadius(int minRadius) { minRadius_ = minRadius; } + int getMinRadius() const { return minRadius_; } - Ptr filterDX = gpu::createSobelFilter(CV_8UC1, CV_32S, 1, 0); - Ptr filterDY = gpu::createSobelFilter(CV_8UC1, CV_32S, 0, 1); - GpuMat dx, dy; - filterDX->apply(src, dx); - filterDY->apply(src, dy); + void setMaxRadius(int maxRadius) { maxRadius_ = maxRadius; } + int getMaxRadius() const { return maxRadius_; } + + void setMaxCircles(int maxCircles) { maxCircles_ = maxCircles; } + int getMaxCircles() const { return maxCircles_; } + + void write(FileStorage& fs) const + { + fs << "name" << "HoughCirclesDetector_GPU" + << "dp" << dp_ + << "minDist" << minDist_ + << "cannyThreshold" << cannyThreshold_ + << "votesThreshold" << votesThreshold_ + << "minRadius" << minRadius_ + << "maxRadius" << maxRadius_ + << "maxCircles" << maxCircles_; + } - circlesAccumCenters_gpu(srcPoints, pointsCount, dx, dy, buf.accum, minRadius, maxRadius, idp); + void read(const FileNode& fn) + { + CV_Assert( String(fn["name"]) == "HoughCirclesDetector_GPU" ); + dp_ = (float)fn["dp"]; + minDist_ = (float)fn["minDist"]; + cannyThreshold_ = (int)fn["cannyThreshold"]; + votesThreshold_ = (int)fn["votesThreshold"]; + minRadius_ = (int)fn["minRadius"]; + maxRadius_ = (int)fn["maxRadius"]; + maxCircles_ = (int)fn["maxCircles"]; + } + + private: + float dp_; + float minDist_; + int cannyThreshold_; + int votesThreshold_; + int minRadius_; + int maxRadius_; + int maxCircles_; + + GpuMat dx_, dy_; + GpuMat edges_; + GpuMat accum_; + GpuMat list_; + GpuMat result_; + Ptr filterDx_; + Ptr filterDy_; + Ptr canny_; + }; - int centersCount = buildCentersList_gpu(buf.accum, centers, votesThreshold); - if (centersCount == 0) + HoughCirclesDetectorImpl::HoughCirclesDetectorImpl(float dp, float minDist, int cannyThreshold, int votesThreshold, + int minRadius, int maxRadius, int maxCircles) : + dp_(dp), minDist_(minDist), cannyThreshold_(cannyThreshold), votesThreshold_(votesThreshold), + minRadius_(minRadius), maxRadius_(maxRadius), maxCircles_(maxCircles) { - circles.release(); - return; + canny_ = gpu::createCannyEdgeDetector(std::max(cannyThreshold_ / 2, 1), cannyThreshold_); + + filterDx_ = gpu::createSobelFilter(CV_8UC1, CV_32S, 1, 0); + filterDy_ = gpu::createSobelFilter(CV_8UC1, CV_32S, 0, 1); } - if (minDist > 1) + void HoughCirclesDetectorImpl::detect(InputArray _src, OutputArray circles) { - cv::AutoBuffer oldBuf_(centersCount); - cv::AutoBuffer newBuf_(centersCount); - int newCount = 0; + using namespace cv::gpu::cudev::hough; + + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.type() == CV_8UC1 ); + CV_Assert( src.cols < std::numeric_limits::max() ); + CV_Assert( src.rows < std::numeric_limits::max() ); + CV_Assert( dp_ > 0 ); + CV_Assert( minRadius_ > 0 && maxRadius_ > minRadius_ ); + CV_Assert( cannyThreshold_ > 0 ); + CV_Assert( votesThreshold_ > 0 ); + CV_Assert( maxCircles_ > 0 ); - ushort2* oldBuf = oldBuf_; - ushort2* newBuf = newBuf_; + const float idp = 1.0f / dp_; - cudaSafeCall( cudaMemcpy(oldBuf, centers, centersCount * sizeof(ushort2), cudaMemcpyDeviceToHost) ); + filterDx_->apply(src, dx_); + filterDy_->apply(src, dy_); - const int cellSize = cvRound(minDist); - const int gridWidth = (src.cols + cellSize - 1) / cellSize; - const int gridHeight = (src.rows + cellSize - 1) / cellSize; + canny_->setLowThreshold(std::max(cannyThreshold_ / 2, 1)); + canny_->setHighThreshold(cannyThreshold_); - std::vector< std::vector > grid(gridWidth * gridHeight); + canny_->detect(dx_, dy_, edges_); - const float minDist2 = minDist * minDist; + ensureSizeIsEnough(2, src.size().area(), CV_32SC1, list_); + unsigned int* srcPoints = list_.ptr(0); + unsigned int* centers = list_.ptr(1); - for (int i = 0; i < centersCount; ++i) + const int pointsCount = buildPointList_gpu(edges_, srcPoints); + if (pointsCount == 0) { - ushort2 p = oldBuf[i]; + circles.release(); + return; + } - bool good = true; + ensureSizeIsEnough(cvCeil(src.rows * idp) + 2, cvCeil(src.cols * idp) + 2, CV_32SC1, accum_); + accum_.setTo(Scalar::all(0)); - int xCell = static_cast(p.x / cellSize); - int yCell = static_cast(p.y / cellSize); + circlesAccumCenters_gpu(srcPoints, pointsCount, dx_, dy_, accum_, minRadius_, maxRadius_, idp); - int x1 = xCell - 1; - int y1 = yCell - 1; - int x2 = xCell + 1; - int y2 = yCell + 1; + int centersCount = buildCentersList_gpu(accum_, centers, votesThreshold_); + if (centersCount == 0) + { + circles.release(); + return; + } - // boundary check - x1 = std::max(0, x1); - y1 = std::max(0, y1); - x2 = std::min(gridWidth - 1, x2); - y2 = std::min(gridHeight - 1, y2); + if (minDist_ > 1) + { + AutoBuffer oldBuf_(centersCount); + AutoBuffer newBuf_(centersCount); + int newCount = 0; - for (int yy = y1; yy <= y2; ++yy) + ushort2* oldBuf = oldBuf_; + ushort2* newBuf = newBuf_; + + cudaSafeCall( cudaMemcpy(oldBuf, centers, centersCount * sizeof(ushort2), cudaMemcpyDeviceToHost) ); + + const int cellSize = cvRound(minDist_); + const int gridWidth = (src.cols + cellSize - 1) / cellSize; + const int gridHeight = (src.rows + cellSize - 1) / cellSize; + + std::vector< std::vector > grid(gridWidth * gridHeight); + + const float minDist2 = minDist_ * minDist_; + + for (int i = 0; i < centersCount; ++i) { - for (int xx = x1; xx <= x2; ++xx) - { - std::vector& m = grid[yy * gridWidth + xx]; + ushort2 p = oldBuf[i]; - for(size_t j = 0; j < m.size(); ++j) + bool good = true; + + int xCell = static_cast(p.x / cellSize); + int yCell = static_cast(p.y / cellSize); + + int x1 = xCell - 1; + int y1 = yCell - 1; + int x2 = xCell + 1; + int y2 = yCell + 1; + + // boundary check + x1 = std::max(0, x1); + y1 = std::max(0, y1); + x2 = std::min(gridWidth - 1, x2); + y2 = std::min(gridHeight - 1, y2); + + for (int yy = y1; yy <= y2; ++yy) + { + for (int xx = x1; xx <= x2; ++xx) { - float dx = (float)(p.x - m[j].x); - float dy = (float)(p.y - m[j].y); + std::vector& m = grid[yy * gridWidth + xx]; - if (dx * dx + dy * dy < minDist2) + for(size_t j = 0; j < m.size(); ++j) { - good = false; - goto break_out; + float dx = (float)(p.x - m[j].x); + float dy = (float)(p.y - m[j].y); + + if (dx * dx + dy * dy < minDist2) + { + good = false; + goto break_out; + } } } } - } - break_out: + break_out: - if(good) - { - grid[yCell * gridWidth + xCell].push_back(p); + if(good) + { + grid[yCell * gridWidth + xCell].push_back(p); - newBuf[newCount++] = p; + newBuf[newCount++] = p; + } } + + cudaSafeCall( cudaMemcpy(centers, newBuf, newCount * sizeof(unsigned int), cudaMemcpyHostToDevice) ); + centersCount = newCount; } - cudaSafeCall( cudaMemcpy(centers, newBuf, newCount * sizeof(unsigned int), cudaMemcpyHostToDevice) ); - centersCount = newCount; - } + ensureSizeIsEnough(1, maxCircles_, CV_32FC3, result_); - ensureSizeIsEnough(1, maxCircles, CV_32FC3, circles); + int circlesCount = circlesAccumRadius_gpu(centers, centersCount, srcPoints, pointsCount, result_.ptr(), maxCircles_, + dp_, minRadius_, maxRadius_, votesThreshold_, deviceSupports(FEATURE_SET_COMPUTE_20)); - const int circlesCount = circlesAccumRadius_gpu(centers, centersCount, srcPoints, pointsCount, circles.ptr(), maxCircles, - dp, minRadius, maxRadius, votesThreshold, deviceSupports(FEATURE_SET_COMPUTE_20)); + if (circlesCount == 0) + { + circles.release(); + return; + } - if (circlesCount > 0) - circles.cols = circlesCount; - else - circles.release(); + result_.cols = circlesCount; + result_.copyTo(circles); + } } -void cv::gpu::HoughCirclesDownload(const GpuMat& d_circles, cv::OutputArray h_circles_) +Ptr cv::gpu::createHoughCirclesDetector(float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles) { - if (d_circles.empty()) - { - h_circles_.release(); - return; - } - - CV_Assert(d_circles.rows == 1 && d_circles.type() == CV_32FC3); - - h_circles_.create(1, d_circles.cols, CV_32FC3); - Mat h_circles = h_circles_.getMat(); - d_circles.download(h_circles); + return new HoughCirclesDetectorImpl(dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius, maxCircles); } ////////////////////////////////////////////////////////// diff --git a/modules/gpuimgproc/test/test_hough.cpp b/modules/gpuimgproc/test/test_hough.cpp index 6e03eaad2c..d0482dc46a 100644 --- a/modules/gpuimgproc/test/test_hough.cpp +++ b/modules/gpuimgproc/test/test_hough.cpp @@ -150,11 +150,13 @@ GPU_TEST_P(HoughCircles, Accuracy) cv::Mat src(size, CV_8UC1); drawCircles(src, circles_gold, true); + cv::Ptr houghCircles = cv::gpu::createHoughCirclesDetector(dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius); + cv::gpu::GpuMat d_circles; - cv::gpu::HoughCircles(loadMat(src, useRoi), d_circles, cv::HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius); + houghCircles->detect(loadMat(src, useRoi), d_circles); std::vector circles; - cv::gpu::HoughCirclesDownload(d_circles, circles); + d_circles.download(circles); ASSERT_FALSE(circles.empty()); From ad4d6bed9dccdb6fecc5daff0463efe26343c5e9 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 30 Apr 2013 13:59:10 +0400 Subject: [PATCH 06/17] refactored gpu::GeneralizedHough --- .../gpuimgproc/include/opencv2/gpuimgproc.hpp | 28 +- modules/gpuimgproc/perf/perf_hough.cpp | 2 +- modules/gpuimgproc/src/hough.cpp | 251 ++++++++++-------- modules/gpuimgproc/test/test_hough.cpp | 4 +- samples/gpu/generalized_hough.cpp | 6 +- 5 files changed, 150 insertions(+), 141 deletions(-) diff --git a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp index a4ed11e6f9..d368ae0a2e 100644 --- a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp +++ b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp @@ -344,34 +344,20 @@ inline void HoughCircles(InputArray src, OutputArray circles, int /*method*/, fl //! finds arbitrary template in the grayscale image using Generalized Hough Transform //! Ballard, D.H. (1981). Generalizing the Hough transform to detect arbitrary shapes. Pattern Recognition 13 (2): 111-122. //! Guil, N., González-Linares, J.M. and Zapata, E.L. (1999). Bidimensional shape detection using an invariant approach. Pattern Recognition 32 (6): 1025-1038. -class CV_EXPORTS GeneralizedHough_GPU : public cv::Algorithm +class CV_EXPORTS GeneralizedHough : public Algorithm { public: - static Ptr create(int method); - - GeneralizedHough_GPU(); - virtual ~GeneralizedHough_GPU(); + static Ptr create(int method); //! set template to search - void setTemplate(const GpuMat& templ, int cannyThreshold = 100, Point templCenter = Point(-1, -1)); - void setTemplate(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, Point templCenter = Point(-1, -1)); + virtual void setTemplate(InputArray templ, int cannyThreshold = 100, Point templCenter = Point(-1, -1)) = 0; + virtual void setTemplate(InputArray edges, InputArray dx, InputArray dy, Point templCenter = Point(-1, -1)) = 0; //! find template on image - void detect(const GpuMat& image, GpuMat& positions, int cannyThreshold = 100); - void detect(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, GpuMat& positions); - - void download(const GpuMat& d_positions, OutputArray h_positions, OutputArray h_votes = noArray()); - - void release(); + virtual void detect(InputArray image, OutputArray positions, int cannyThreshold = 100) = 0; + virtual void detect(InputArray edges, InputArray dx, InputArray dy, OutputArray positions) = 0; -protected: - virtual void setTemplateImpl(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, Point templCenter) = 0; - virtual void detectImpl(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, GpuMat& positions) = 0; - virtual void releaseImpl() = 0; - -private: - GpuMat edges_; - Ptr canny_; + virtual void downloadResults(InputArray d_positions, OutputArray h_positions, OutputArray h_votes = noArray()) = 0; }; ////////////////////////// Corners Detection /////////////////////////// diff --git a/modules/gpuimgproc/perf/perf_hough.cpp b/modules/gpuimgproc/perf/perf_hough.cpp index b0f41e5783..f72a820f5b 100644 --- a/modules/gpuimgproc/perf/perf_hough.cpp +++ b/modules/gpuimgproc/perf/perf_hough.cpp @@ -286,7 +286,7 @@ PERF_TEST_P(Method_Sz, GeneralizedHough, const cv::gpu::GpuMat d_dy(dy); cv::gpu::GpuMat posAndVotes; - cv::Ptr d_hough = cv::gpu::GeneralizedHough_GPU::create(method); + cv::Ptr d_hough = cv::gpu::GeneralizedHough::create(method); if (method & GHT_ROTATION) { d_hough->set("maxAngle", 90.0); diff --git a/modules/gpuimgproc/src/hough.cpp b/modules/gpuimgproc/src/hough.cpp index 67d6e383c0..90b0261bd7 100644 --- a/modules/gpuimgproc/src/hough.cpp +++ b/modules/gpuimgproc/src/hough.cpp @@ -51,16 +51,9 @@ Ptr cv::gpu::createHoughLinesDetector(float, float, int Ptr cv::gpu::createHoughSegmentDetector(float, float, int, int, int) { throw_no_cuda(); return Ptr(); } -Ptr cv::gpu::createHoughCirclesDetector(float, float, int, int, int, int, int) { throw_no_cuda(); return Ptr(); } +Ptr cv::gpu::createHoughCirclesDetector(float, float, int, int, int, int, int) { throw_no_cuda(); return Ptr(); } -Ptr cv::gpu::GeneralizedHough_GPU::create(int) { throw_no_cuda(); return Ptr(); } -cv::gpu::GeneralizedHough_GPU::~GeneralizedHough_GPU() {} -void cv::gpu::GeneralizedHough_GPU::setTemplate(const GpuMat&, int, Point) { throw_no_cuda(); } -void cv::gpu::GeneralizedHough_GPU::setTemplate(const GpuMat&, const GpuMat&, const GpuMat&, Point) { throw_no_cuda(); } -void cv::gpu::GeneralizedHough_GPU::detect(const GpuMat&, GpuMat&, int) { throw_no_cuda(); } -void cv::gpu::GeneralizedHough_GPU::detect(const GpuMat&, const GpuMat&, const GpuMat&, GpuMat&) { throw_no_cuda(); } -void cv::gpu::GeneralizedHough_GPU::download(const GpuMat&, OutputArray, OutputArray) { throw_no_cuda(); } -void cv::gpu::GeneralizedHough_GPU::release() {} +Ptr cv::gpu::GeneralizedHough::create(int) { throw_no_cuda(); return Ptr(); } #else /* !defined (HAVE_CUDA) */ @@ -644,7 +637,133 @@ namespace cv { namespace gpu { namespace cudev namespace { ///////////////////////////////////// - // Common + // GeneralizedHoughBase + + class GeneralizedHoughBase : public gpu::GeneralizedHough + { + public: + GeneralizedHoughBase(); + + void setTemplate(InputArray templ, int cannyThreshold = 100, Point templCenter = Point(-1, -1)); + void setTemplate(InputArray edges, InputArray dx, InputArray dy, Point templCenter = Point(-1, -1)); + + void detect(InputArray image, OutputArray positions, int cannyThreshold = 100); + void detect(InputArray edges, InputArray dx, InputArray dy, OutputArray positions); + + void downloadResults(InputArray d_positions, OutputArray h_positions, OutputArray h_votes = noArray()); + + protected: + virtual void setTemplateImpl(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, Point templCenter) = 0; + virtual void detectImpl(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, OutputArray positions) = 0; + + private: + GpuMat dx_, dy_; + GpuMat edges_; + Ptr canny_; + Ptr filterDx_; + Ptr filterDy_; + }; + + GeneralizedHoughBase::GeneralizedHoughBase() + { + canny_ = gpu::createCannyEdgeDetector(50, 100); + filterDx_ = gpu::createSobelFilter(CV_8UC1, CV_32S, 1, 0); + filterDy_ = gpu::createSobelFilter(CV_8UC1, CV_32S, 0, 1); + } + + void GeneralizedHoughBase::setTemplate(InputArray _templ, int cannyThreshold, Point templCenter) + { + GpuMat templ = _templ.getGpuMat(); + + CV_Assert( templ.type() == CV_8UC1 ); + CV_Assert( cannyThreshold > 0 ); + + ensureSizeIsEnough(templ.size(), CV_32SC1, dx_); + ensureSizeIsEnough(templ.size(), CV_32SC1, dy_); + + filterDx_->apply(templ, dx_); + filterDy_->apply(templ, dy_); + + ensureSizeIsEnough(templ.size(), CV_8UC1, edges_); + + canny_->setLowThreshold(cannyThreshold / 2); + canny_->setHighThreshold(cannyThreshold); + canny_->detect(dx_, dy_, edges_); + + if (templCenter == Point(-1, -1)) + templCenter = Point(templ.cols / 2, templ.rows / 2); + + setTemplateImpl(edges_, dx_, dy_, templCenter); + } + + void GeneralizedHoughBase::setTemplate(InputArray _edges, InputArray _dx, InputArray _dy, Point templCenter) + { + GpuMat edges = _edges.getGpuMat(); + GpuMat dx = _dx.getGpuMat(); + GpuMat dy = _dy.getGpuMat(); + + if (templCenter == Point(-1, -1)) + templCenter = Point(edges.cols / 2, edges.rows / 2); + + setTemplateImpl(edges, dx, dy, templCenter); + } + + void GeneralizedHoughBase::detect(InputArray _image, OutputArray positions, int cannyThreshold) + { + GpuMat image = _image.getGpuMat(); + + CV_Assert( image.type() == CV_8UC1 ); + CV_Assert( cannyThreshold > 0 ); + + ensureSizeIsEnough(image.size(), CV_32SC1, dx_); + ensureSizeIsEnough(image.size(), CV_32SC1, dy_); + + filterDx_->apply(image, dx_); + filterDy_->apply(image, dy_); + + ensureSizeIsEnough(image.size(), CV_8UC1, edges_); + + canny_->setLowThreshold(cannyThreshold / 2); + canny_->setHighThreshold(cannyThreshold); + canny_->detect(dx_, dy_, edges_); + + detectImpl(edges_, dx_, dy_, positions); + } + + void GeneralizedHoughBase::detect(InputArray _edges, InputArray _dx, InputArray _dy, OutputArray positions) + { + GpuMat edges = _edges.getGpuMat(); + GpuMat dx = _dx.getGpuMat(); + GpuMat dy = _dy.getGpuMat(); + + detectImpl(edges, dx, dy, positions); + } + + void GeneralizedHoughBase::downloadResults(InputArray _d_positions, OutputArray h_positions, OutputArray h_votes) + { + GpuMat d_positions = _d_positions.getGpuMat(); + + if (d_positions.empty()) + { + h_positions.release(); + if (h_votes.needed()) + h_votes.release(); + return; + } + + CV_Assert( d_positions.rows == 2 && d_positions.type() == CV_32FC4 ); + + d_positions.row(0).download(h_positions); + + if (h_votes.needed()) + { + GpuMat d_votes(1, d_positions.cols, CV_32SC3, d_positions.ptr(1)); + d_votes.download(h_votes); + } + } + + ///////////////////////////////////// + // GHT_Pos template void releaseVector(std::vector& v) { @@ -652,14 +771,14 @@ namespace empty.swap(v); } - class GHT_Pos : public GeneralizedHough_GPU + class GHT_Pos : public GeneralizedHoughBase { public: GHT_Pos(); protected: void setTemplateImpl(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, Point templCenter); - void detectImpl(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, GpuMat& positions); + void detectImpl(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, OutputArray positions); void releaseImpl(); virtual void processTempl() = 0; @@ -667,7 +786,7 @@ namespace void buildEdgePointList(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy); void filterMinDist(); - void convertTo(GpuMat& positions); + void convertTo(OutputArray positions); int maxSize; double minDist; @@ -717,7 +836,7 @@ namespace processTempl(); } - void GHT_Pos::detectImpl(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, GpuMat& positions) + void GHT_Pos::detectImpl(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, OutputArray positions) { imageSize = edges.size(); @@ -892,7 +1011,7 @@ namespace cudaSafeCall( cudaMemcpy(outBuf.ptr(1), &newVoteBuf[0], posCount * sizeof(int3), cudaMemcpyHostToDevice) ); } - void GHT_Pos::convertTo(GpuMat& positions) + void GHT_Pos::convertTo(OutputArray positions) { ensureSizeIsEnough(2, posCount, CV_32FC4, positions); GpuMat(2, posCount, CV_32FC4, outBuf.data, outBuf.step).copyTo(positions); @@ -1541,7 +1660,7 @@ namespace } } -Ptr cv::gpu::GeneralizedHough_GPU::create(int method) +Ptr cv::gpu::GeneralizedHough::create(int method) { switch (method) { @@ -1562,104 +1681,8 @@ Ptr cv::gpu::GeneralizedHough_GPU::create(int method) return new GHT_Guil_Full(); } - CV_Error(cv::Error::StsBadArg, "Unsupported method"); - return Ptr(); -} - -cv::gpu::GeneralizedHough_GPU::GeneralizedHough_GPU() -{ - canny_ = gpu::createCannyEdgeDetector(50, 100); -} - -cv::gpu::GeneralizedHough_GPU::~GeneralizedHough_GPU() -{ -} - -void cv::gpu::GeneralizedHough_GPU::setTemplate(const GpuMat& templ, int cannyThreshold, Point templCenter) -{ - CV_Assert(templ.type() == CV_8UC1); - CV_Assert(cannyThreshold > 0); - - ensureSizeIsEnough(templ.size(), CV_8UC1, edges_); - - canny_->setLowThreshold(cannyThreshold / 2); - canny_->setHighThreshold(cannyThreshold); - canny_->detect(templ, edges_); - - if (templCenter == Point(-1, -1)) - templCenter = Point(templ.cols / 2, templ.rows / 2); - - Ptr filterDX = gpu::createSobelFilter(CV_8UC1, CV_32S, 1, 0); - Ptr filterDY = gpu::createSobelFilter(CV_8UC1, CV_32S, 0, 1); - GpuMat dx, dy; - filterDX->apply(templ, dx); - filterDY->apply(templ, dy); - - setTemplateImpl(edges_, dx, dy, templCenter); -} - -void cv::gpu::GeneralizedHough_GPU::setTemplate(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, Point templCenter) -{ - if (templCenter == Point(-1, -1)) - templCenter = Point(edges.cols / 2, edges.rows / 2); - - setTemplateImpl(edges, dx, dy, templCenter); -} - -void cv::gpu::GeneralizedHough_GPU::detect(const GpuMat& image, GpuMat& positions, int cannyThreshold) -{ - CV_Assert(image.type() == CV_8UC1); - CV_Assert(cannyThreshold > 0); - - ensureSizeIsEnough(image.size(), CV_8UC1, edges_); - - canny_->setLowThreshold(cannyThreshold / 2); - canny_->setHighThreshold(cannyThreshold); - canny_->detect(image, edges_); - - Ptr filterDX = gpu::createSobelFilter(CV_8UC1, CV_32S, 1, 0); - Ptr filterDY = gpu::createSobelFilter(CV_8UC1, CV_32S, 0, 1); - GpuMat dx, dy; - filterDX->apply(image, dx); - filterDY->apply(image, dy); - - detectImpl(edges_, dx, dy, positions); -} - -void cv::gpu::GeneralizedHough_GPU::detect(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, GpuMat& positions) -{ - detectImpl(edges, dx, dy, positions); -} - -void cv::gpu::GeneralizedHough_GPU::download(const GpuMat& d_positions, OutputArray h_positions_, OutputArray h_votes_) -{ - if (d_positions.empty()) - { - h_positions_.release(); - if (h_votes_.needed()) - h_votes_.release(); - return; - } - - CV_Assert(d_positions.rows == 2 && d_positions.type() == CV_32FC4); - - h_positions_.create(1, d_positions.cols, CV_32FC4); - Mat h_positions = h_positions_.getMat(); - d_positions.row(0).download(h_positions); - - if (h_votes_.needed()) - { - h_votes_.create(1, d_positions.cols, CV_32SC3); - Mat h_votes = h_votes_.getMat(); - GpuMat d_votes(1, d_positions.cols, CV_32SC3, const_cast(d_positions.ptr(1))); - d_votes.download(h_votes); - } -} - -void cv::gpu::GeneralizedHough_GPU::release() -{ - edges_.release(); - releaseImpl(); + CV_Error(Error::StsBadArg, "Unsupported method"); + return Ptr(); } #endif /* !defined (HAVE_CUDA) */ diff --git a/modules/gpuimgproc/test/test_hough.cpp b/modules/gpuimgproc/test/test_hough.cpp index d0482dc46a..e4319bd219 100644 --- a/modules/gpuimgproc/test/test_hough.cpp +++ b/modules/gpuimgproc/test/test_hough.cpp @@ -218,7 +218,7 @@ GPU_TEST_P(GeneralizedHough, POSITION) templ.copyTo(imageROI); } - cv::Ptr hough = cv::gpu::GeneralizedHough_GPU::create(cv::GeneralizedHough::GHT_POSITION); + cv::Ptr hough = cv::gpu::GeneralizedHough::create(cv::GeneralizedHough::GHT_POSITION); hough->set("votesThreshold", 200); hough->setTemplate(loadMat(templ, useRoi)); @@ -227,7 +227,7 @@ GPU_TEST_P(GeneralizedHough, POSITION) hough->detect(loadMat(image, useRoi), d_pos); std::vector pos; - hough->download(d_pos, pos); + hough->downloadResults(d_pos, pos); ASSERT_EQ(gold_count, pos.size()); diff --git a/samples/gpu/generalized_hough.cpp b/samples/gpu/generalized_hough.cpp index a8f7cc67cc..dbd924f752 100644 --- a/samples/gpu/generalized_hough.cpp +++ b/samples/gpu/generalized_hough.cpp @@ -11,7 +11,7 @@ using namespace std; using namespace cv; -using namespace cv::gpu; +using cv::gpu::GpuMat; static Mat loadImage(const string& name) { @@ -101,7 +101,7 @@ int main(int argc, const char* argv[]) GpuMat d_image(image); GpuMat d_position; - Ptr d_hough = GeneralizedHough_GPU::create(method); + Ptr d_hough = gpu::GeneralizedHough::create(method); d_hough->set("minDist", minDist); d_hough->set("levels", levels); d_hough->set("dp", dp); @@ -134,7 +134,7 @@ int main(int argc, const char* argv[]) tm.start(); d_hough->detect(d_image, d_position); - d_hough->download(d_position, position); + d_hough->downloadResults(d_position, position); tm.stop(); } From d7ff3ad0cf067f9485488a2b7cda15c0b1078625 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 30 Apr 2013 15:00:25 +0400 Subject: [PATCH 07/17] refactored cornerHarris and cornerMinEigenVal * converted it into Algorithm --- .../gpuimgproc/include/opencv2/gpuimgproc.hpp | 36 ++++- modules/gpuimgproc/perf/perf_corners.cpp | 14 +- modules/gpuimgproc/src/corners.cpp | 153 +++++++++++------- modules/gpuimgproc/src/gftt.cpp | 10 +- modules/gpuimgproc/test/test_corners.cpp | 8 +- samples/gpu/performance/tests.cpp | 6 +- 6 files changed, 143 insertions(+), 84 deletions(-) diff --git a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp index d368ae0a2e..adb9a8e06b 100644 --- a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp +++ b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp @@ -362,17 +362,37 @@ public: ////////////////////////// Corners Detection /////////////////////////// +class CV_EXPORTS CornernessCriteria : public Algorithm +{ +public: + virtual void compute(InputArray src, OutputArray dst, Stream& stream = Stream::Null()) = 0; +}; + //! computes Harris cornerness criteria at each image pixel -CV_EXPORTS void cornerHarris(const GpuMat& src, GpuMat& dst, int blockSize, int ksize, double k, int borderType = BORDER_REFLECT101); -CV_EXPORTS void cornerHarris(const GpuMat& src, GpuMat& dst, GpuMat& Dx, GpuMat& Dy, int blockSize, int ksize, double k, int borderType = BORDER_REFLECT101); -CV_EXPORTS void cornerHarris(const GpuMat& src, GpuMat& dst, GpuMat& Dx, GpuMat& Dy, GpuMat& buf, int blockSize, int ksize, double k, - int borderType = BORDER_REFLECT101, Stream& stream = Stream::Null()); +CV_EXPORTS Ptr createHarrisCorner(int srcType, int blockSize, int ksize, double k, int borderType = BORDER_REFLECT101); //! computes minimum eigen value of 2x2 derivative covariation matrix at each pixel - the cornerness criteria -CV_EXPORTS void cornerMinEigenVal(const GpuMat& src, GpuMat& dst, int blockSize, int ksize, int borderType=BORDER_REFLECT101); -CV_EXPORTS void cornerMinEigenVal(const GpuMat& src, GpuMat& dst, GpuMat& Dx, GpuMat& Dy, int blockSize, int ksize, int borderType=BORDER_REFLECT101); -CV_EXPORTS void cornerMinEigenVal(const GpuMat& src, GpuMat& dst, GpuMat& Dx, GpuMat& Dy, GpuMat& buf, int blockSize, int ksize, - int borderType=BORDER_REFLECT101, Stream& stream = Stream::Null()); +CV_EXPORTS Ptr createMinEigenValCorner(int srcType, int blockSize, int ksize, int borderType = BORDER_REFLECT101); + +// obsolete + +__OPENCV_GPUIMGPROC_DEPR_BEFORE__ void cornerHarris(InputArray src, OutputArray dst, + int blockSize, int ksize, double k, int borderType = BORDER_REFLECT101, + Stream& stream = Stream::Null()) __OPENCV_GPUIMGPROC_DEPR_AFTER__; + +inline void cornerHarris(InputArray src, OutputArray dst, int blockSize, int ksize, double k, int borderType, Stream& stream) +{ + gpu::createHarrisCorner(src.type(), blockSize, ksize, k, borderType)->compute(src, dst, stream); +} + +__OPENCV_GPUIMGPROC_DEPR_BEFORE__ void cornerMinEigenVal(InputArray src, OutputArray dst, + int blockSize, int ksize, int borderType = BORDER_REFLECT101, + Stream& stream = Stream::Null()) __OPENCV_GPUIMGPROC_DEPR_AFTER__; + +inline void cornerMinEigenVal(InputArray src, OutputArray dst, int blockSize, int ksize, int borderType, Stream& stream) +{ + gpu::createMinEigenValCorner(src.type(), blockSize, ksize, borderType)->compute(src, dst, stream); +} ////////////////////////// Feature Detection /////////////////////////// diff --git a/modules/gpuimgproc/perf/perf_corners.cpp b/modules/gpuimgproc/perf/perf_corners.cpp index 28e8806e58..a0c1f8d30f 100644 --- a/modules/gpuimgproc/perf/perf_corners.cpp +++ b/modules/gpuimgproc/perf/perf_corners.cpp @@ -75,11 +75,10 @@ PERF_TEST_P(Image_Type_Border_BlockSz_ApertureSz, CornerHarris, { const cv::gpu::GpuMat d_img(img); cv::gpu::GpuMat dst; - cv::gpu::GpuMat d_Dx; - cv::gpu::GpuMat d_Dy; - cv::gpu::GpuMat d_buf; - TEST_CYCLE() cv::gpu::cornerHarris(d_img, dst, d_Dx, d_Dy, d_buf, blockSize, apertureSize, k, borderMode); + cv::Ptr harris = cv::gpu::createHarrisCorner(img.type(), blockSize, apertureSize, k, borderMode); + + TEST_CYCLE() harris->compute(d_img, dst); GPU_SANITY_CHECK(dst, 1e-4); } @@ -118,11 +117,10 @@ PERF_TEST_P(Image_Type_Border_BlockSz_ApertureSz, CornerMinEigenVal, { const cv::gpu::GpuMat d_img(img); cv::gpu::GpuMat dst; - cv::gpu::GpuMat d_Dx; - cv::gpu::GpuMat d_Dy; - cv::gpu::GpuMat d_buf; - TEST_CYCLE() cv::gpu::cornerMinEigenVal(d_img, dst, d_Dx, d_Dy, d_buf, blockSize, apertureSize, borderMode); + cv::Ptr minEigenVal = cv::gpu::createMinEigenValCorner(img.type(), blockSize, apertureSize, borderMode); + + TEST_CYCLE() minEigenVal->compute(d_img, dst); GPU_SANITY_CHECK(dst, 1e-4); } diff --git a/modules/gpuimgproc/src/corners.cpp b/modules/gpuimgproc/src/corners.cpp index 824a3308ee..1a72bd7c8a 100644 --- a/modules/gpuimgproc/src/corners.cpp +++ b/modules/gpuimgproc/src/corners.cpp @@ -47,13 +47,8 @@ using namespace cv::gpu; #if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) -void cv::gpu::cornerHarris(const GpuMat&, GpuMat&, int, int, double, int) { throw_no_cuda(); } -void cv::gpu::cornerHarris(const GpuMat&, GpuMat&, GpuMat&, GpuMat&, int, int, double, int) { throw_no_cuda(); } -void cv::gpu::cornerHarris(const GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, int, int, double, int, Stream&) { throw_no_cuda(); } - -void cv::gpu::cornerMinEigenVal(const GpuMat&, GpuMat&, int, int, int) { throw_no_cuda(); } -void cv::gpu::cornerMinEigenVal(const GpuMat&, GpuMat&, GpuMat&, GpuMat&, int, int, int) { throw_no_cuda(); } -void cv::gpu::cornerMinEigenVal(const GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, int, int, int, Stream&) { throw_no_cuda(); } +Ptr cv::gpu::createHarrisCorner(int, int, int, double, int) { throw_no_cuda(); return Ptr(); } +Ptr cv::gpu::createMinEigenValCorner(int, int, int, int) { throw_no_cuda(); return Ptr(); } #else /* !defined (HAVE_CUDA) */ @@ -68,89 +63,127 @@ namespace cv { namespace gpu { namespace cudev namespace { - void extractCovData(const GpuMat& src, GpuMat& Dx, GpuMat& Dy, GpuMat& buf, int blockSize, int ksize, int borderType, Stream& stream) + class CornerBase : public CornernessCriteria + { + protected: + CornerBase(int srcType, int blockSize, int ksize, int borderType); + + void extractCovData(const GpuMat& src, Stream& stream); + + int srcType_; + int blockSize_; + int ksize_; + int borderType_; + GpuMat Dx_, Dy_; + + private: + Ptr filterDx_, filterDy_; + }; + + CornerBase::CornerBase(int srcType, int blockSize, int ksize, int borderType) : + srcType_(srcType), blockSize_(blockSize), ksize_(ksize), borderType_(borderType) { - (void) buf; + CV_Assert( borderType_ == BORDER_REFLECT101 || borderType_ == BORDER_REPLICATE || borderType_ == BORDER_REFLECT ); - double scale = static_cast(1 << ((ksize > 0 ? ksize : 3) - 1)) * blockSize; + const int sdepth = CV_MAT_DEPTH(srcType_); + const int cn = CV_MAT_CN(srcType_); - if (ksize < 0) + CV_Assert( cn == 1 ); + + double scale = static_cast(1 << ((ksize_ > 0 ? ksize_ : 3) - 1)) * blockSize_; + + if (ksize_ < 0) scale *= 2.; - if (src.depth() == CV_8U) + if (sdepth == CV_8U) scale *= 255.; scale = 1./scale; - Dx.create(src.size(), CV_32F); - Dy.create(src.size(), CV_32F); - - Ptr filterDx, filterDy; - - if (ksize > 0) + if (ksize_ > 0) { - filterDx = gpu::createSobelFilter(src.type(), CV_32F, 1, 0, ksize, scale, borderType); - filterDy = gpu::createSobelFilter(src.type(), CV_32F, 0, 1, ksize, scale, borderType); + filterDx_ = gpu::createSobelFilter(srcType, CV_32F, 1, 0, ksize_, scale, borderType_); + filterDy_ = gpu::createSobelFilter(srcType, CV_32F, 0, 1, ksize_, scale, borderType_); } else { - filterDx = gpu::createScharrFilter(src.type(), CV_32F, 1, 0, scale, borderType); - filterDy = gpu::createScharrFilter(src.type(), CV_32F, 0, 1, scale, borderType); + filterDx_ = gpu::createScharrFilter(srcType, CV_32F, 1, 0, scale, borderType_); + filterDy_ = gpu::createScharrFilter(srcType, CV_32F, 0, 1, scale, borderType_); } + } - filterDx->apply(src, Dx); - filterDy->apply(src, Dy); + void CornerBase::extractCovData(const GpuMat& src, Stream& stream) + { + CV_Assert( src.type() == srcType_ ); + filterDx_->apply(src, Dx_, stream); + filterDy_->apply(src, Dy_, stream); } -} -void cv::gpu::cornerHarris(const GpuMat& src, GpuMat& dst, int blockSize, int ksize, double k, int borderType) -{ - GpuMat Dx, Dy; - cornerHarris(src, dst, Dx, Dy, blockSize, ksize, k, borderType); -} + class Harris : public CornerBase + { + public: + Harris(int srcType, int blockSize, int ksize, double k, int borderType) : + CornerBase(srcType, blockSize, ksize, borderType), k_(static_cast(k)) + { + } -void cv::gpu::cornerHarris(const GpuMat& src, GpuMat& dst, GpuMat& Dx, GpuMat& Dy, int blockSize, int ksize, double k, int borderType) -{ - GpuMat buf; - cornerHarris(src, dst, Dx, Dy, buf, blockSize, ksize, k, borderType); -} + void compute(InputArray src, OutputArray dst, Stream& stream = Stream::Null()); -void cv::gpu::cornerHarris(const GpuMat& src, GpuMat& dst, GpuMat& Dx, GpuMat& Dy, GpuMat& buf, int blockSize, int ksize, double k, int borderType, Stream& stream) -{ - using namespace cv::gpu::cudev::imgproc; + private: + float k_; + }; - CV_Assert(borderType == cv::BORDER_REFLECT101 || borderType == cv::BORDER_REPLICATE || borderType == cv::BORDER_REFLECT); + void Harris::compute(InputArray _src, OutputArray _dst, Stream& stream) + { + using namespace cv::gpu::cudev::imgproc; - extractCovData(src, Dx, Dy, buf, blockSize, ksize, borderType, stream); + GpuMat src = _src.getGpuMat(); - dst.create(src.size(), CV_32F); + extractCovData(src, stream); - cornerHarris_gpu(blockSize, static_cast(k), Dx, Dy, dst, borderType, StreamAccessor::getStream(stream)); -} + _dst.create(src.size(), CV_32FC1); + GpuMat dst = _dst.getGpuMat(); -void cv::gpu::cornerMinEigenVal(const GpuMat& src, GpuMat& dst, int blockSize, int ksize, int borderType) -{ - GpuMat Dx, Dy; - cornerMinEigenVal(src, dst, Dx, Dy, blockSize, ksize, borderType); -} + cornerHarris_gpu(blockSize_, k_, Dx_, Dy_, dst, borderType_, StreamAccessor::getStream(stream)); + } -void cv::gpu::cornerMinEigenVal(const GpuMat& src, GpuMat& dst, GpuMat& Dx, GpuMat& Dy, int blockSize, int ksize, int borderType) -{ - GpuMat buf; - cornerMinEigenVal(src, dst, Dx, Dy, buf, blockSize, ksize, borderType); -} + class MinEigenVal : public CornerBase + { + public: + MinEigenVal(int srcType, int blockSize, int ksize, int borderType) : + CornerBase(srcType, blockSize, ksize, borderType) + { + } -void cv::gpu::cornerMinEigenVal(const GpuMat& src, GpuMat& dst, GpuMat& Dx, GpuMat& Dy, GpuMat& buf, int blockSize, int ksize, int borderType, Stream& stream) -{ - using namespace ::cv::gpu::cudev::imgproc; + void compute(InputArray src, OutputArray dst, Stream& stream = Stream::Null()); - CV_Assert(borderType == cv::BORDER_REFLECT101 || borderType == cv::BORDER_REPLICATE || borderType == cv::BORDER_REFLECT); + private: + float k_; + }; - extractCovData(src, Dx, Dy, buf, blockSize, ksize, borderType, stream); + void MinEigenVal::compute(InputArray _src, OutputArray _dst, Stream& stream) + { + using namespace cv::gpu::cudev::imgproc; + + GpuMat src = _src.getGpuMat(); + + extractCovData(src, stream); + + _dst.create(src.size(), CV_32FC1); + GpuMat dst = _dst.getGpuMat(); + + cornerMinEigenVal_gpu(blockSize_, Dx_, Dy_, dst, borderType_, StreamAccessor::getStream(stream)); + } +} - dst.create(src.size(), CV_32F); +Ptr cv::gpu::createHarrisCorner(int srcType, int blockSize, int ksize, double k, int borderType) +{ + return new Harris(srcType, blockSize, ksize, k, borderType); +} - cornerMinEigenVal_gpu(blockSize, Dx, Dy, dst, borderType, StreamAccessor::getStream(stream)); +Ptr cv::gpu::createMinEigenValCorner(int srcType, int blockSize, int ksize, int borderType) +{ + return new MinEigenVal(srcType, blockSize, ksize, borderType); } #endif /* !defined (HAVE_CUDA) */ diff --git a/modules/gpuimgproc/src/gftt.cpp b/modules/gpuimgproc/src/gftt.cpp index cca1df4446..c441069d31 100644 --- a/modules/gpuimgproc/src/gftt.cpp +++ b/modules/gpuimgproc/src/gftt.cpp @@ -75,10 +75,12 @@ void cv::gpu::GoodFeaturesToTrackDetector_GPU::operator ()(const GpuMat& image, ensureSizeIsEnough(image.size(), CV_32F, eig_); - if (useHarrisDetector) - cornerHarris(image, eig_, Dx_, Dy_, buf_, blockSize, 3, harrisK); - else - cornerMinEigenVal(image, eig_, Dx_, Dy_, buf_, blockSize, 3); + Ptr cornerCriteria = + useHarrisDetector ? + gpu::createHarrisCorner(image.type(), blockSize, 3, harrisK) : + gpu::createMinEigenValCorner(image.type(), blockSize, 3); + + cornerCriteria->compute(image, eig_); double maxVal = 0; gpu::minMax(eig_, 0, &maxVal, GpuMat(), minMaxbuf_); diff --git a/modules/gpuimgproc/test/test_corners.cpp b/modules/gpuimgproc/test/test_corners.cpp index 54d8df457f..2625480565 100644 --- a/modules/gpuimgproc/test/test_corners.cpp +++ b/modules/gpuimgproc/test/test_corners.cpp @@ -82,8 +82,10 @@ GPU_TEST_P(CornerHarris, Accuracy) double k = randomDouble(0.1, 0.9); + cv::Ptr harris = cv::gpu::createHarrisCorner(src.type(), blockSize, apertureSize, k, borderType); + cv::gpu::GpuMat dst; - cv::gpu::cornerHarris(loadMat(src), dst, blockSize, apertureSize, k, borderType); + harris->compute(loadMat(src), dst); cv::Mat dst_gold; cv::cornerHarris(src, dst_gold, blockSize, apertureSize, k, borderType); @@ -126,8 +128,10 @@ GPU_TEST_P(CornerMinEigen, Accuracy) cv::Mat src = readImageType("stereobm/aloe-L.png", type); ASSERT_FALSE(src.empty()); + cv::Ptr minEigenVal = cv::gpu::createMinEigenValCorner(src.type(), blockSize, apertureSize, borderType); + cv::gpu::GpuMat dst; - cv::gpu::cornerMinEigenVal(loadMat(src), dst, blockSize, apertureSize, borderType); + minEigenVal->compute(loadMat(src), dst); cv::Mat dst_gold; cv::cornerMinEigenVal(src, dst_gold, blockSize, apertureSize, borderType); diff --git a/samples/gpu/performance/tests.cpp b/samples/gpu/performance/tests.cpp index 99ba56cddb..f95730e351 100644 --- a/samples/gpu/performance/tests.cpp +++ b/samples/gpu/performance/tests.cpp @@ -176,10 +176,12 @@ TEST(cornerHarris) d_src.upload(src); - gpu::cornerHarris(d_src, d_dst, 5, 7, 0.1, BORDER_REFLECT101); + Ptr harris = gpu::createHarrisCorner(src.type(), 5, 7, 0.1, BORDER_REFLECT101); + + harris->compute(d_src, d_dst); GPU_ON; - gpu::cornerHarris(d_src, d_dst, 5, 7, 0.1, BORDER_REFLECT101); + harris->compute(d_src, d_dst); GPU_OFF; } } From 70e6dc615afb79843c19020bc599452d3a0bd5a5 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 30 Apr 2013 16:07:56 +0400 Subject: [PATCH 08/17] refactored GoodFeaturesToTrackDetector --- modules/gpu/perf4au/main.cpp | 6 +- .../gpuimgproc/include/opencv2/gpuimgproc.hpp | 47 +---- modules/gpuimgproc/perf/perf_gftt.cpp | 4 +- modules/gpuimgproc/src/gftt.cpp | 197 +++++++++++------- modules/gpuimgproc/test/test_gftt.cpp | 10 +- .../opencv2/videostab/global_motion.hpp | 2 +- modules/videostab/src/global_motion.cpp | 4 +- samples/gpu/performance/tests.cpp | 6 +- samples/gpu/pyrlk_optical_flow.cpp | 6 +- 9 files changed, 142 insertions(+), 140 deletions(-) diff --git a/modules/gpu/perf4au/main.cpp b/modules/gpu/perf4au/main.cpp index df8a793ac5..5e39c3d1e6 100644 --- a/modules/gpu/perf4au/main.cpp +++ b/modules/gpu/perf4au/main.cpp @@ -148,17 +148,17 @@ PERF_TEST_P(Image_Depth, GoodFeaturesToTrack, if (PERF_RUN_GPU()) { - cv::gpu::GoodFeaturesToTrackDetector_GPU d_detector(maxCorners, qualityLevel, minDistance, blockSize, useHarrisDetector, k); + cv::Ptr detector = cv::gpu::createGoodFeaturesToTrackDetector(src.type(), maxCorners, qualityLevel, minDistance, blockSize, useHarrisDetector, k); cv::gpu::GpuMat d_src(src); cv::gpu::GpuMat d_mask(mask); cv::gpu::GpuMat d_pts; - d_detector(d_src, d_pts, d_mask); + detector->detect(d_src, d_pts, d_mask); TEST_CYCLE() { - d_detector(d_src, d_pts, d_mask); + detector->detect(d_src, d_pts, d_mask); } } else diff --git a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp index adb9a8e06b..2fd17d9b35 100644 --- a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp +++ b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp @@ -394,54 +394,17 @@ inline void cornerMinEigenVal(InputArray src, OutputArray dst, int blockSize, in gpu::createMinEigenValCorner(src.type(), blockSize, ksize, borderType)->compute(src, dst, stream); } -////////////////////////// Feature Detection /////////////////////////// +////////////////////////// Corners Detection /////////////////////////// -class CV_EXPORTS GoodFeaturesToTrackDetector_GPU +class CV_EXPORTS CornersDetector : public Algorithm { public: - explicit GoodFeaturesToTrackDetector_GPU(int maxCorners = 1000, double qualityLevel = 0.01, double minDistance = 0.0, - int blockSize = 3, bool useHarrisDetector = false, double harrisK = 0.04); - //! return 1 rows matrix with CV_32FC2 type - void operator ()(const GpuMat& image, GpuMat& corners, const GpuMat& mask = GpuMat()); - - int maxCorners; - double qualityLevel; - double minDistance; - - int blockSize; - bool useHarrisDetector; - double harrisK; - - void releaseMemory() - { - Dx_.release(); - Dy_.release(); - buf_.release(); - eig_.release(); - minMaxbuf_.release(); - tmpCorners_.release(); - } - -private: - GpuMat Dx_; - GpuMat Dy_; - GpuMat buf_; - GpuMat eig_; - GpuMat minMaxbuf_; - GpuMat tmpCorners_; + virtual void detect(InputArray image, OutputArray corners, InputArray mask = noArray()) = 0; }; -inline GoodFeaturesToTrackDetector_GPU::GoodFeaturesToTrackDetector_GPU(int maxCorners_, double qualityLevel_, double minDistance_, - int blockSize_, bool useHarrisDetector_, double harrisK_) -{ - maxCorners = maxCorners_; - qualityLevel = qualityLevel_; - minDistance = minDistance_; - blockSize = blockSize_; - useHarrisDetector = useHarrisDetector_; - harrisK = harrisK_; -} +CV_EXPORTS Ptr createGoodFeaturesToTrackDetector(int srcType, int maxCorners = 1000, double qualityLevel = 0.01, double minDistance = 0.0, + int blockSize = 3, bool useHarrisDetector = false, double harrisK = 0.04); ///////////////////////////// Mean Shift ////////////////////////////// diff --git a/modules/gpuimgproc/perf/perf_gftt.cpp b/modules/gpuimgproc/perf/perf_gftt.cpp index 982182d17e..ed8d6ac16d 100644 --- a/modules/gpuimgproc/perf/perf_gftt.cpp +++ b/modules/gpuimgproc/perf/perf_gftt.cpp @@ -66,12 +66,12 @@ PERF_TEST_P(Image_MinDistance, GoodFeaturesToTrack, if (PERF_RUN_GPU()) { - cv::gpu::GoodFeaturesToTrackDetector_GPU d_detector(maxCorners, qualityLevel, minDistance); + cv::Ptr d_detector = cv::gpu::createGoodFeaturesToTrackDetector(image.type(), maxCorners, qualityLevel, minDistance); const cv::gpu::GpuMat d_image(image); cv::gpu::GpuMat pts; - TEST_CYCLE() d_detector(d_image, pts); + TEST_CYCLE() d_detector->detect(d_image, pts); GPU_SANITY_CHECK(pts); } diff --git a/modules/gpuimgproc/src/gftt.cpp b/modules/gpuimgproc/src/gftt.cpp index c441069d31..ff197d84c2 100644 --- a/modules/gpuimgproc/src/gftt.cpp +++ b/modules/gpuimgproc/src/gftt.cpp @@ -45,9 +45,9 @@ using namespace cv; using namespace cv::gpu; -#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) +#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) || !defined(HAVE_OPENCV_GPUARITHM) -void cv::gpu::GoodFeaturesToTrackDetector_GPU::operator ()(const GpuMat&, GpuMat&, const GpuMat&) { throw_no_cuda(); } +Ptr cv::gpu::createGoodFeaturesToTrackDetector(int, int, double, double, int, bool, double) { throw_no_cuda(); return Ptr(); } #else /* !defined (HAVE_CUDA) */ @@ -60,119 +60,156 @@ namespace cv { namespace gpu { namespace cudev } }}} -void cv::gpu::GoodFeaturesToTrackDetector_GPU::operator ()(const GpuMat& image, GpuMat& corners, const GpuMat& mask) +namespace { -#ifndef HAVE_OPENCV_GPUARITHM - (void) image; - (void) corners; - (void) mask; - throw_no_cuda(); -#else - using namespace cv::gpu::cudev::gfft; + class GoodFeaturesToTrackDetector : public CornersDetector + { + public: + GoodFeaturesToTrackDetector(int srcType, int maxCorners, double qualityLevel, double minDistance, + int blockSize, bool useHarrisDetector, double harrisK); + + void detect(InputArray image, OutputArray corners, InputArray mask = noArray()); + + private: + int maxCorners_; + double qualityLevel_; + double minDistance_; + + Ptr cornerCriteria_; + + GpuMat Dx_; + GpuMat Dy_; + GpuMat buf_; + GpuMat eig_; + GpuMat minMaxbuf_; + GpuMat tmpCorners_; + }; + + GoodFeaturesToTrackDetector::GoodFeaturesToTrackDetector(int srcType, int maxCorners, double qualityLevel, double minDistance, + int blockSize, bool useHarrisDetector, double harrisK) : + maxCorners_(maxCorners), qualityLevel_(qualityLevel), minDistance_(minDistance) + { + CV_Assert( qualityLevel_ > 0 && minDistance_ >= 0 && maxCorners_ >= 0 ); - CV_Assert(qualityLevel > 0 && minDistance >= 0 && maxCorners >= 0); - CV_Assert(mask.empty() || (mask.type() == CV_8UC1 && mask.size() == image.size())); + cornerCriteria_ = useHarrisDetector ? + gpu::createHarrisCorner(srcType, blockSize, 3, harrisK) : + gpu::createMinEigenValCorner(srcType, blockSize, 3); + } - ensureSizeIsEnough(image.size(), CV_32F, eig_); + void GoodFeaturesToTrackDetector::detect(InputArray _image, OutputArray _corners, InputArray _mask) + { + using namespace cv::gpu::cudev::gfft; - Ptr cornerCriteria = - useHarrisDetector ? - gpu::createHarrisCorner(image.type(), blockSize, 3, harrisK) : - gpu::createMinEigenValCorner(image.type(), blockSize, 3); + GpuMat image = _image.getGpuMat(); + GpuMat mask = _mask.getGpuMat(); - cornerCriteria->compute(image, eig_); + CV_Assert( mask.empty() || (mask.type() == CV_8UC1 && mask.size() == image.size()) ); - double maxVal = 0; - gpu::minMax(eig_, 0, &maxVal, GpuMat(), minMaxbuf_); + ensureSizeIsEnough(image.size(), CV_32FC1, eig_); + cornerCriteria_->compute(image, eig_); - ensureSizeIsEnough(1, std::max(1000, static_cast(image.size().area() * 0.05)), CV_32FC2, tmpCorners_); + double maxVal = 0; + gpu::minMax(eig_, 0, &maxVal, noArray(), minMaxbuf_); - int total = findCorners_gpu(eig_, static_cast(maxVal * qualityLevel), mask, tmpCorners_.ptr(), tmpCorners_.cols); + ensureSizeIsEnough(1, std::max(1000, static_cast(image.size().area() * 0.05)), CV_32FC2, tmpCorners_); - if (total == 0) - { - corners.release(); - return; - } + int total = findCorners_gpu(eig_, static_cast(maxVal * qualityLevel_), mask, tmpCorners_.ptr(), tmpCorners_.cols); - sortCorners_gpu(eig_, tmpCorners_.ptr(), total); + if (total == 0) + { + _corners.release(); + return; + } - if (minDistance < 1) - tmpCorners_.colRange(0, maxCorners > 0 ? std::min(maxCorners, total) : total).copyTo(corners); - else - { - std::vector tmp(total); - Mat tmpMat(1, total, CV_32FC2, (void*)&tmp[0]); - tmpCorners_.colRange(0, total).download(tmpMat); + sortCorners_gpu(eig_, tmpCorners_.ptr(), total); - std::vector tmp2; - tmp2.reserve(total); + if (minDistance_ < 1) + { + tmpCorners_.colRange(0, maxCorners_ > 0 ? std::min(maxCorners_, total) : total).copyTo(_corners); + } + else + { + std::vector tmp(total); + Mat tmpMat(1, total, CV_32FC2, (void*)&tmp[0]); + tmpCorners_.colRange(0, total).download(tmpMat); - const int cell_size = cvRound(minDistance); - const int grid_width = (image.cols + cell_size - 1) / cell_size; - const int grid_height = (image.rows + cell_size - 1) / cell_size; + std::vector tmp2; + tmp2.reserve(total); - std::vector< std::vector > grid(grid_width * grid_height); + const int cell_size = cvRound(minDistance_); + const int grid_width = (image.cols + cell_size - 1) / cell_size; + const int grid_height = (image.rows + cell_size - 1) / cell_size; - for (int i = 0; i < total; ++i) - { - Point2f p = tmp[i]; + std::vector< std::vector > grid(grid_width * grid_height); - bool good = true; + for (int i = 0; i < total; ++i) + { + Point2f p = tmp[i]; - int x_cell = static_cast(p.x / cell_size); - int y_cell = static_cast(p.y / cell_size); + bool good = true; - int x1 = x_cell - 1; - int y1 = y_cell - 1; - int x2 = x_cell + 1; - int y2 = y_cell + 1; + int x_cell = static_cast(p.x / cell_size); + int y_cell = static_cast(p.y / cell_size); - // boundary check - x1 = std::max(0, x1); - y1 = std::max(0, y1); - x2 = std::min(grid_width - 1, x2); - y2 = std::min(grid_height - 1, y2); + int x1 = x_cell - 1; + int y1 = y_cell - 1; + int x2 = x_cell + 1; + int y2 = y_cell + 1; - for (int yy = y1; yy <= y2; yy++) - { - for (int xx = x1; xx <= x2; xx++) - { - std::vector& m = grid[yy * grid_width + xx]; + // boundary check + x1 = std::max(0, x1); + y1 = std::max(0, y1); + x2 = std::min(grid_width - 1, x2); + y2 = std::min(grid_height - 1, y2); - if (!m.empty()) + for (int yy = y1; yy <= y2; yy++) + { + for (int xx = x1; xx <= x2; xx++) { - for(size_t j = 0; j < m.size(); j++) - { - float dx = p.x - m[j].x; - float dy = p.y - m[j].y; + std::vector& m = grid[yy * grid_width + xx]; - if (dx * dx + dy * dy < minDistance * minDistance) + if (!m.empty()) + { + for(size_t j = 0; j < m.size(); j++) { - good = false; - goto break_out; + float dx = p.x - m[j].x; + float dy = p.y - m[j].y; + + if (dx * dx + dy * dy < minDistance_ * minDistance_) + { + good = false; + goto break_out; + } } } } } - } - break_out: + break_out: - if(good) - { - grid[y_cell * grid_width + x_cell].push_back(p); + if(good) + { + grid[y_cell * grid_width + x_cell].push_back(p); - tmp2.push_back(p); + tmp2.push_back(p); - if (maxCorners > 0 && tmp2.size() == static_cast(maxCorners)) - break; + if (maxCorners_ > 0 && tmp2.size() == static_cast(maxCorners_)) + break; + } } - } - corners.upload(Mat(1, static_cast(tmp2.size()), CV_32FC2, &tmp2[0])); + _corners.create(1, static_cast(tmp2.size()), CV_32FC2); + GpuMat corners = _corners.getGpuMat(); + + corners.upload(Mat(1, static_cast(tmp2.size()), CV_32FC2, &tmp2[0])); + } } -#endif +} + +Ptr cv::gpu::createGoodFeaturesToTrackDetector(int srcType, int maxCorners, double qualityLevel, double minDistance, + int blockSize, bool useHarrisDetector, double harrisK) +{ + return new GoodFeaturesToTrackDetector(srcType, maxCorners, qualityLevel, minDistance, blockSize, useHarrisDetector, harrisK); } #endif /* !defined (HAVE_CUDA) */ diff --git a/modules/gpuimgproc/test/test_gftt.cpp b/modules/gpuimgproc/test/test_gftt.cpp index b20df33ae5..6ba6e0cfff 100644 --- a/modules/gpuimgproc/test/test_gftt.cpp +++ b/modules/gpuimgproc/test/test_gftt.cpp @@ -76,10 +76,10 @@ GPU_TEST_P(GoodFeaturesToTrack, Accuracy) int maxCorners = 1000; double qualityLevel = 0.01; - cv::gpu::GoodFeaturesToTrackDetector_GPU detector(maxCorners, qualityLevel, minDistance); + cv::Ptr detector = cv::gpu::createGoodFeaturesToTrackDetector(image.type(), maxCorners, qualityLevel, minDistance); cv::gpu::GpuMat d_pts; - detector(loadMat(image), d_pts); + detector->detect(loadMat(image), d_pts); ASSERT_FALSE(d_pts.empty()); @@ -114,12 +114,12 @@ GPU_TEST_P(GoodFeaturesToTrack, EmptyCorners) int maxCorners = 1000; double qualityLevel = 0.01; - cv::gpu::GoodFeaturesToTrackDetector_GPU detector(maxCorners, qualityLevel, minDistance); - cv::gpu::GpuMat src(100, 100, CV_8UC1, cv::Scalar::all(0)); cv::gpu::GpuMat corners(1, maxCorners, CV_32FC2); - detector(src, corners); + cv::Ptr detector = cv::gpu::createGoodFeaturesToTrackDetector(src.type(), maxCorners, qualityLevel, minDistance); + + detector->detect(src, corners); ASSERT_TRUE(corners.empty()); } diff --git a/modules/videostab/include/opencv2/videostab/global_motion.hpp b/modules/videostab/include/opencv2/videostab/global_motion.hpp index 58b831b372..8ccc067a38 100644 --- a/modules/videostab/include/opencv2/videostab/global_motion.hpp +++ b/modules/videostab/include/opencv2/videostab/global_motion.hpp @@ -217,7 +217,7 @@ public: private: Ptr motionEstimator_; - gpu::GoodFeaturesToTrackDetector_GPU detector_; + Ptr detector_; SparsePyrLkOptFlowEstimatorGpu optFlowEstimator_; Ptr outlierRejector_; diff --git a/modules/videostab/src/global_motion.cpp b/modules/videostab/src/global_motion.cpp index d6c291ca70..9a54b5ae64 100644 --- a/modules/videostab/src/global_motion.cpp +++ b/modules/videostab/src/global_motion.cpp @@ -742,6 +742,8 @@ Mat KeypointBasedMotionEstimator::estimate(const Mat &frame0, const Mat &frame1, KeypointBasedMotionEstimatorGpu::KeypointBasedMotionEstimatorGpu(Ptr estimator) : ImageMotionEstimatorBase(estimator->motionModel()), motionEstimator_(estimator) { + detector_ = gpu::createGoodFeaturesToTrackDetector(CV_8UC1); + CV_Assert(gpu::getCudaEnabledDeviceCount() > 0); setOutlierRejector(new NullOutlierRejector()); } @@ -769,7 +771,7 @@ Mat KeypointBasedMotionEstimatorGpu::estimate(const gpu::GpuMat &frame0, const g } // find keypoints - detector_(grayFrame0, pointsPrev_); + detector_->detect(grayFrame0, pointsPrev_); // find correspondences optFlowEstimator_.run(frame0, frame1, pointsPrev_, points_, status_); diff --git a/samples/gpu/performance/tests.cpp b/samples/gpu/performance/tests.cpp index f95730e351..da2d4e2263 100644 --- a/samples/gpu/performance/tests.cpp +++ b/samples/gpu/performance/tests.cpp @@ -1174,15 +1174,15 @@ TEST(GoodFeaturesToTrack) goodFeaturesToTrack(src, pts, 8000, 0.01, 0.0); CPU_OFF; - gpu::GoodFeaturesToTrackDetector_GPU detector(8000, 0.01, 0.0); + Ptr detector = gpu::createGoodFeaturesToTrackDetector(src.type(), 8000, 0.01, 0.0); gpu::GpuMat d_src(src); gpu::GpuMat d_pts; - detector(d_src, d_pts); + detector->detect(d_src, d_pts); GPU_ON; - detector(d_src, d_pts); + detector->detect(d_src, d_pts); GPU_OFF; } diff --git a/samples/gpu/pyrlk_optical_flow.cpp b/samples/gpu/pyrlk_optical_flow.cpp index 2edb9746c6..08717292cd 100644 --- a/samples/gpu/pyrlk_optical_flow.cpp +++ b/samples/gpu/pyrlk_optical_flow.cpp @@ -176,12 +176,12 @@ int main(int argc, const char* argv[]) // goodFeaturesToTrack - GoodFeaturesToTrackDetector_GPU detector(points, 0.01, minDist); - GpuMat d_frame0Gray(frame0Gray); GpuMat d_prevPts; - detector(d_frame0Gray, d_prevPts); + Ptr detector = gpu::createGoodFeaturesToTrackDetector(d_frame0Gray.type(), points, 0.01, minDist); + + detector->detect(d_frame0Gray, d_prevPts); // Sparse From 1fcc8074bd88ca706ea0e8891afa84186b6b375b Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 30 Apr 2013 16:29:23 +0400 Subject: [PATCH 09/17] switched to Input/Output Array in Mean Shift --- .../gpuimgproc/include/opencv2/gpuimgproc.hpp | 6 +-- modules/gpuimgproc/src/mean_shift.cpp | 52 +++++++++---------- modules/gpuimgproc/src/mssegmentation.cpp | 16 +++--- 3 files changed, 39 insertions(+), 35 deletions(-) diff --git a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp index 2fd17d9b35..24b8b64f0a 100644 --- a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp +++ b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp @@ -409,17 +409,17 @@ CV_EXPORTS Ptr createGoodFeaturesToTrackDetector(int srcType, i ///////////////////////////// Mean Shift ////////////////////////////// //! Does mean shift filtering on GPU. -CV_EXPORTS void meanShiftFiltering(const GpuMat& src, GpuMat& dst, int sp, int sr, +CV_EXPORTS void meanShiftFiltering(InputArray src, OutputArray dst, int sp, int sr, TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1), Stream& stream = Stream::Null()); //! Does mean shift procedure on GPU. -CV_EXPORTS void meanShiftProc(const GpuMat& src, GpuMat& dstr, GpuMat& dstsp, int sp, int sr, +CV_EXPORTS void meanShiftProc(InputArray src, OutputArray dstr, OutputArray dstsp, int sp, int sr, TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1), Stream& stream = Stream::Null()); //! Does mean shift segmentation with elimination of small regions. -CV_EXPORTS void meanShiftSegmentation(const GpuMat& src, Mat& dst, int sp, int sr, int minsize, +CV_EXPORTS void meanShiftSegmentation(InputArray src, OutputArray dst, int sp, int sr, int minsize, TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1)); /////////////////////////// Match Template //////////////////////////// diff --git a/modules/gpuimgproc/src/mean_shift.cpp b/modules/gpuimgproc/src/mean_shift.cpp index e30f95bf98..26368ca5ac 100644 --- a/modules/gpuimgproc/src/mean_shift.cpp +++ b/modules/gpuimgproc/src/mean_shift.cpp @@ -47,13 +47,13 @@ using namespace cv::gpu; #if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) -void cv::gpu::meanShiftFiltering(const GpuMat&, GpuMat&, int, int, TermCriteria, Stream&) { throw_no_cuda(); } -void cv::gpu::meanShiftProc(const GpuMat&, GpuMat&, GpuMat&, int, int, TermCriteria, Stream&) { throw_no_cuda(); } +void cv::gpu::meanShiftFiltering(InputArray, OutputArray, int, int, TermCriteria, Stream&) { throw_no_cuda(); } +void cv::gpu::meanShiftProc(InputArray, OutputArray, OutputArray, int, int, TermCriteria, Stream&) { throw_no_cuda(); } #else /* !defined (HAVE_CUDA) */ //////////////////////////////////////////////////////////////////////// -// meanShiftFiltering_GPU +// meanShiftFiltering namespace cv { namespace gpu { namespace cudev { @@ -63,27 +63,26 @@ namespace cv { namespace gpu { namespace cudev } }}} -void cv::gpu::meanShiftFiltering(const GpuMat& src, GpuMat& dst, int sp, int sr, TermCriteria criteria, Stream& stream) +void cv::gpu::meanShiftFiltering(InputArray _src, OutputArray _dst, int sp, int sr, TermCriteria criteria, Stream& stream) { using namespace ::cv::gpu::cudev::imgproc; - if( src.empty() ) - CV_Error( cv::Error::StsBadArg, "The input image is empty" ); + GpuMat src = _src.getGpuMat(); - if( src.depth() != CV_8U || src.channels() != 4 ) - CV_Error( cv::Error::StsUnsupportedFormat, "Only 8-bit, 4-channel images are supported" ); + CV_Assert( src.type() == CV_8UC4 ); - dst.create( src.size(), CV_8UC4 ); + _dst.create(src.size(), CV_8UC4); + GpuMat dst = _dst.getGpuMat(); - if( !(criteria.type & TermCriteria::MAX_ITER) ) + if (!(criteria.type & TermCriteria::MAX_ITER)) criteria.maxCount = 5; int maxIter = std::min(std::max(criteria.maxCount, 1), 100); - float eps; - if( !(criteria.type & TermCriteria::EPS) ) - eps = 1.f; - eps = (float)std::max(criteria.epsilon, 0.0); + if (!(criteria.type & TermCriteria::EPS)) + criteria.epsilon = 1.f; + + float eps = (float) std::max(criteria.epsilon, 0.0); meanShiftFiltering_gpu(src, dst, sp, sr, maxIter, eps, StreamAccessor::getStream(stream)); } @@ -99,28 +98,29 @@ namespace cv { namespace gpu { namespace cudev } }}} -void cv::gpu::meanShiftProc(const GpuMat& src, GpuMat& dstr, GpuMat& dstsp, int sp, int sr, TermCriteria criteria, Stream& stream) +void cv::gpu::meanShiftProc(InputArray _src, OutputArray _dstr, OutputArray _dstsp, int sp, int sr, TermCriteria criteria, Stream& stream) { using namespace ::cv::gpu::cudev::imgproc; - if( src.empty() ) - CV_Error( cv::Error::StsBadArg, "The input image is empty" ); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.type() == CV_8UC4 ); - if( src.depth() != CV_8U || src.channels() != 4 ) - CV_Error( cv::Error::StsUnsupportedFormat, "Only 8-bit, 4-channel images are supported" ); + _dstr.create(src.size(), CV_8UC4); + _dstsp.create(src.size(), CV_16SC2); - dstr.create( src.size(), CV_8UC4 ); - dstsp.create( src.size(), CV_16SC2 ); + GpuMat dstr = _dstr.getGpuMat(); + GpuMat dstsp = _dstsp.getGpuMat(); - if( !(criteria.type & TermCriteria::MAX_ITER) ) + if (!(criteria.type & TermCriteria::MAX_ITER)) criteria.maxCount = 5; int maxIter = std::min(std::max(criteria.maxCount, 1), 100); - float eps; - if( !(criteria.type & TermCriteria::EPS) ) - eps = 1.f; - eps = (float)std::max(criteria.epsilon, 0.0); + if (!(criteria.type & TermCriteria::EPS)) + criteria.epsilon = 1.f; + + float eps = (float) std::max(criteria.epsilon, 0.0); meanShiftProc_gpu(src, dstr, dstsp, sp, sr, maxIter, eps, StreamAccessor::getStream(stream)); } diff --git a/modules/gpuimgproc/src/mssegmentation.cpp b/modules/gpuimgproc/src/mssegmentation.cpp index 7f02168e1a..ec1c5feb4b 100644 --- a/modules/gpuimgproc/src/mssegmentation.cpp +++ b/modules/gpuimgproc/src/mssegmentation.cpp @@ -43,7 +43,7 @@ #if !defined HAVE_CUDA || defined(CUDA_DISABLER) -void cv::gpu::meanShiftSegmentation(const GpuMat&, Mat&, int, int, int, TermCriteria) { throw_no_cuda(); } +void cv::gpu::meanShiftSegmentation(InputArray, OutputArray, int, int, int, TermCriteria) { throw_no_cuda(); } #else @@ -222,9 +222,12 @@ inline int dist2(const cv::Vec2s& lhs, const cv::Vec2s& rhs) } // anonymous namespace -void cv::gpu::meanShiftSegmentation(const GpuMat& src, Mat& dst, int sp, int sr, int minsize, TermCriteria criteria) +void cv::gpu::meanShiftSegmentation(InputArray _src, OutputArray _dst, int sp, int sr, int minsize, TermCriteria criteria) { - CV_Assert(src.type() == CV_8UC4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.type() == CV_8UC4 ); + const int nrows = src.rows; const int ncols = src.cols; const int hr = sr; @@ -232,7 +235,7 @@ void cv::gpu::meanShiftSegmentation(const GpuMat& src, Mat& dst, int sp, int sr, // Perform mean shift procedure and obtain region and spatial maps GpuMat d_rmap, d_spmap; - meanShiftProc(src, d_rmap, d_spmap, sp, sr, criteria); + gpu::meanShiftProc(src, d_rmap, d_spmap, sp, sr, criteria); Mat rmap(d_rmap); Mat spmap(d_spmap); @@ -337,7 +340,7 @@ void cv::gpu::meanShiftSegmentation(const GpuMat& src, Mat& dst, int sp, int sr, } // Sort all graph's edges connecting differnet components (in asceding order) - sort(edges.begin(), edges.end()); + std::sort(edges.begin(), edges.end()); // Exclude small components (starting from the nearest couple) for (size_t i = 0; i < edges.size(); ++i) @@ -366,7 +369,8 @@ void cv::gpu::meanShiftSegmentation(const GpuMat& src, Mat& dst, int sp, int sr, } // Create final image, color of each segment is the average color of its pixels - dst.create(src.size(), src.type()); + _dst.create(src.size(), src.type()); + Mat dst = _dst.getMat(); for (int y = 0; y < nrows; ++y) { From de56163f9734b35550dafe6c0366635b49e277b8 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 30 Apr 2013 17:27:06 +0400 Subject: [PATCH 10/17] refactored gpu::matchTemplate (converted it into Algorithm) --- .../gpuimgproc/include/opencv2/gpuimgproc.hpp | 24 +- .../gpuimgproc/perf/perf_match_template.cpp | 8 +- modules/gpuimgproc/src/match_template.cpp | 472 +++++++++++++----- .../gpuimgproc/test/test_match_template.cpp | 24 +- samples/gpu/performance/tests.cpp | 16 +- 5 files changed, 390 insertions(+), 154 deletions(-) diff --git a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp index 24b8b64f0a..886e10cabc 100644 --- a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp +++ b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp @@ -424,20 +424,24 @@ CV_EXPORTS void meanShiftSegmentation(InputArray src, OutputArray dst, int sp, i /////////////////////////// Match Template //////////////////////////// -struct CV_EXPORTS MatchTemplateBuf +//! computes the proximity map for the raster template and the image where the template is searched for +class CV_EXPORTS TemplateMatching : public Algorithm { - Size user_block_size; - GpuMat imagef, templf; - std::vector images; - std::vector image_sums; - std::vector image_sqsums; +public: + virtual void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null()) = 0; }; -//! computes the proximity map for the raster template and the image where the template is searched for -CV_EXPORTS void matchTemplate(const GpuMat& image, const GpuMat& templ, GpuMat& result, int method, Stream &stream = Stream::Null()); +CV_EXPORTS Ptr createTemplateMatching(int srcType, int method, Size user_block_size = Size()); -//! computes the proximity map for the raster template and the image where the template is searched for -CV_EXPORTS void matchTemplate(const GpuMat& image, const GpuMat& templ, GpuMat& result, int method, MatchTemplateBuf &buf, Stream& stream = Stream::Null()); +// obsolete + +__OPENCV_GPUIMGPROC_DEPR_BEFORE__ void matchTemplate(InputArray image, InputArray templ, OutputArray result, + int method, Stream& stream = Stream::Null()) __OPENCV_GPUIMGPROC_DEPR_AFTER__; + +inline void matchTemplate(InputArray image, InputArray templ, OutputArray result, int method, Stream& stream) +{ + gpu::createTemplateMatching(image.type(), method)->match(image, templ, result, stream); +} ////////////////////////// Bilateral Filter /////////////////////////// diff --git a/modules/gpuimgproc/perf/perf_match_template.cpp b/modules/gpuimgproc/perf/perf_match_template.cpp index f3af149144..35f36596c6 100644 --- a/modules/gpuimgproc/perf/perf_match_template.cpp +++ b/modules/gpuimgproc/perf/perf_match_template.cpp @@ -76,7 +76,9 @@ PERF_TEST_P(Sz_TemplateSz_Cn_Method, MatchTemplate8U, const cv::gpu::GpuMat d_templ(templ); cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::matchTemplate(d_image, d_templ, dst, method); + cv::Ptr alg = cv::gpu::createTemplateMatching(image.type(), method); + + TEST_CYCLE() alg->match(d_image, d_templ, dst); GPU_SANITY_CHECK(dst, 1e-5, ERROR_RELATIVE); } @@ -116,7 +118,9 @@ PERF_TEST_P(Sz_TemplateSz_Cn_Method, MatchTemplate32F, const cv::gpu::GpuMat d_templ(templ); cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::matchTemplate(d_image, d_templ, dst, method); + cv::Ptr alg = cv::gpu::createTemplateMatching(image.type(), method); + + TEST_CYCLE() alg->match(d_image, d_templ, dst); GPU_SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE); } diff --git a/modules/gpuimgproc/src/match_template.cpp b/modules/gpuimgproc/src/match_template.cpp index 059d41ca9f..2b5d5cb1ca 100644 --- a/modules/gpuimgproc/src/match_template.cpp +++ b/modules/gpuimgproc/src/match_template.cpp @@ -47,7 +47,7 @@ using namespace cv::gpu; #if !defined (HAVE_CUDA) || !defined (HAVE_OPENCV_GPUARITHM) || defined (CUDA_DISABLER) -void cv::gpu::matchTemplate(const GpuMat&, const GpuMat&, GpuMat&, int, Stream&) { throw_no_cuda(); } +Ptr cv::gpu::createTemplateMatching(int, int, Size) { throw_no_cuda(); return Ptr(); } #else @@ -137,11 +137,8 @@ namespace cv { namespace gpu { namespace cudev } }}} -using namespace ::cv::gpu::cudev::match_template; - namespace { - // Evaluates optimal template's area threshold. If // template's area is less than the threshold, we use naive match // template version, otherwise FFT-based (if available) @@ -149,135 +146,317 @@ namespace { switch (method) { - case cv::TM_CCORR: + case TM_CCORR: if (depth == CV_32F) return 250; if (depth == CV_8U) return 300; break; - case cv::TM_SQDIFF: + + case TM_SQDIFF: if (depth == CV_8U) return 300; break; } - CV_Error(cv::Error::StsBadArg, "getTemplateThreshold: unsupported match template mode"); + + CV_Error(Error::StsBadArg, "unsupported match template mode"); return 0; } + /////////////////////////////////////////////////////////////// + // CCORR_32F + + class Match_CCORR_32F : public TemplateMatching + { + public: + explicit Match_CCORR_32F(Size user_block_size); + + void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null()); - void matchTemplate_CCORR_32F( - const GpuMat& image, const GpuMat& templ, GpuMat& result, MatchTemplateBuf &buf, Stream& stream) + private: + Ptr conv_; + GpuMat result_; + }; + + Match_CCORR_32F::Match_CCORR_32F(Size user_block_size) + { + conv_ = gpu::createConvolution(user_block_size); + } + + void Match_CCORR_32F::match(InputArray _image, InputArray _templ, OutputArray _result, Stream& _stream) { - result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32F); - if (templ.size().area() < getTemplateThreshold(cv::TM_CCORR, CV_32F)) + using namespace cv::gpu::cudev::match_template; + + GpuMat image = _image.getGpuMat(); + GpuMat templ = _templ.getGpuMat(); + + CV_Assert( image.depth() == CV_32F ); + CV_Assert( image.type() == templ.type() ); + CV_Assert( image.cols >= templ.cols && image.rows >= templ.rows ); + + cudaStream_t stream = StreamAccessor::getStream(_stream); + + _result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32FC1); + GpuMat result = _result.getGpuMat(); + + if (templ.size().area() < getTemplateThreshold(TM_CCORR, CV_32F)) { - matchTemplateNaive_CCORR_32F(image, templ, result, image.channels(), StreamAccessor::getStream(stream)); + matchTemplateNaive_CCORR_32F(image, templ, result, image.channels(), stream); return; } - Ptr conv = gpu::createConvolution(buf.user_block_size); - if (image.channels() == 1) { - conv->convolve(image.reshape(1), templ.reshape(1), result, true, stream); + conv_->convolve(image.reshape(1), templ.reshape(1), result, true, _stream); } else { - GpuMat result_; - conv->convolve(image.reshape(1), templ.reshape(1), result_, true, stream); - extractFirstChannel_32F(result_, result, image.channels(), StreamAccessor::getStream(stream)); + conv_->convolve(image.reshape(1), templ.reshape(1), result_, true, _stream); + extractFirstChannel_32F(result_, result, image.channels(), stream); } } + /////////////////////////////////////////////////////////////// + // CCORR_8U - void matchTemplate_CCORR_8U( - const GpuMat& image, const GpuMat& templ, GpuMat& result, MatchTemplateBuf &buf, Stream& stream) + class Match_CCORR_8U : public TemplateMatching { - if (templ.size().area() < getTemplateThreshold(cv::TM_CCORR, CV_8U)) + public: + explicit Match_CCORR_8U(Size user_block_size) : match32F_(user_block_size) { - result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32F); + } + + void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null()); + + private: + GpuMat imagef_, templf_; + Match_CCORR_32F match32F_; + }; + + void Match_CCORR_8U::match(InputArray _image, InputArray _templ, OutputArray _result, Stream& stream) + { + using namespace cv::gpu::cudev::match_template; + + GpuMat image = _image.getGpuMat(); + GpuMat templ = _templ.getGpuMat(); + + CV_Assert( image.depth() == CV_8U ); + CV_Assert( image.type() == templ.type() ); + CV_Assert( image.cols >= templ.cols && image.rows >= templ.rows ); + + if (templ.size().area() < getTemplateThreshold(TM_CCORR, CV_8U)) + { + _result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32FC1); + GpuMat result = _result.getGpuMat(); + matchTemplateNaive_CCORR_8U(image, templ, result, image.channels(), StreamAccessor::getStream(stream)); return; } - image.convertTo(buf.imagef, CV_32F, stream); - templ.convertTo(buf.templf, CV_32F, stream); + image.convertTo(imagef_, CV_32F, stream); + templ.convertTo(templf_, CV_32F, stream); - matchTemplate_CCORR_32F(buf.imagef, buf.templf, result, buf, stream); + match32F_.match(imagef_, templf_, _result, stream); } + /////////////////////////////////////////////////////////////// + // CCORR_NORMED_8U - void matchTemplate_CCORR_NORMED_8U( - const GpuMat& image, const GpuMat& templ, GpuMat& result, MatchTemplateBuf &buf, Stream& stream) + class Match_CCORR_NORMED_8U : public TemplateMatching { - matchTemplate_CCORR_8U(image, templ, result, buf, stream); + public: + explicit Match_CCORR_NORMED_8U(Size user_block_size) : match_CCORR_(user_block_size) + { + } + + void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null()); + + private: + Match_CCORR_8U match_CCORR_; + GpuMat image_sqsums_; + GpuMat intBuffer_; + }; + + void Match_CCORR_NORMED_8U::match(InputArray _image, InputArray _templ, OutputArray _result, Stream& stream) + { + using namespace cv::gpu::cudev::match_template; + + GpuMat image = _image.getGpuMat(); + GpuMat templ = _templ.getGpuMat(); - buf.image_sqsums.resize(1); - gpu::sqrIntegral(image.reshape(1), buf.image_sqsums[0], stream); + CV_Assert( image.depth() == CV_8U ); + CV_Assert( image.type() == templ.type() ); + CV_Assert( image.cols >= templ.cols && image.rows >= templ.rows ); - unsigned long long templ_sqsum = (unsigned long long)gpu::sqrSum(templ.reshape(1))[0]; - normalize_8U(templ.cols, templ.rows, buf.image_sqsums[0], templ_sqsum, result, image.channels(), StreamAccessor::getStream(stream)); + match_CCORR_.match(image, templ, _result, stream); + GpuMat result = _result.getGpuMat(); + + gpu::sqrIntegral(image.reshape(1), image_sqsums_, intBuffer_, stream); + + unsigned long long templ_sqsum = (unsigned long long) gpu::sqrSum(templ.reshape(1))[0]; + + normalize_8U(templ.cols, templ.rows, image_sqsums_, templ_sqsum, result, image.channels(), StreamAccessor::getStream(stream)); } + /////////////////////////////////////////////////////////////// + // SQDIFF_32F - void matchTemplate_SQDIFF_32F( - const GpuMat& image, const GpuMat& templ, GpuMat& result, MatchTemplateBuf &buf, Stream& stream) + class Match_SQDIFF_32F : public TemplateMatching { - (void)buf; - result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32F); + public: + void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null()); + }; + + void Match_SQDIFF_32F::match(InputArray _image, InputArray _templ, OutputArray _result, Stream& stream) + { + using namespace cv::gpu::cudev::match_template; + + GpuMat image = _image.getGpuMat(); + GpuMat templ = _templ.getGpuMat(); + + CV_Assert( image.depth() == CV_32F ); + CV_Assert( image.type() == templ.type() ); + CV_Assert( image.cols >= templ.cols && image.rows >= templ.rows ); + + _result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32FC1); + GpuMat result = _result.getGpuMat(); + matchTemplateNaive_SQDIFF_32F(image, templ, result, image.channels(), StreamAccessor::getStream(stream)); } + /////////////////////////////////////////////////////////////// + // SQDIFF_8U - void matchTemplate_SQDIFF_8U( - const GpuMat& image, const GpuMat& templ, GpuMat& result, MatchTemplateBuf &buf, Stream& stream) + class Match_SQDIFF_8U : public TemplateMatching { - if (templ.size().area() < getTemplateThreshold(cv::TM_SQDIFF, CV_8U)) + public: + explicit Match_SQDIFF_8U(Size user_block_size) : match_CCORR_(user_block_size) { - result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32F); + } + + void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null()); + + private: + GpuMat image_sqsums_; + GpuMat intBuffer_; + Match_CCORR_8U match_CCORR_; + }; + + void Match_SQDIFF_8U::match(InputArray _image, InputArray _templ, OutputArray _result, Stream& stream) + { + using namespace cv::gpu::cudev::match_template; + + GpuMat image = _image.getGpuMat(); + GpuMat templ = _templ.getGpuMat(); + + CV_Assert( image.depth() == CV_8U ); + CV_Assert( image.type() == templ.type() ); + CV_Assert( image.cols >= templ.cols && image.rows >= templ.rows ); + + if (templ.size().area() < getTemplateThreshold(TM_SQDIFF, CV_8U)) + { + _result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32FC1); + GpuMat result = _result.getGpuMat(); + matchTemplateNaive_SQDIFF_8U(image, templ, result, image.channels(), StreamAccessor::getStream(stream)); return; } - buf.image_sqsums.resize(1); - gpu::sqrIntegral(image.reshape(1), buf.image_sqsums[0], stream); + gpu::sqrIntegral(image.reshape(1), image_sqsums_, intBuffer_, stream); - unsigned long long templ_sqsum = (unsigned long long)gpu::sqrSum(templ.reshape(1))[0]; + unsigned long long templ_sqsum = (unsigned long long) gpu::sqrSum(templ.reshape(1))[0]; - matchTemplate_CCORR_8U(image, templ, result, buf, stream); - matchTemplatePrepared_SQDIFF_8U(templ.cols, templ.rows, buf.image_sqsums[0], templ_sqsum, result, image.channels(), StreamAccessor::getStream(stream)); + match_CCORR_.match(image, templ, _result, stream); + GpuMat result = _result.getGpuMat(); + + matchTemplatePrepared_SQDIFF_8U(templ.cols, templ.rows, image_sqsums_, templ_sqsum, result, image.channels(), StreamAccessor::getStream(stream)); } + /////////////////////////////////////////////////////////////// + // SQDIFF_NORMED_8U + + class Match_SQDIFF_NORMED_8U : public TemplateMatching + { + public: + explicit Match_SQDIFF_NORMED_8U(Size user_block_size) : match_CCORR_(user_block_size) + { + } + + void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null()); + + private: + GpuMat image_sqsums_; + GpuMat intBuffer_; + Match_CCORR_8U match_CCORR_; + }; - void matchTemplate_SQDIFF_NORMED_8U( - const GpuMat& image, const GpuMat& templ, GpuMat& result, MatchTemplateBuf &buf, Stream& stream) + void Match_SQDIFF_NORMED_8U::match(InputArray _image, InputArray _templ, OutputArray _result, Stream& stream) { - buf.image_sqsums.resize(1); - gpu::sqrIntegral(image.reshape(1), buf.image_sqsums[0], stream); + using namespace cv::gpu::cudev::match_template; - unsigned long long templ_sqsum = (unsigned long long)gpu::sqrSum(templ.reshape(1))[0]; + GpuMat image = _image.getGpuMat(); + GpuMat templ = _templ.getGpuMat(); - matchTemplate_CCORR_8U(image, templ, result, buf, stream); - matchTemplatePrepared_SQDIFF_NORMED_8U(templ.cols, templ.rows, buf.image_sqsums[0], templ_sqsum, result, image.channels(), StreamAccessor::getStream(stream)); + CV_Assert( image.depth() == CV_8U ); + CV_Assert( image.type() == templ.type() ); + CV_Assert( image.cols >= templ.cols && image.rows >= templ.rows ); + + gpu::sqrIntegral(image.reshape(1), image_sqsums_, intBuffer_, stream); + + unsigned long long templ_sqsum = (unsigned long long) gpu::sqrSum(templ.reshape(1))[0]; + + match_CCORR_.match(image, templ, _result, stream); + GpuMat result = _result.getGpuMat(); + + matchTemplatePrepared_SQDIFF_NORMED_8U(templ.cols, templ.rows, image_sqsums_, templ_sqsum, result, image.channels(), StreamAccessor::getStream(stream)); } + /////////////////////////////////////////////////////////////// + // CCOFF_8U - void matchTemplate_CCOFF_8U( - const GpuMat& image, const GpuMat& templ, GpuMat& result, MatchTemplateBuf &buf, Stream& stream) + class Match_CCOEFF_8U : public TemplateMatching { - matchTemplate_CCORR_8U(image, templ, result, buf, stream); + public: + explicit Match_CCOEFF_8U(Size user_block_size) : match_CCORR_(user_block_size) + { + } + + void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null()); + + private: + GpuMat intBuffer_; + std::vector images_; + std::vector image_sums_; + Match_CCORR_8U match_CCORR_; + }; + + void Match_CCOEFF_8U::match(InputArray _image, InputArray _templ, OutputArray _result, Stream& stream) + { + using namespace cv::gpu::cudev::match_template; + + GpuMat image = _image.getGpuMat(); + GpuMat templ = _templ.getGpuMat(); + + CV_Assert( image.depth() == CV_8U ); + CV_Assert( image.type() == templ.type() ); + CV_Assert( image.cols >= templ.cols && image.rows >= templ.rows ); + + match_CCORR_.match(image, templ, _result, stream); + GpuMat result = _result.getGpuMat(); if (image.channels() == 1) { - buf.image_sums.resize(1); - gpu::integral(image, buf.image_sums[0], stream); + image_sums_.resize(1); + gpu::integral(image, image_sums_[0], intBuffer_, stream); + + unsigned int templ_sum = (unsigned int) gpu::sum(templ)[0]; - unsigned int templ_sum = (unsigned int)gpu::sum(templ)[0]; - matchTemplatePrepared_CCOFF_8U(templ.cols, templ.rows, buf.image_sums[0], templ_sum, result, StreamAccessor::getStream(stream)); + matchTemplatePrepared_CCOFF_8U(templ.cols, templ.rows, image_sums_[0], templ_sum, result, StreamAccessor::getStream(stream)); } else { - gpu::split(image, buf.images); - buf.image_sums.resize(buf.images.size()); + gpu::split(image, images_); + + image_sums_.resize(images_.size()); for (int i = 0; i < image.channels(); ++i) - gpu::integral(buf.images[i], buf.image_sums[i], stream); + gpu::integral(images_[i], image_sums_[i], intBuffer_, stream); Scalar templ_sum = gpu::sum(templ); @@ -285,60 +464,91 @@ namespace { case 2: matchTemplatePrepared_CCOFF_8UC2( - templ.cols, templ.rows, buf.image_sums[0], buf.image_sums[1], - (unsigned int)templ_sum[0], (unsigned int)templ_sum[1], + templ.cols, templ.rows, image_sums_[0], image_sums_[1], + (unsigned int) templ_sum[0], (unsigned int) templ_sum[1], result, StreamAccessor::getStream(stream)); break; case 3: matchTemplatePrepared_CCOFF_8UC3( - templ.cols, templ.rows, buf.image_sums[0], buf.image_sums[1], buf.image_sums[2], - (unsigned int)templ_sum[0], (unsigned int)templ_sum[1], (unsigned int)templ_sum[2], + templ.cols, templ.rows, image_sums_[0], image_sums_[1], image_sums_[2], + (unsigned int) templ_sum[0], (unsigned int) templ_sum[1], (unsigned int) templ_sum[2], result, StreamAccessor::getStream(stream)); break; case 4: matchTemplatePrepared_CCOFF_8UC4( - templ.cols, templ.rows, buf.image_sums[0], buf.image_sums[1], buf.image_sums[2], buf.image_sums[3], - (unsigned int)templ_sum[0], (unsigned int)templ_sum[1], (unsigned int)templ_sum[2], - (unsigned int)templ_sum[3], result, StreamAccessor::getStream(stream)); + templ.cols, templ.rows, image_sums_[0], image_sums_[1], image_sums_[2], image_sums_[3], + (unsigned int) templ_sum[0], (unsigned int) templ_sum[1], (unsigned int) templ_sum[2], (unsigned int) templ_sum[3], + result, StreamAccessor::getStream(stream)); break; default: - CV_Error(cv::Error::StsBadArg, "matchTemplate: unsupported number of channels"); + CV_Error(Error::StsBadArg, "unsupported number of channels"); } } } + /////////////////////////////////////////////////////////////// + // CCOFF_NORMED_8U - void matchTemplate_CCOFF_NORMED_8U( - const GpuMat& image, const GpuMat& templ, GpuMat& result, MatchTemplateBuf &buf, Stream& stream) + class Match_CCOEFF_NORMED_8U : public TemplateMatching { - image.convertTo(buf.imagef, CV_32F, stream); - templ.convertTo(buf.templf, CV_32F, stream); + public: + explicit Match_CCOEFF_NORMED_8U(Size user_block_size) : match_CCORR_32F_(user_block_size) + { + } + + void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null()); - matchTemplate_CCORR_32F(buf.imagef, buf.templf, result, buf, stream); + private: + GpuMat imagef_, templf_; + Match_CCORR_32F match_CCORR_32F_; + GpuMat intBuffer_; + std::vector images_; + std::vector image_sums_; + std::vector image_sqsums_; + }; + + void Match_CCOEFF_NORMED_8U::match(InputArray _image, InputArray _templ, OutputArray _result, Stream& stream) + { + using namespace cv::gpu::cudev::match_template; + + GpuMat image = _image.getGpuMat(); + GpuMat templ = _templ.getGpuMat(); + + CV_Assert( image.depth() == CV_8U ); + CV_Assert( image.type() == templ.type() ); + CV_Assert( image.cols >= templ.cols && image.rows >= templ.rows ); + + image.convertTo(imagef_, CV_32F, stream); + templ.convertTo(templf_, CV_32F, stream); + + match_CCORR_32F_.match(imagef_, templf_, _result, stream); + GpuMat result = _result.getGpuMat(); if (image.channels() == 1) { - buf.image_sums.resize(1); - gpu::integral(image, buf.image_sums[0], stream); - buf.image_sqsums.resize(1); - gpu::sqrIntegral(image, buf.image_sqsums[0], stream); + image_sums_.resize(1); + gpu::integral(image, image_sums_[0], intBuffer_, stream); + + image_sqsums_.resize(1); + gpu::sqrIntegral(image, image_sqsums_[0], intBuffer_, stream); - unsigned int templ_sum = (unsigned int)gpu::sum(templ)[0]; - unsigned long long templ_sqsum = (unsigned long long)gpu::sqrSum(templ)[0]; + unsigned int templ_sum = (unsigned int) gpu::sum(templ)[0]; + unsigned long long templ_sqsum = (unsigned long long) gpu::sqrSum(templ)[0]; matchTemplatePrepared_CCOFF_NORMED_8U( - templ.cols, templ.rows, buf.image_sums[0], buf.image_sqsums[0], + templ.cols, templ.rows, image_sums_[0], image_sqsums_[0], templ_sum, templ_sqsum, result, StreamAccessor::getStream(stream)); } else { - gpu::split(image, buf.images); - buf.image_sums.resize(buf.images.size()); - buf.image_sqsums.resize(buf.images.size()); + gpu::split(image, images_); + + image_sums_.resize(images_.size()); + image_sqsums_.resize(images_.size()); for (int i = 0; i < image.channels(); ++i) { - gpu::integral(buf.images[i], buf.image_sums[i], stream); - gpu::sqrIntegral(buf.images[i], buf.image_sqsums[i], stream); + gpu::integral(images_[i], image_sums_[i], intBuffer_, stream); + gpu::sqrIntegral(images_[i], image_sqsums_[i], intBuffer_, stream); } Scalar templ_sum = gpu::sum(templ); @@ -349,8 +559,8 @@ namespace case 2: matchTemplatePrepared_CCOFF_NORMED_8UC2( templ.cols, templ.rows, - buf.image_sums[0], buf.image_sqsums[0], - buf.image_sums[1], buf.image_sqsums[1], + image_sums_[0], image_sqsums_[0], + image_sums_[1], image_sqsums_[1], (unsigned int)templ_sum[0], (unsigned long long)templ_sqsum[0], (unsigned int)templ_sum[1], (unsigned long long)templ_sqsum[1], result, StreamAccessor::getStream(stream)); @@ -358,9 +568,9 @@ namespace case 3: matchTemplatePrepared_CCOFF_NORMED_8UC3( templ.cols, templ.rows, - buf.image_sums[0], buf.image_sqsums[0], - buf.image_sums[1], buf.image_sqsums[1], - buf.image_sums[2], buf.image_sqsums[2], + image_sums_[0], image_sqsums_[0], + image_sums_[1], image_sqsums_[1], + image_sums_[2], image_sqsums_[2], (unsigned int)templ_sum[0], (unsigned long long)templ_sqsum[0], (unsigned int)templ_sum[1], (unsigned long long)templ_sqsum[1], (unsigned int)templ_sum[2], (unsigned long long)templ_sqsum[2], @@ -369,10 +579,10 @@ namespace case 4: matchTemplatePrepared_CCOFF_NORMED_8UC4( templ.cols, templ.rows, - buf.image_sums[0], buf.image_sqsums[0], - buf.image_sums[1], buf.image_sqsums[1], - buf.image_sums[2], buf.image_sqsums[2], - buf.image_sums[3], buf.image_sqsums[3], + image_sums_[0], image_sqsums_[0], + image_sums_[1], image_sqsums_[1], + image_sums_[2], image_sqsums_[2], + image_sums_[3], image_sqsums_[3], (unsigned int)templ_sum[0], (unsigned long long)templ_sqsum[0], (unsigned int)templ_sum[1], (unsigned long long)templ_sqsum[1], (unsigned int)templ_sum[2], (unsigned long long)templ_sqsum[2], @@ -380,46 +590,60 @@ namespace result, StreamAccessor::getStream(stream)); break; default: - CV_Error(cv::Error::StsBadArg, "matchTemplate: unsupported number of channels"); + CV_Error(Error::StsBadArg, "unsupported number of channels"); } } } } - -void cv::gpu::matchTemplate(const GpuMat& image, const GpuMat& templ, GpuMat& result, int method, Stream& stream) +Ptr cv::gpu::createTemplateMatching(int srcType, int method, Size user_block_size) { - MatchTemplateBuf buf; - matchTemplate(image, templ, result, method, buf, stream); -} - + const int sdepth = CV_MAT_DEPTH(srcType); -void cv::gpu::matchTemplate( - const GpuMat& image, const GpuMat& templ, GpuMat& result, int method, - MatchTemplateBuf &buf, Stream& stream) -{ - CV_Assert(image.type() == templ.type()); - CV_Assert(image.cols >= templ.cols && image.rows >= templ.rows); + CV_Assert( sdepth == CV_8U || sdepth == CV_32F ); - typedef void (*Caller)(const GpuMat&, const GpuMat&, GpuMat&, MatchTemplateBuf&, Stream& stream); + if (sdepth == CV_32F) + { + switch (method) + { + case TM_SQDIFF: + return new Match_SQDIFF_32F; - static const Caller callers8U[] = { ::matchTemplate_SQDIFF_8U, ::matchTemplate_SQDIFF_NORMED_8U, - ::matchTemplate_CCORR_8U, ::matchTemplate_CCORR_NORMED_8U, - ::matchTemplate_CCOFF_8U, ::matchTemplate_CCOFF_NORMED_8U }; - static const Caller callers32F[] = { ::matchTemplate_SQDIFF_32F, 0, - ::matchTemplate_CCORR_32F, 0, 0, 0 }; + case TM_CCORR: + return new Match_CCORR_32F(user_block_size); - const Caller* callers = 0; - switch (image.depth()) - { - case CV_8U: callers = callers8U; break; - case CV_32F: callers = callers32F; break; - default: CV_Error(cv::Error::StsBadArg, "matchTemplate: unsupported data type"); + default: + CV_Error( Error::StsBadFlag, "Unsopported method" ); + return Ptr(); + } } + else + { + switch (method) + { + case TM_SQDIFF: + return new Match_SQDIFF_8U(user_block_size); + + case TM_SQDIFF_NORMED: + return new Match_SQDIFF_NORMED_8U(user_block_size); - Caller caller = callers[method]; - CV_Assert(caller); - caller(image, templ, result, buf, stream); + case TM_CCORR: + return new Match_CCORR_8U(user_block_size); + + case TM_CCORR_NORMED: + return new Match_CCORR_NORMED_8U(user_block_size); + + case TM_CCOEFF: + return new Match_CCOEFF_8U(user_block_size); + + case TM_CCOEFF_NORMED: + return new Match_CCOEFF_NORMED_8U(user_block_size); + + default: + CV_Error( Error::StsBadFlag, "Unsopported method" ); + return Ptr(); + } + } } #endif diff --git a/modules/gpuimgproc/test/test_match_template.cpp b/modules/gpuimgproc/test/test_match_template.cpp index d187579230..b6fd161408 100644 --- a/modules/gpuimgproc/test/test_match_template.cpp +++ b/modules/gpuimgproc/test/test_match_template.cpp @@ -82,8 +82,10 @@ GPU_TEST_P(MatchTemplate8U, Accuracy) cv::Mat image = randomMat(size, CV_MAKETYPE(CV_8U, cn)); cv::Mat templ = randomMat(templ_size, CV_MAKETYPE(CV_8U, cn)); + cv::Ptr alg = cv::gpu::createTemplateMatching(image.type(), method); + cv::gpu::GpuMat dst; - cv::gpu::matchTemplate(loadMat(image), loadMat(templ), dst, method); + alg->match(loadMat(image), loadMat(templ), dst); cv::Mat dst_gold; cv::matchTemplate(image, templ, dst_gold, method); @@ -128,8 +130,10 @@ GPU_TEST_P(MatchTemplate32F, Regression) cv::Mat image = randomMat(size, CV_MAKETYPE(CV_32F, cn)); cv::Mat templ = randomMat(templ_size, CV_MAKETYPE(CV_32F, cn)); + cv::Ptr alg = cv::gpu::createTemplateMatching(image.type(), method); + cv::gpu::GpuMat dst; - cv::gpu::matchTemplate(loadMat(image), loadMat(templ), dst, method); + alg->match(loadMat(image), loadMat(templ), dst); cv::Mat dst_gold; cv::matchTemplate(image, templ, dst_gold, method); @@ -169,8 +173,10 @@ GPU_TEST_P(MatchTemplateBlackSource, Accuracy) cv::Mat pattern = readImage("matchtemplate/cat.png"); ASSERT_FALSE(pattern.empty()); + cv::Ptr alg = cv::gpu::createTemplateMatching(image.type(), method); + cv::gpu::GpuMat d_dst; - cv::gpu::matchTemplate(loadMat(image), loadMat(pattern), d_dst, method); + alg->match(loadMat(image), loadMat(pattern), d_dst); cv::Mat dst(d_dst); @@ -214,8 +220,10 @@ GPU_TEST_P(MatchTemplate_CCOEF_NORMED, Accuracy) cv::Mat pattern = readImage(patternName); ASSERT_FALSE(pattern.empty()); + cv::Ptr alg = cv::gpu::createTemplateMatching(image.type(), cv::TM_CCOEFF_NORMED); + cv::gpu::GpuMat d_dst; - cv::gpu::matchTemplate(loadMat(image), loadMat(pattern), d_dst, cv::TM_CCOEFF_NORMED); + alg->match(loadMat(image), loadMat(pattern), d_dst); cv::Mat dst(d_dst); @@ -263,8 +271,10 @@ GPU_TEST_P(MatchTemplate_CanFindBigTemplate, SQDIFF_NORMED) cv::Mat templ = readImage("matchtemplate/template.png"); ASSERT_FALSE(templ.empty()); + cv::Ptr alg = cv::gpu::createTemplateMatching(scene.type(), cv::TM_SQDIFF_NORMED); + cv::gpu::GpuMat d_result; - cv::gpu::matchTemplate(loadMat(scene), loadMat(templ), d_result, cv::TM_SQDIFF_NORMED); + alg->match(loadMat(scene), loadMat(templ), d_result); cv::Mat result(d_result); @@ -286,8 +296,10 @@ GPU_TEST_P(MatchTemplate_CanFindBigTemplate, SQDIFF) cv::Mat templ = readImage("matchtemplate/template.png"); ASSERT_FALSE(templ.empty()); + cv::Ptr alg = cv::gpu::createTemplateMatching(scene.type(), cv::TM_SQDIFF); + cv::gpu::GpuMat d_result; - cv::gpu::matchTemplate(loadMat(scene), loadMat(templ), d_result, cv::TM_SQDIFF); + alg->match(loadMat(scene), loadMat(templ), d_result); cv::Mat result(d_result); diff --git a/samples/gpu/performance/tests.cpp b/samples/gpu/performance/tests.cpp index da2d4e2263..3c26d16b04 100644 --- a/samples/gpu/performance/tests.cpp +++ b/samples/gpu/performance/tests.cpp @@ -17,24 +17,16 @@ using namespace std; using namespace cv; -static void InitMatchTemplate() -{ - Mat src; gen(src, 500, 500, CV_32F, 0, 1); - Mat templ; gen(templ, 500, 500, CV_32F, 0, 1); - gpu::GpuMat d_src(src), d_templ(templ), d_dst; - gpu::matchTemplate(d_src, d_templ, d_dst, TM_CCORR); -} - TEST(matchTemplate) { - InitMatchTemplate(); - Mat src, templ, dst; gen(src, 3000, 3000, CV_32F, 0, 1); gpu::GpuMat d_src(src), d_templ, d_dst; + Ptr alg = gpu::createTemplateMatching(src.type(), TM_CCORR); + for (int templ_size = 5; templ_size < 200; templ_size *= 5) { SUBTEST << src.cols << 'x' << src.rows << ", 32FC1" << ", templ " << templ_size << 'x' << templ_size << ", CCORR"; @@ -47,10 +39,10 @@ TEST(matchTemplate) CPU_OFF; d_templ.upload(templ); - gpu::matchTemplate(d_src, d_templ, d_dst, TM_CCORR); + alg->match(d_src, d_templ, d_dst); GPU_ON; - gpu::matchTemplate(d_src, d_templ, d_dst, TM_CCORR); + alg->match(d_src, d_templ, d_dst); GPU_OFF; } } From 62a5a70cd09a905d44409613126bd70ba6233875 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Mon, 6 May 2013 10:58:09 +0400 Subject: [PATCH 11/17] switched to Input/Output Array in bilateralFilter & blendLinear --- .../gpuimgproc/include/opencv2/gpuimgproc.hpp | 6 ++--- modules/gpuimgproc/src/bilateral_filter.cpp | 19 +++++++------ modules/gpuimgproc/src/blend.cpp | 27 ++++++++++++------- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp index 886e10cabc..2aaef9b6f3 100644 --- a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp +++ b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp @@ -446,15 +446,15 @@ inline void matchTemplate(InputArray image, InputArray templ, OutputArray result ////////////////////////// Bilateral Filter /////////////////////////// //! Performa bilateral filtering of passsed image -CV_EXPORTS void bilateralFilter(const GpuMat& src, GpuMat& dst, int kernel_size, float sigma_color, float sigma_spatial, +CV_EXPORTS void bilateralFilter(InputArray src, OutputArray dst, int kernel_size, float sigma_color, float sigma_spatial, int borderMode = BORDER_DEFAULT, Stream& stream = Stream::Null()); ///////////////////////////// Blending //////////////////////////////// //! performs linear blending of two images //! to avoid accuracy errors sum of weigths shouldn't be very close to zero -CV_EXPORTS void blendLinear(const GpuMat& img1, const GpuMat& img2, const GpuMat& weights1, const GpuMat& weights2, - GpuMat& result, Stream& stream = Stream::Null()); +CV_EXPORTS void blendLinear(InputArray img1, InputArray img2, InputArray weights1, InputArray weights2, + OutputArray result, Stream& stream = Stream::Null()); }} // namespace cv { namespace gpu { diff --git a/modules/gpuimgproc/src/bilateral_filter.cpp b/modules/gpuimgproc/src/bilateral_filter.cpp index c95dbe4f53..b9d0b811e4 100644 --- a/modules/gpuimgproc/src/bilateral_filter.cpp +++ b/modules/gpuimgproc/src/bilateral_filter.cpp @@ -47,7 +47,7 @@ using namespace cv::gpu; #if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) -void cv::gpu::bilateralFilter(const GpuMat&, GpuMat&, int, float, float, int, Stream&) { throw_no_cuda(); } +void cv::gpu::bilateralFilter(InputArray, OutputArray, int, float, float, int, Stream&) { throw_no_cuda(); } #else @@ -60,7 +60,7 @@ namespace cv { namespace gpu { namespace cudev } }}} -void cv::gpu::bilateralFilter(const GpuMat& src, GpuMat& dst, int kernel_size, float sigma_color, float sigma_spatial, int borderMode, Stream& s) +void cv::gpu::bilateralFilter(InputArray _src, OutputArray _dst, int kernel_size, float sigma_color, float sigma_spatial, int borderMode, Stream& stream) { using cv::gpu::cudev::imgproc::bilateral_filter_gpu; @@ -79,18 +79,21 @@ void cv::gpu::bilateralFilter(const GpuMat& src, GpuMat& dst, int kernel_size, f sigma_color = (sigma_color <= 0 ) ? 1 : sigma_color; sigma_spatial = (sigma_spatial <= 0 ) ? 1 : sigma_spatial; - int radius = (kernel_size <= 0) ? cvRound(sigma_spatial*1.5) : kernel_size/2; kernel_size = std::max(radius, 1)*2 + 1; - CV_Assert(src.depth() <= CV_32F && src.channels() <= 4); + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.depth() <= CV_32F && src.channels() <= 4 ); + CV_Assert( borderMode == BORDER_REFLECT101 || borderMode == BORDER_REPLICATE || borderMode == BORDER_CONSTANT || borderMode == BORDER_REFLECT || borderMode == BORDER_WRAP ); + const func_t func = funcs[src.depth()][src.channels() - 1]; - CV_Assert(func != 0); + CV_Assert( func != 0 ); - CV_Assert(borderMode == BORDER_REFLECT101 || borderMode == BORDER_REPLICATE || borderMode == BORDER_CONSTANT || borderMode == BORDER_REFLECT || borderMode == BORDER_WRAP); + _dst.create(src.size(), src.type()); + GpuMat dst = _dst.getGpuMat(); - dst.create(src.size(), src.type()); - func(src, dst, kernel_size, sigma_spatial, sigma_color, borderMode, StreamAccessor::getStream(s)); + func(src, dst, kernel_size, sigma_spatial, sigma_color, borderMode, StreamAccessor::getStream(stream)); } #endif diff --git a/modules/gpuimgproc/src/blend.cpp b/modules/gpuimgproc/src/blend.cpp index e92e379455..71c72a7153 100644 --- a/modules/gpuimgproc/src/blend.cpp +++ b/modules/gpuimgproc/src/blend.cpp @@ -47,7 +47,7 @@ using namespace cv::gpu; #if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) -void cv::gpu::blendLinear(const GpuMat&, const GpuMat&, const GpuMat&, const GpuMat&, GpuMat&, Stream&) { throw_no_cuda(); } +void cv::gpu::blendLinear(InputArray, InputArray, InputArray, InputArray, OutputArray, Stream&) { throw_no_cuda(); } #else @@ -67,21 +67,28 @@ namespace cv { namespace gpu { namespace cudev using namespace ::cv::gpu::cudev::blend; -void cv::gpu::blendLinear(const GpuMat& img1, const GpuMat& img2, const GpuMat& weights1, const GpuMat& weights2, - GpuMat& result, Stream& stream) +void cv::gpu::blendLinear(InputArray _img1, InputArray _img2, InputArray _weights1, InputArray _weights2, + OutputArray _result, Stream& stream) { - CV_Assert(img1.size() == img2.size()); - CV_Assert(img1.type() == img2.type()); - CV_Assert(weights1.size() == img1.size()); - CV_Assert(weights2.size() == img2.size()); - CV_Assert(weights1.type() == CV_32F); - CV_Assert(weights2.type() == CV_32F); + GpuMat img1 = _img1.getGpuMat(); + GpuMat img2 = _img2.getGpuMat(); + + GpuMat weights1 = _weights1.getGpuMat(); + GpuMat weights2 = _weights2.getGpuMat(); + + CV_Assert( img1.size() == img2.size() ); + CV_Assert( img1.type() == img2.type() ); + CV_Assert( weights1.size() == img1.size() ); + CV_Assert( weights2.size() == img2.size() ); + CV_Assert( weights1.type() == CV_32FC1 ); + CV_Assert( weights2.type() == CV_32FC1 ); const Size size = img1.size(); const int depth = img1.depth(); const int cn = img1.channels(); - result.create(size, CV_MAKE_TYPE(depth, cn)); + _result.create(size, CV_MAKE_TYPE(depth, cn)); + GpuMat result = _result.getGpuMat(); switch (depth) { From 9498f8208515789cc37db7cb5684cd2dfce88c93 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Mon, 6 May 2013 13:36:52 +0400 Subject: [PATCH 12/17] updated documentation --- modules/gpuimgproc/doc/color.rst | 68 ++++- modules/gpuimgproc/doc/feature_detection.rst | 111 +++++--- modules/gpuimgproc/doc/histogram.rst | 138 ++++++--- modules/gpuimgproc/doc/hough.rst | 278 ++++++++++++++++--- modules/gpuimgproc/doc/imgproc.rst | 164 ++++++----- 5 files changed, 572 insertions(+), 187 deletions(-) diff --git a/modules/gpuimgproc/doc/color.rst b/modules/gpuimgproc/doc/color.rst index 70de236ea5..5cdcd5749b 100644 --- a/modules/gpuimgproc/doc/color.rst +++ b/modules/gpuimgproc/doc/color.rst @@ -6,16 +6,16 @@ Color space processing gpu::cvtColor ------------------ +------------- Converts an image from one color space to another. -.. ocv:function:: void gpu::cvtColor(const GpuMat& src, GpuMat& dst, int code, int dcn = 0, Stream& stream = Stream::Null()) +.. ocv:function:: void gpu::cvtColor(InputArray src, OutputArray dst, int code, int dcn = 0, Stream& stream = Stream::Null()) :param src: Source image with ``CV_8U`` , ``CV_16U`` , or ``CV_32F`` depth and 1, 3, or 4 channels. - :param dst: Destination image with the same size and depth as ``src`` . + :param dst: Destination image. - :param code: Color space conversion code. For details, see :ocv:func:`cvtColor` . Conversion to/from Luv and Bayer color spaces is not supported. + :param code: Color space conversion code. For details, see :ocv:func:`cvtColor` . :param dcn: Number of channels in the destination image. If the parameter is 0, the number of the channels is derived automatically from ``src`` and the ``code`` . @@ -27,11 +27,45 @@ Converts an image from one color space to another. +gpu::demosaicing +---------------- +Converts an image from Bayer pattern to RGB or grayscale. + +.. ocv:function:: void gpu::demosaicing(InputArray src, OutputArray dst, int code, int dcn = -1, Stream& stream = Stream::Null()) + + :param src: Source image (8-bit or 16-bit single channel). + + :param dst: Destination image. + + :param code: Color space conversion code (see the description below). + + :param dcn: Number of channels in the destination image. If the parameter is 0, the number of the channels is derived automatically from ``src`` and the ``code`` . + + :param stream: Stream for the asynchronous version. + +The function can do the following transformations: + +* Demosaicing using bilinear interpolation + + * ``COLOR_BayerBG2GRAY`` , ``COLOR_BayerGB2GRAY`` , ``COLOR_BayerRG2GRAY`` , ``COLOR_BayerGR2GRAY`` + + * ``COLOR_BayerBG2BGR`` , ``COLOR_BayerGB2BGR`` , ``COLOR_BayerRG2BGR`` , ``COLOR_BayerGR2BGR`` + +* Demosaicing using Malvar-He-Cutler algorithm ([MHT2011]_) + + * ``COLOR_BayerBG2GRAY_MHT`` , ``COLOR_BayerGB2GRAY_MHT`` , ``COLOR_BayerRG2GRAY_MHT`` , ``COLOR_BayerGR2GRAY_MHT`` + + * ``COLOR_BayerBG2BGR_MHT`` , ``COLOR_BayerGB2BGR_MHT`` , ``COLOR_BayerRG2BGR_MHT`` , ``COLOR_BayerGR2BGR_MHT`` + +.. seealso:: :ocv:func:`cvtColor` + + + gpu::swapChannels ----------------- Exchanges the color channels of an image in-place. -.. ocv:function:: void gpu::swapChannels(GpuMat& image, const int dstOrder[4], Stream& stream = Stream::Null()) +.. ocv:function:: void gpu::swapChannels(InputOutputArray image, const int dstOrder[4], Stream& stream = Stream::Null()) :param image: Source image. Supports only ``CV_8UC4`` type. @@ -43,11 +77,27 @@ The methods support arbitrary permutations of the original channels, including r +gpu::gammaCorrection +-------------------- +Routines for correcting image color gamma. + +.. ocv:function:: void gpu::gammaCorrection(InputArray src, OutputArray dst, bool forward = true, Stream& stream = Stream::Null()) + + :param src: Source image (3- or 4-channel 8 bit). + + :param dst: Destination image. + + :param forward: ``true`` for forward gamma correction or ``false`` for inverse gamma correction. + + :param stream: Stream for the asynchronous version. + + + gpu::alphaComp -------------------- +-------------- Composites two images using alpha opacity values contained in each image. -.. ocv:function:: void gpu::alphaComp(const GpuMat& img1, const GpuMat& img2, GpuMat& dst, int alpha_op, Stream& stream = Stream::Null()) +.. ocv:function:: void gpu::alphaComp(InputArray img1, InputArray img2, OutputArray dst, int alpha_op, Stream& stream = Stream::Null()) :param img1: First image. Supports ``CV_8UC4`` , ``CV_16UC4`` , ``CV_32SC4`` and ``CV_32FC4`` types. @@ -72,3 +122,7 @@ Composites two images using alpha opacity values contained in each image. * **ALPHA_PREMUL** :param stream: Stream for the asynchronous version. + + + +.. [MHT2011] Pascal Getreuer, Malvar-He-Cutler Linear Image Demosaicking, Image Processing On Line, 2011 diff --git a/modules/gpuimgproc/doc/feature_detection.rst b/modules/gpuimgproc/doc/feature_detection.rst index c38b8c2007..fc5e592cf8 100644 --- a/modules/gpuimgproc/doc/feature_detection.rst +++ b/modules/gpuimgproc/doc/feature_detection.rst @@ -5,15 +5,41 @@ Feature Detection -gpu::cornerHarris ---------------------- -Computes the Harris cornerness criteria at each image pixel. +gpu::CornernessCriteria +----------------------- +.. ocv:class:: gpu::CornernessCriteria : public Algorithm -.. ocv:function:: void gpu::cornerHarris(const GpuMat& src, GpuMat& dst, int blockSize, int ksize, double k, int borderType=BORDER_REFLECT101) +Base class for Cornerness Criteria computation. :: - :param src: Source image. Only ``CV_8UC1`` and ``CV_32FC1`` images are supported for now. + class CV_EXPORTS CornernessCriteria : public Algorithm + { + public: + virtual void compute(InputArray src, OutputArray dst, Stream& stream = Stream::Null()) = 0; + }; + + + +gpu::CornernessCriteria::compute +-------------------------------- +Computes the cornerness criteria at each image pixel. + +.. ocv:function:: void gpu::CornernessCriteria::compute(InputArray src, OutputArray dst, Stream& stream = Stream::Null()) + + :param src: Source image. + + :param dst: Destination image containing cornerness values. It will have the same size as ``src`` and ``CV_32FC1`` type. - :param dst: Destination image containing cornerness values. It has the same size as ``src`` and ``CV_32FC1`` type. + :param stream: Stream for the asynchronous version. + + + +gpu::createHarrisCorner +----------------------- +Creates implementation for Harris cornerness criteria. + +.. ocv:function:: Ptr gpu::createHarrisCorner(int srcType, int blockSize, int ksize, double k, int borderType = BORDER_REFLECT101) + + :param srcType: Input source type. Only ``CV_8UC1`` and ``CV_32FC1`` are supported for now. :param blockSize: Neighborhood size. @@ -27,55 +53,70 @@ Computes the Harris cornerness criteria at each image pixel. -gpu::cornerMinEigenVal --------------------------- -Computes the minimum eigen value of a 2x2 derivative covariation matrix at each pixel (the cornerness criteria). - -.. ocv:function:: void gpu::cornerMinEigenVal(const GpuMat& src, GpuMat& dst, int blockSize, int ksize, int borderType=BORDER_REFLECT101) - -.. ocv:function:: void gpu::cornerMinEigenVal(const GpuMat& src, GpuMat& dst, GpuMat& Dx, GpuMat& Dy, int blockSize, int ksize, int borderType=BORDER_REFLECT101) - -.. ocv:function:: void gpu::cornerMinEigenVal(const GpuMat& src, GpuMat& dst, GpuMat& Dx, GpuMat& Dy, GpuMat& buf, int blockSize, int ksize, int borderType=BORDER_REFLECT101, Stream& stream = Stream::Null()) +gpu::createMinEigenValCorner +---------------------------- +Creates implementation for the minimum eigen value of a 2x2 derivative covariation matrix (the cornerness criteria). - :param src: Source image. Only ``CV_8UC1`` and ``CV_32FC1`` images are supported for now. +.. ocv:function:: Ptr gpu::createMinEigenValCorner(int srcType, int blockSize, int ksize, int borderType = BORDER_REFLECT101) - :param dst: Destination image containing cornerness values. The size is the same. The type is ``CV_32FC1`` . + :param srcType: Input source type. Only ``CV_8UC1`` and ``CV_32FC1`` are supported for now. :param blockSize: Neighborhood size. :param ksize: Aperture parameter for the Sobel operator. - :param borderType: Pixel extrapolation method. Only ``BORDER_REFLECT101`` and ``BORDER_REPLICATE`` are supported for now. + :param borderType: Pixel extrapolation method. Only ``BORDER_REFLECT101`` and ``BORDER_REPLICATE`` are supported for now. .. seealso:: :ocv:func:`cornerMinEigenVal` -gpu::GoodFeaturesToTrackDetector_GPU ------------------------------------- -.. ocv:class:: gpu::GoodFeaturesToTrackDetector_GPU +gpu::CornersDetector +-------------------- +.. ocv:class:: gpu::CornersDetector : public Algorithm -Class used for strong corners detection on an image. :: +Base class for Corners Detector. :: - class GoodFeaturesToTrackDetector_GPU + class CV_EXPORTS CornersDetector : public Algorithm { public: - explicit GoodFeaturesToTrackDetector_GPU(int maxCorners_ = 1000, double qualityLevel_ = 0.01, double minDistance_ = 0.0, - int blockSize_ = 3, bool useHarrisDetector_ = false, double harrisK_ = 0.04); + virtual void detect(InputArray image, OutputArray corners, InputArray mask = noArray()) = 0; + }; - void operator ()(const GpuMat& image, GpuMat& corners, const GpuMat& mask = GpuMat()); - int maxCorners; - double qualityLevel; - double minDistance; - int blockSize; - bool useHarrisDetector; - double harrisK; +gpu::CornersDetector::detect +---------------------------- +Determines strong corners on an image. - void releaseMemory(); - }; +.. ocv:function:: void gpu::CornersDetector::detect(InputArray image, OutputArray corners, InputArray mask = noArray()) + + :param image: Input 8-bit or floating-point 32-bit, single-channel image. + + :param corners: Output vector of detected corners (1-row matrix with CV_32FC2 type with corners positions). + + :param mask: Optional region of interest. If the image is not empty (it needs to have the type ``CV_8UC1`` and the same size as ``image`` ), it specifies the region in which the corners are detected. + + + +gpu::createGoodFeaturesToTrackDetector +-------------------------------------- +Creates implementation for :ocv:class:`gpu::CornersDetector` . + +.. ocv:function:: Ptr gpu::createGoodFeaturesToTrackDetector(int srcType, int maxCorners = 1000, double qualityLevel = 0.01, double minDistance = 0.0, int blockSize = 3, bool useHarrisDetector = false, double harrisK = 0.04) + + :param srcType: Input source type. Only ``CV_8UC1`` and ``CV_32FC1`` are supported for now. + + :param maxCorners: Maximum number of corners to return. If there are more corners than are found, the strongest of them is returned. + + :param qualityLevel: Parameter characterizing the minimal accepted quality of image corners. The parameter value is multiplied by the best corner quality measure, which is the minimal eigenvalue (see :ocv:func:`cornerMinEigenVal` ) or the Harris function response (see :ocv:func:`cornerHarris` ). The corners with the quality measure less than the product are rejected. For example, if the best corner has the quality measure = 1500, and the ``qualityLevel=0.01`` , then all the corners with the quality measure less than 15 are rejected. + + :param minDistance: Minimum possible Euclidean distance between the returned corners. + + :param blockSize: Size of an average block for computing a derivative covariation matrix over each pixel neighborhood. See :ocv:func:`cornerEigenValsAndVecs` . + + :param useHarrisDetector: Parameter indicating whether to use a Harris detector (see :ocv:func:`cornerHarris`) or :ocv:func:`cornerMinEigenVal`. -The class finds the most prominent corners in the image. + :param harrisK: Free parameter of the Harris detector. .. seealso:: :ocv:func:`goodFeaturesToTrack` diff --git a/modules/gpuimgproc/doc/histogram.rst b/modules/gpuimgproc/doc/histogram.rst index 7b29de6ba9..dfdf322864 100644 --- a/modules/gpuimgproc/doc/histogram.rst +++ b/modules/gpuimgproc/doc/histogram.rst @@ -5,11 +5,89 @@ Histogram Calculation +gpu::calcHist +------------- +Calculates histogram for one channel 8-bit image. + +.. ocv:function:: void gpu::calcHist(InputArray src, OutputArray hist, Stream& stream = Stream::Null()) + + :param src: Source image with ``CV_8UC1`` type. + + :param hist: Destination histogram with one row, 256 columns, and the ``CV_32SC1`` type. + + :param stream: Stream for the asynchronous version. + + + +gpu::equalizeHist +----------------- +Equalizes the histogram of a grayscale image. + +.. ocv:function:: void gpu::equalizeHist(InputArray src, OutputArray dst, Stream& stream = Stream::Null()) + +.. ocv:function:: void gpu::equalizeHist(InputArray src, OutputArray dst, InputOutputArray buf, Stream& stream = Stream::Null()) + + :param src: Source image with ``CV_8UC1`` type. + + :param dst: Destination image. + + :param buf: Optional buffer to avoid extra memory allocations (for many calls with the same sizes). + + :param stream: Stream for the asynchronous version. + +.. seealso:: :ocv:func:`equalizeHist` + + + +gpu::CLAHE +---------- +.. ocv:class:: gpu::CLAHE : public cv::CLAHE + +Base class for Contrast Limited Adaptive Histogram Equalization. :: + + class CV_EXPORTS CLAHE : public cv::CLAHE + { + public: + using cv::CLAHE::apply; + virtual void apply(InputArray src, OutputArray dst, Stream& stream) = 0; + }; + + + +gpu::CLAHE::apply +----------------- +Equalizes the histogram of a grayscale image using Contrast Limited Adaptive Histogram Equalization. + +.. ocv:function:: void gpu::CLAHE::apply(InputArray src, OutputArray dst) + +.. ocv:function:: void gpu::CLAHE::apply(InputArray src, OutputArray dst, Stream& stream) + + :param src: Source image with ``CV_8UC1`` type. + + :param dst: Destination image. + + :param stream: Stream for the asynchronous version. + + + +gpu::createCLAHE +---------------- +Creates implementation for :ocv:class:`gpu::CLAHE` . + +.. ocv:function:: Ptr createCLAHE(double clipLimit = 40.0, Size tileGridSize = Size(8, 8)) + + :param clipLimit: Threshold for contrast limiting. + + :param tileGridSize: Size of grid for histogram equalization. Input image will be divided into equally sized rectangular tiles. ``tileGridSize`` defines the number of tiles in row and column. + + + + gpu::evenLevels -------------------- +--------------- Computes levels with even distribution. -.. ocv:function:: void gpu::evenLevels(GpuMat& levels, int nLevels, int lowerLevel, int upperLevel) +.. ocv:function:: void gpu::evenLevels(OutputArray levels, int nLevels, int lowerLevel, int upperLevel) :param levels: Destination array. ``levels`` has 1 row, ``nLevels`` columns, and the ``CV_32SC1`` type. @@ -22,16 +100,16 @@ Computes levels with even distribution. gpu::histEven ------------------ +------------- Calculates a histogram with evenly distributed bins. -.. ocv:function:: void gpu::histEven(const GpuMat& src, GpuMat& hist, int histSize, int lowerLevel, int upperLevel, Stream& stream = Stream::Null()) +.. ocv:function:: void gpu::histEven(InputArray src, OutputArray hist, int histSize, int lowerLevel, int upperLevel, Stream& stream = Stream::Null()) -.. ocv:function:: void gpu::histEven(const GpuMat& src, GpuMat& hist, GpuMat& buf, int histSize, int lowerLevel, int upperLevel, Stream& stream = Stream::Null()) +.. ocv:function:: void gpu::histEven(InputArray src, OutputArray hist, InputOutputArray buf, int histSize, int lowerLevel, int upperLevel, Stream& stream = Stream::Null()) -.. ocv:function:: void gpu::histEven( const GpuMat& src, GpuMat hist[4], int histSize[4], int lowerLevel[4], int upperLevel[4], Stream& stream=Stream::Null() ) +.. ocv:function:: void gpu::histEven(InputArray src, GpuMat hist[4], int histSize[4], int lowerLevel[4], int upperLevel[4], Stream& stream = Stream::Null()) -.. ocv:function:: void gpu::histEven( const GpuMat& src, GpuMat hist[4], GpuMat& buf, int histSize[4], int lowerLevel[4], int upperLevel[4], Stream& stream=Stream::Null() ) +.. ocv:function:: void gpu::histEven(InputArray src, GpuMat hist[4], InputOutputArray buf, int histSize[4], int lowerLevel[4], int upperLevel[4], Stream& stream = Stream::Null()) :param src: Source image. ``CV_8U``, ``CV_16U``, or ``CV_16S`` depth and 1 or 4 channels are supported. For a four-channel image, all channels are processed separately. @@ -50,12 +128,16 @@ Calculates a histogram with evenly distributed bins. gpu::histRange ------------------- +-------------- Calculates a histogram with bins determined by the ``levels`` array. -.. ocv:function:: void gpu::histRange(const GpuMat& src, GpuMat& hist, const GpuMat& levels, Stream& stream = Stream::Null()) +.. ocv:function:: void gpu::histRange(InputArray src, OutputArray hist, InputArray levels, Stream& stream = Stream::Null()) + +.. ocv:function:: void gpu::histRange(InputArray src, OutputArray hist, InputArray levels, InputOutputArray buf, Stream& stream = Stream::Null()) -.. ocv:function:: void gpu::histRange(const GpuMat& src, GpuMat& hist, const GpuMat& levels, GpuMat& buf, Stream& stream = Stream::Null()) +.. ocv:function:: void gpu::histRange(InputArray src, GpuMat hist[4], const GpuMat levels[4], Stream& stream = Stream::Null()) + +.. ocv:function:: void gpu::histRange(InputArray src, GpuMat hist[4], const GpuMat levels[4], InputOutputArray buf, Stream& stream = Stream::Null()) :param src: Source image. ``CV_8U`` , ``CV_16U`` , or ``CV_16S`` depth and 1 or 4 channels are supported. For a four-channel image, all channels are processed separately. @@ -66,39 +148,3 @@ Calculates a histogram with bins determined by the ``levels`` array. :param buf: Optional buffer to avoid extra memory allocations (for many calls with the same sizes). :param stream: Stream for the asynchronous version. - - - -gpu::calcHist ------------------- -Calculates histogram for one channel 8-bit image. - -.. ocv:function:: void gpu::calcHist(const GpuMat& src, GpuMat& hist, Stream& stream = Stream::Null()) - - :param src: Source image. - - :param hist: Destination histogram with one row, 256 columns, and the ``CV_32SC1`` type. - - :param stream: Stream for the asynchronous version. - - - -gpu::equalizeHist ------------------- -Equalizes the histogram of a grayscale image. - -.. ocv:function:: void gpu::equalizeHist(const GpuMat& src, GpuMat& dst, Stream& stream = Stream::Null()) - -.. ocv:function:: void gpu::equalizeHist(const GpuMat& src, GpuMat& dst, GpuMat& hist, GpuMat& buf, Stream& stream = Stream::Null()) - - :param src: Source image. - - :param dst: Destination image. - - :param hist: Destination histogram with one row, 256 columns, and the ``CV_32SC1`` type. - - :param buf: Optional buffer to avoid extra memory allocations (for many calls with the same sizes). - - :param stream: Stream for the asynchronous version. - -.. seealso:: :ocv:func:`equalizeHist` diff --git a/modules/gpuimgproc/doc/hough.rst b/modules/gpuimgproc/doc/hough.rst index 33afabbb6b..eb0f83c97e 100644 --- a/modules/gpuimgproc/doc/hough.rst +++ b/modules/gpuimgproc/doc/hough.rst @@ -5,18 +5,70 @@ Hough Transform -gpu::HoughLines ---------------- -Finds lines in a binary image using the classical Hough transform. +gpu::HoughLinesDetector +----------------------- +.. ocv:class:: gpu::HoughLinesDetector : public Algorithm + +Base class for lines detector algorithm. :: + + class CV_EXPORTS HoughLinesDetector : public Algorithm + { + public: + virtual void detect(InputArray src, OutputArray lines) = 0; + virtual void downloadResults(InputArray d_lines, OutputArray h_lines, OutputArray h_votes = noArray()) = 0; + + virtual void setRho(float rho) = 0; + virtual float getRho() const = 0; + + virtual void setTheta(float theta) = 0; + virtual float getTheta() const = 0; + + virtual void setThreshold(int threshold) = 0; + virtual int getThreshold() const = 0; + + virtual void setDoSort(bool doSort) = 0; + virtual bool getDoSort() const = 0; -.. ocv:function:: void gpu::HoughLines(const GpuMat& src, GpuMat& lines, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096) + virtual void setMaxLines(int maxLines) = 0; + virtual int getMaxLines() const = 0; + }; -.. ocv:function:: void gpu::HoughLines(const GpuMat& src, GpuMat& lines, HoughLinesBuf& buf, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096) + + +gpu::HoughLinesDetector::detect +------------------------------- +Finds lines in a binary image using the classical Hough transform. + +.. ocv:function:: void gpu::HoughLinesDetector::detect(InputArray src, OutputArray lines) :param src: 8-bit, single-channel binary source image. :param lines: Output vector of lines. Each line is represented by a two-element vector :math:`(\rho, \theta)` . :math:`\rho` is the distance from the coordinate origin :math:`(0,0)` (top-left corner of the image). :math:`\theta` is the line rotation angle in radians ( :math:`0 \sim \textrm{vertical line}, \pi/2 \sim \textrm{horizontal line}` ). +.. seealso:: :ocv:func:`HoughLines` + + + +gpu::HoughLinesDetector::downloadResults +---------------------------------------- +Downloads results from :ocv:func:`gpu::HoughLinesDetector::detect` to host memory. + +.. ocv:function:: void gpu::HoughLinesDetector::downloadResults(InputArray d_lines, OutputArray h_lines, OutputArray h_votes = noArray()) + + :param d_lines: Result of :ocv:func:`gpu::HoughLinesDetector::detect` . + + :param h_lines: Output host array. + + :param h_votes: Optional output array for line's votes. + + + +gpu::createHoughLinesDetector +----------------------------- +Creates implementation for :ocv:class:`gpu::HoughLinesDetector` . + +.. ocv:function:: Ptr gpu::createHoughLinesDetector(float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096) + :param rho: Distance resolution of the accumulator in pixels. :param theta: Angle resolution of the accumulator in radians. @@ -27,47 +79,129 @@ Finds lines in a binary image using the classical Hough transform. :param maxLines: Maximum number of output lines. - :param buf: Optional buffer to avoid extra memory allocations (for many calls with the same sizes). -.. seealso:: :ocv:func:`HoughLines` +gpu::HoughSegmentDetector +------------------------- +.. ocv:class:: gpu::HoughSegmentDetector : public Algorithm +Base class for line segments detector algorithm. :: -gpu::HoughLinesDownload ------------------------ -Downloads results from :ocv:func:`gpu::HoughLines` to host memory. + class CV_EXPORTS HoughSegmentDetector : public Algorithm + { + public: + virtual void detect(InputArray src, OutputArray lines) = 0; -.. ocv:function:: void gpu::HoughLinesDownload(const GpuMat& d_lines, OutputArray h_lines, OutputArray h_votes = noArray()) + virtual void setRho(float rho) = 0; + virtual float getRho() const = 0; - :param d_lines: Result of :ocv:func:`gpu::HoughLines` . + virtual void setTheta(float theta) = 0; + virtual float getTheta() const = 0; - :param h_lines: Output host array. + virtual void setMinLineLength(int minLineLength) = 0; + virtual int getMinLineLength() const = 0; - :param h_votes: Optional output array for line's votes. + virtual void setMaxLineGap(int maxLineGap) = 0; + virtual int getMaxLineGap() const = 0; -.. seealso:: :ocv:func:`gpu::HoughLines` + virtual void setMaxLines(int maxLines) = 0; + virtual int getMaxLines() const = 0; + }; -gpu::HoughCircles ------------------ -Finds circles in a grayscale image using the Hough transform. +gpu::HoughSegmentDetector::detect +--------------------------------- +Finds line segments in a binary image using the probabilistic Hough transform. + +.. ocv:function:: void gpu::HoughSegmentDetector::detect(InputArray src, OutputArray lines) + + :param src: 8-bit, single-channel binary source image. + + :param lines: Output vector of lines. Each line is represented by a 4-element vector :math:`(x_1, y_1, x_2, y_2)` , where :math:`(x_1,y_1)` and :math:`(x_2, y_2)` are the ending points of each detected line segment. + +.. seealso:: :ocv:func:`HoughLinesP` + + + +gpu::createHoughSegmentDetector +------------------------------- +Creates implementation for :ocv:class:`gpu::HoughSegmentDetector` . + +.. ocv:function:: Ptr gpu::createHoughSegmentDetector(float rho, float theta, int minLineLength, int maxLineGap, int maxLines = 4096) + + :param rho: Distance resolution of the accumulator in pixels. + + :param theta: Angle resolution of the accumulator in radians. + + :param minLineLength: Minimum line length. Line segments shorter than that are rejected. + + :param maxLineGap: Maximum allowed gap between points on the same line to link them. + + :param maxLines: Maximum number of output lines. + + + +gpu::HoughCirclesDetector +------------------------- +.. ocv:class:: gpu::HoughCirclesDetector : public Algorithm + +Base class for circles detector algorithm. :: + + class CV_EXPORTS HoughCirclesDetector : public Algorithm + { + public: + virtual void detect(InputArray src, OutputArray circles) = 0; + + virtual void setDp(float dp) = 0; + virtual float getDp() const = 0; -.. ocv:function:: void gpu::HoughCircles(const GpuMat& src, GpuMat& circles, int method, float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles = 4096) + virtual void setMinDist(float minDist) = 0; + virtual float getMinDist() const = 0; -.. ocv:function:: void gpu::HoughCircles(const GpuMat& src, GpuMat& circles, HoughCirclesBuf& buf, int method, float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles = 4096) + virtual void setCannyThreshold(int cannyThreshold) = 0; + virtual int getCannyThreshold() const = 0; + + virtual void setVotesThreshold(int votesThreshold) = 0; + virtual int getVotesThreshold() const = 0; + + virtual void setMinRadius(int minRadius) = 0; + virtual int getMinRadius() const = 0; + + virtual void setMaxRadius(int maxRadius) = 0; + virtual int getMaxRadius() const = 0; + + virtual void setMaxCircles(int maxCircles) = 0; + virtual int getMaxCircles() const = 0; + }; + + + +gpu::HoughCirclesDetector::detect +--------------------------------- +Finds circles in a grayscale image using the Hough transform. + +.. ocv:function:: void gpu::HoughCirclesDetector::detect(InputArray src, OutputArray circles) :param src: 8-bit, single-channel grayscale input image. :param circles: Output vector of found circles. Each vector is encoded as a 3-element floating-point vector :math:`(x, y, radius)` . - :param method: Detection method to use. Currently, the only implemented method is ``CV_HOUGH_GRADIENT`` , which is basically *21HT* , described in [Yuen90]_. +.. seealso:: :ocv:func:`HoughCircles` + + + +gpu::createHoughCirclesDetector +------------------------------- +Creates implementation for :ocv:class:`gpu::HoughCirclesDetector` . + +.. ocv:function:: Ptr gpu::createHoughCirclesDetector(float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles = 4096) :param dp: Inverse ratio of the accumulator resolution to the image resolution. For example, if ``dp=1`` , the accumulator has the same resolution as the input image. If ``dp=2`` , the accumulator has half as big width and height. :param minDist: Minimum distance between the centers of the detected circles. If the parameter is too small, multiple neighbor circles may be falsely detected in addition to a true one. If it is too large, some circles may be missed. - :param cannyThreshold: The higher threshold of the two passed to the :ocv:func:`gpu::Canny` edge detector (the lower one is twice smaller). + :param cannyThreshold: The higher threshold of the two passed to Canny edge detector (the lower one is twice smaller). :param votesThreshold: The accumulator threshold for the circle centers at the detection stage. The smaller it is, the more false circles may be detected. @@ -77,20 +211,102 @@ Finds circles in a grayscale image using the Hough transform. :param maxCircles: Maximum number of output circles. - :param buf: Optional buffer to avoid extra memory allocations (for many calls with the same sizes). -.. seealso:: :ocv:func:`HoughCircles` +gpu::GeneralizedHough +--------------------- +.. ocv:class:: gpu::GeneralizedHough : public Algorithm +Base class for generalized hough transform. :: -gpu::HoughCirclesDownload -------------------------- -Downloads results from :ocv:func:`gpu::HoughCircles` to host memory. + class CV_EXPORTS GeneralizedHough : public Algorithm + { + public: + static Ptr create(int method); + + virtual void setTemplate(InputArray templ, int cannyThreshold = 100, Point templCenter = Point(-1, -1)) = 0; + virtual void setTemplate(InputArray edges, InputArray dx, InputArray dy, Point templCenter = Point(-1, -1)) = 0; + + virtual void detect(InputArray image, OutputArray positions, int cannyThreshold = 100) = 0; + virtual void detect(InputArray edges, InputArray dx, InputArray dy, OutputArray positions) = 0; + + virtual void downloadResults(InputArray d_positions, OutputArray h_positions, OutputArray h_votes = noArray()) = 0; + }; + + +Finds arbitrary template in the grayscale image using Generalized Hough Transform. + + + +gpu::GeneralizedHough::create +----------------------------- +Creates implementation for :ocv:class:`gpu::GeneralizedHough` . + +.. ocv:function:: Ptr gpu::GeneralizedHough::create(int method) + + :param method: Combination of flags ( ``cv::GeneralizedHough::GHT_POSITION`` , ``cv::GeneralizedHough::GHT_SCALE`` , ``cv::GeneralizedHough::GHT_ROTATION`` ) specifying transformation to find. + +For full affine transformations (move + scale + rotation) [Guil1999]_ algorithm is used, otherwise [Ballard1981]_ algorithm is used. + + + +gpu::GeneralizedHough::setTemplate +---------------------------------- +Set template to search. + +.. ocv:function:: void gpu::GeneralizedHough::setTemplate(InputArray templ, int cannyThreshold = 100, Point templCenter = Point(-1, -1)) + +.. ocv:function:: void gpu::GeneralizedHough::setTemplate(InputArray edges, InputArray dx, InputArray dy, Point templCenter = Point(-1, -1)) + + :param templ: Template image. Canny edge detector will be applied to extract template edges. + + :param cannyThreshold: Threshold value for Canny edge detector. + + :param templCenter: Center for rotation. By default image center will be used. + + :param edges: Edge map for template image. + + :param dx: First derivative of template image in the vertical direction. Support only ``CV_32S`` type. + + :param dy: First derivative of template image in the horizontal direction. Support only ``CV_32S`` type. + + + +gpu::GeneralizedHough::detect +----------------------------- +Finds template (set by :ocv:func:`gpu::GeneralizedHough::setTemplate` ) in the grayscale image. + +.. ocv:function:: void gpu::GeneralizedHough::detect(InputArray image, OutputArray positions, int cannyThreshold = 100) + +.. ocv:function:: void gpu::GeneralizedHough::detect(InputArray edges, InputArray dx, InputArray dy, OutputArray positions) + + :param templ: Input image. Canny edge detector will be applied to extract template edges. + + :param positions: Output vector of found objects. Each vector is encoded as a 4-element floating-point vector :math:`(x, y, scale, angle)` . + + :param cannyThreshold: Threshold value for Canny edge detector. + + :param edges: Edge map for input image. + + :param dx: First derivative of input image in the vertical direction. Support only ``CV_32S`` type. + + :param dy: First derivative of input image in the horizontal direction. Support only ``CV_32S`` type. + + + +gpu::GeneralizedHough::downloadResults +-------------------------------------- +Downloads results from :ocv:func:`gpu::GeneralizedHough::detect` to host memory. + +.. ocv:function:: void gpu::GeneralizedHough::downloadResult(InputArray d_positions, OutputArray h_positions, OutputArray h_votes = noArray()) + + :param d_lines: Result of :ocv:func:`gpu::GeneralizedHough::detect` . + + :param h_lines: Output host array. -.. ocv:function:: void gpu::HoughCirclesDownload(const GpuMat& d_circles, OutputArray h_circles) + :param h_votes: Optional output array for votes. Each vector is encoded as a 3-element integer-point vector :math:`(position_votes, scale_votes, angle_votes)` . - :param d_circles: Result of :ocv:func:`gpu::HoughCircles` . - :param h_circles: Output host array. -.. seealso:: :ocv:func:`gpu::HoughCircles` +.. [Ballard1981] Ballard, D.H. (1981). Generalizing the Hough transform to detect arbitrary shapes. Pattern Recognition 13 (2): 111-122. +.. [Guil1999] Guil, N., González-Linares, J.M. and Zapata, E.L. (1999). Bidimensional shape detection using an invariant approach. Pattern Recognition 32 (6): 1025-1038. diff --git a/modules/gpuimgproc/doc/imgproc.rst b/modules/gpuimgproc/doc/imgproc.rst index cd91afecfa..776c339a53 100644 --- a/modules/gpuimgproc/doc/imgproc.rst +++ b/modules/gpuimgproc/doc/imgproc.rst @@ -5,11 +5,72 @@ Image Processing +gpu::CannyEdgeDetector +---------------------- +.. ocv:class:: gpu::CannyEdgeDetector : public Algorithm + +Base class for Canny Edge Detector. :: + + class CV_EXPORTS CannyEdgeDetector : public Algorithm + { + public: + virtual void detect(InputArray image, OutputArray edges) = 0; + virtual void detect(InputArray dx, InputArray dy, OutputArray edges) = 0; + + virtual void setLowThreshold(double low_thresh) = 0; + virtual double getLowThreshold() const = 0; + + virtual void setHighThreshold(double high_thresh) = 0; + virtual double getHighThreshold() const = 0; + + virtual void setAppertureSize(int apperture_size) = 0; + virtual int getAppertureSize() const = 0; + + virtual void setL2Gradient(bool L2gradient) = 0; + virtual bool getL2Gradient() const = 0; + }; + + + +gpu::CannyEdgeDetector::detect +------------------------------ +Finds edges in an image using the [Canny86]_ algorithm. + +.. ocv:function:: void gpu::CannyEdgeDetector::detect(InputArray image, OutputArray edges) + +.. ocv:function:: void gpu::CannyEdgeDetector::detect(InputArray dx, InputArray dy, OutputArray edges) + + :param image: Single-channel 8-bit input image. + + :param dx: First derivative of image in the vertical direction. Support only ``CV_32S`` type. + + :param dy: First derivative of image in the horizontal direction. Support only ``CV_32S`` type. + + :param edges: Output edge map. It has the same size and type as ``image`` . + + + +gpu::createCannyEdgeDetector +---------------------------- +Creates implementation for :ocv:class:`gpu::CannyEdgeDetector` . + +.. ocv:function:: Ptr gpu::createCannyEdgeDetector(double low_thresh, double high_thresh, int apperture_size = 3, bool L2gradient = false) + + :param low_thresh: First threshold for the hysteresis procedure. + + :param high_thresh: Second threshold for the hysteresis procedure. + + :param apperture_size: Aperture size for the :ocv:func:`Sobel` operator. + + :param L2gradient: Flag indicating whether a more accurate :math:`L_2` norm :math:`=\sqrt{(dI/dx)^2 + (dI/dy)^2}` should be used to compute the image gradient magnitude ( ``L2gradient=true`` ), or a faster default :math:`L_1` norm :math:`=|dI/dx|+|dI/dy|` is enough ( ``L2gradient=false`` ). + + + gpu::meanShiftFiltering ---------------------------- +----------------------- Performs mean-shift filtering for each point of the source image. -.. ocv:function:: void gpu::meanShiftFiltering( const GpuMat& src, GpuMat& dst, int sp, int sr, TermCriteria criteria=TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1), Stream& stream=Stream::Null() ) +.. ocv:function:: void gpu::meanShiftFiltering(InputArray src, OutputArray dst, int sp, int sr, TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1), Stream& stream = Stream::Null()) :param src: Source image. Only ``CV_8UC4`` images are supported for now. @@ -26,10 +87,10 @@ It maps each point of the source image into another point. As a result, you have gpu::meanShiftProc ----------------------- +------------------ Performs a mean-shift procedure and stores information about processed points (their colors and positions) in two images. -.. ocv:function:: void gpu::meanShiftProc( const GpuMat& src, GpuMat& dstr, GpuMat& dstsp, int sp, int sr, TermCriteria criteria=TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1), Stream& stream=Stream::Null() ) +.. ocv:function:: void gpu::meanShiftProc(InputArray src, OutputArray dstr, OutputArray dstsp, int sp, int sr, TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1), Stream& stream = Stream::Null()) :param src: Source image. Only ``CV_8UC4`` images are supported for now. @@ -48,14 +109,14 @@ Performs a mean-shift procedure and stores information about processed points (t gpu::meanShiftSegmentation ------------------------------- +-------------------------- Performs a mean-shift segmentation of the source image and eliminates small segments. -.. ocv:function:: void gpu::meanShiftSegmentation(const GpuMat& src, Mat& dst, int sp, int sr, int minsize, TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1)) +.. ocv:function:: void gpu::meanShiftSegmentation(InputArray src, OutputArray dst, int sp, int sr, int minsize, TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1)) :param src: Source image. Only ``CV_8UC4`` images are supported for now. - :param dst: Segmented image with the same size and type as ``src`` . + :param dst: Segmented image with the same size and type as ``src`` (host memory). :param sp: Spatial window radius. @@ -67,46 +128,49 @@ Performs a mean-shift segmentation of the source image and eliminates small segm -gpu::MatchTemplateBuf +gpu::TemplateMatching --------------------- -.. ocv:struct:: gpu::MatchTemplateBuf +.. ocv:class:: gpu::TemplateMatching : public Algorithm -Class providing memory buffers for :ocv:func:`gpu::matchTemplate` function, plus it allows to adjust some specific parameters. :: +Base class for Template Matching. :: - struct CV_EXPORTS MatchTemplateBuf + class CV_EXPORTS TemplateMatching : public Algorithm { - Size user_block_size; - GpuMat imagef, templf; - std::vector images; - std::vector image_sums; - std::vector image_sqsums; + public: + virtual void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null()) = 0; }; -You can use field `user_block_size` to set specific block size for :ocv:func:`gpu::matchTemplate` function. If you leave its default value `Size(0,0)` then automatic estimation of block size will be used (which is optimized for speed). By varying `user_block_size` you can reduce memory requirements at the cost of speed. - -gpu::matchTemplate ----------------------- +gpu::TemplateMatching::match +---------------------------- Computes a proximity map for a raster template and an image where the template is searched for. -.. ocv:function:: void gpu::matchTemplate(const GpuMat& image, const GpuMat& templ, GpuMat& result, int method, Stream &stream = Stream::Null()) - -.. ocv:function:: void gpu::matchTemplate(const GpuMat& image, const GpuMat& templ, GpuMat& result, int method, MatchTemplateBuf &buf, Stream& stream = Stream::Null()) +.. ocv:function:: void gpu::TemplateMatching::match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null()) - :param image: Source image. ``CV_32F`` and ``CV_8U`` depth images (1..4 channels) are supported for now. + :param image: Source image. :param templ: Template image with the size and type the same as ``image`` . :param result: Map containing comparison results ( ``CV_32FC1`` ). If ``image`` is *W x H* and ``templ`` is *w x h*, then ``result`` must be *W-w+1 x H-h+1*. - :param method: Specifies the way to compare the template with the image. + :param stream: Stream for the asynchronous version. - :param buf: Optional buffer to avoid extra memory allocations and to adjust some specific parameters. See :ocv:struct:`gpu::MatchTemplateBuf`. - :param stream: Stream for the asynchronous version. - The following methods are supported for the ``CV_8U`` depth images for now: +gpu::createTemplateMatching +--------------------------- +Creates implementation for :ocv:class:`gpu::TemplateMatching` . + +.. ocv:function:: Ptr gpu::createTemplateMatching(int srcType, int method, Size user_block_size = Size()) + + :param srcType: Input source type. ``CV_32F`` and ``CV_8U`` depth images (1..4 channels) are supported for now. + + :param method: Specifies the way to compare the template with the image. + + :param user_block_size: You can use field `user_block_size` to set specific block size. If you leave its default value `Size(0,0)` then automatic estimation of block size will be used (which is optimized for speed). By varying `user_block_size` you can reduce memory requirements at the cost of speed. + +The following methods are supported for the ``CV_8U`` depth images for now: * ``CV_TM_SQDIFF`` * ``CV_TM_SQDIFF_NORMED`` @@ -115,7 +179,7 @@ Computes a proximity map for a raster template and an image where the template i * ``CV_TM_CCOEFF`` * ``CV_TM_CCOEFF_NORMED`` - The following methods are supported for the ``CV_32F`` images for now: +The following methods are supported for the ``CV_32F`` images for now: * ``CV_TM_SQDIFF`` * ``CV_TM_CCORR`` @@ -124,45 +188,11 @@ Computes a proximity map for a raster template and an image where the template i -gpu::Canny -------------------- -Finds edges in an image using the [Canny86]_ algorithm. - -.. ocv:function:: void gpu::Canny(const GpuMat& image, GpuMat& edges, double low_thresh, double high_thresh, int apperture_size = 3, bool L2gradient = false) - -.. ocv:function:: void gpu::Canny(const GpuMat& image, CannyBuf& buf, GpuMat& edges, double low_thresh, double high_thresh, int apperture_size = 3, bool L2gradient = false) - -.. ocv:function:: void gpu::Canny(const GpuMat& dx, const GpuMat& dy, GpuMat& edges, double low_thresh, double high_thresh, bool L2gradient = false) - -.. ocv:function:: void gpu::Canny(const GpuMat& dx, const GpuMat& dy, CannyBuf& buf, GpuMat& edges, double low_thresh, double high_thresh, bool L2gradient = false) - - :param image: Single-channel 8-bit input image. - - :param dx: First derivative of image in the vertical direction. Support only ``CV_32S`` type. - - :param dy: First derivative of image in the horizontal direction. Support only ``CV_32S`` type. - - :param edges: Output edge map. It has the same size and type as ``image`` . - - :param low_thresh: First threshold for the hysteresis procedure. - - :param high_thresh: Second threshold for the hysteresis procedure. - - :param apperture_size: Aperture size for the :ocv:func:`Sobel` operator. - - :param L2gradient: Flag indicating whether a more accurate :math:`L_2` norm :math:`=\sqrt{(dI/dx)^2 + (dI/dy)^2}` should be used to compute the image gradient magnitude ( ``L2gradient=true`` ), or a faster default :math:`L_1` norm :math:`=|dI/dx|+|dI/dy|` is enough ( ``L2gradient=false`` ). - - :param buf: Optional buffer to avoid extra memory allocations (for many calls with the same sizes). - -.. seealso:: :ocv:func:`Canny` - - - gpu::bilateralFilter -------------------- Performs bilateral filtering of passed image -.. ocv:function:: void gpu::bilateralFilter( const GpuMat& src, GpuMat& dst, int kernel_size, float sigma_color, float sigma_spatial, int borderMode=BORDER_DEFAULT, Stream& stream=Stream::Null() ) +.. ocv:function:: void gpu::bilateralFilter(InputArray src, OutputArray dst, int kernel_size, float sigma_color, float sigma_spatial, int borderMode=BORDER_DEFAULT, Stream& stream=Stream::Null()) :param src: Source image. Supports only (channles != 2 && depth() != CV_8S && depth() != CV_32S && depth() != CV_64F). @@ -178,9 +208,7 @@ Performs bilateral filtering of passed image :param stream: Stream for the asynchronous version. -.. seealso:: - - :ocv:func:`bilateralFilter` +.. seealso:: :ocv:func:`bilateralFilter` @@ -188,7 +216,7 @@ gpu::blendLinear ------------------- Performs linear blending of two images. -.. ocv:function:: void gpu::blendLinear(const GpuMat& img1, const GpuMat& img2, const GpuMat& weights1, const GpuMat& weights2, GpuMat& result, Stream& stream = Stream::Null()) +.. ocv:function:: void gpu::blendLinear(InputArray img1, InputArray img2, InputArray weights1, InputArray weights2, OutputArray result, Stream& stream = Stream::Null()) :param img1: First image. Supports only ``CV_8U`` and ``CV_32F`` depth. From 1d79e1313318f6c5acf013ea9373a7e1330b64a4 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Mon, 6 May 2013 15:21:11 +0400 Subject: [PATCH 13/17] removed dependecy from gpuarithm --- modules/gpuimgproc/test/test_histogram.cpp | 6 +++--- modules/gpuimgproc/test/test_precomp.hpp | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/gpuimgproc/test/test_histogram.cpp b/modules/gpuimgproc/test/test_histogram.cpp index c3d17d2a1f..8a5b22a959 100644 --- a/modules/gpuimgproc/test/test_histogram.cpp +++ b/modules/gpuimgproc/test/test_histogram.cpp @@ -72,11 +72,11 @@ GPU_TEST_P(HistEven, Accuracy) int hbins = 30; float hranges[] = {0.0f, 180.0f}; - std::vector srcs; - cv::gpu::split(loadMat(hsv), srcs); + std::vector srcs; + cv::split(hsv, srcs); cv::gpu::GpuMat hist; - cv::gpu::histEven(srcs[0], hist, hbins, (int)hranges[0], (int)hranges[1]); + cv::gpu::histEven(loadMat(srcs[0]), hist, hbins, (int)hranges[0], (int)hranges[1]); cv::MatND histnd; int histSize[] = {hbins}; diff --git a/modules/gpuimgproc/test/test_precomp.hpp b/modules/gpuimgproc/test/test_precomp.hpp index 4196aa9fe1..71ba4020ce 100644 --- a/modules/gpuimgproc/test/test_precomp.hpp +++ b/modules/gpuimgproc/test/test_precomp.hpp @@ -55,7 +55,6 @@ #include "opencv2/ts/gpu_test.hpp" #include "opencv2/gpuimgproc.hpp" -#include "opencv2/gpuarithm.hpp" #include "opencv2/imgproc.hpp" #endif From f614e354439ffd797f0f20995348ee98efcaf7a6 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Mon, 6 May 2013 15:21:31 +0400 Subject: [PATCH 14/17] split hough sources --- .../gpuimgproc/src/cuda/build_point_list.cu | 138 ++ .../gpuimgproc/src/cuda/generalized_hough.cu | 1085 +++++++++++ modules/gpuimgproc/src/cuda/hough.cu | 1710 ----------------- modules/gpuimgproc/src/cuda/hough_circles.cu | 255 +++ modules/gpuimgproc/src/cuda/hough_lines.cu | 212 ++ modules/gpuimgproc/src/cuda/hough_segments.cu | 249 +++ .../src/{hough.cpp => generalized_hough.cpp} | 705 +------ modules/gpuimgproc/src/hough_circles.cpp | 297 +++ modules/gpuimgproc/src/hough_lines.cpp | 202 ++ modules/gpuimgproc/src/hough_segments.cpp | 183 ++ modules/gpuimgproc/src/precomp.hpp | 1 + 11 files changed, 2714 insertions(+), 2323 deletions(-) create mode 100644 modules/gpuimgproc/src/cuda/build_point_list.cu create mode 100644 modules/gpuimgproc/src/cuda/generalized_hough.cu delete mode 100644 modules/gpuimgproc/src/cuda/hough.cu create mode 100644 modules/gpuimgproc/src/cuda/hough_circles.cu create mode 100644 modules/gpuimgproc/src/cuda/hough_lines.cu create mode 100644 modules/gpuimgproc/src/cuda/hough_segments.cu rename modules/gpuimgproc/src/{hough.cpp => generalized_hough.cpp} (58%) create mode 100644 modules/gpuimgproc/src/hough_circles.cpp create mode 100644 modules/gpuimgproc/src/hough_lines.cpp create mode 100644 modules/gpuimgproc/src/hough_segments.cpp diff --git a/modules/gpuimgproc/src/cuda/build_point_list.cu b/modules/gpuimgproc/src/cuda/build_point_list.cu new file mode 100644 index 0000000000..c5f2b23f6f --- /dev/null +++ b/modules/gpuimgproc/src/cuda/build_point_list.cu @@ -0,0 +1,138 @@ +/*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*/ + +#if !defined CUDA_DISABLER + +#include "opencv2/core/cuda/common.hpp" +#include "opencv2/core/cuda/emulation.hpp" + +namespace cv { namespace gpu { namespace cudev +{ + namespace hough + { + __device__ int g_counter; + + template + __global__ void buildPointList(const PtrStepSzb src, unsigned int* list) + { + __shared__ unsigned int s_queues[4][32 * PIXELS_PER_THREAD]; + __shared__ int s_qsize[4]; + __shared__ int s_globStart[4]; + + const int x = blockIdx.x * blockDim.x * PIXELS_PER_THREAD + threadIdx.x; + const int y = blockIdx.y * blockDim.y + threadIdx.y; + + if (threadIdx.x == 0) + s_qsize[threadIdx.y] = 0; + __syncthreads(); + + if (y < src.rows) + { + // fill the queue + const uchar* srcRow = src.ptr(y); + for (int i = 0, xx = x; i < PIXELS_PER_THREAD && xx < src.cols; ++i, xx += blockDim.x) + { + if (srcRow[xx]) + { + const unsigned int val = (y << 16) | xx; + const int qidx = Emulation::smem::atomicAdd(&s_qsize[threadIdx.y], 1); + s_queues[threadIdx.y][qidx] = val; + } + } + } + + __syncthreads(); + + // let one thread reserve the space required in the global list + if (threadIdx.x == 0 && threadIdx.y == 0) + { + // find how many items are stored in each list + int totalSize = 0; + for (int i = 0; i < blockDim.y; ++i) + { + s_globStart[i] = totalSize; + totalSize += s_qsize[i]; + } + + // calculate the offset in the global list + const int globalOffset = atomicAdd(&g_counter, totalSize); + for (int i = 0; i < blockDim.y; ++i) + s_globStart[i] += globalOffset; + } + + __syncthreads(); + + // copy local queues to global queue + const int qsize = s_qsize[threadIdx.y]; + int gidx = s_globStart[threadIdx.y] + threadIdx.x; + for(int i = threadIdx.x; i < qsize; i += blockDim.x, gidx += blockDim.x) + list[gidx] = s_queues[threadIdx.y][i]; + } + + int buildPointList_gpu(PtrStepSzb src, unsigned int* list) + { + const int PIXELS_PER_THREAD = 16; + + void* counterPtr; + cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); + + cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); + + const dim3 block(32, 4); + const dim3 grid(divUp(src.cols, block.x * PIXELS_PER_THREAD), divUp(src.rows, block.y)); + + cudaSafeCall( cudaFuncSetCacheConfig(buildPointList, cudaFuncCachePreferShared) ); + + buildPointList<<>>(src, list); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + + int totalCount; + cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); + + return totalCount; + } + } +}}} + +#endif /* CUDA_DISABLER */ diff --git a/modules/gpuimgproc/src/cuda/generalized_hough.cu b/modules/gpuimgproc/src/cuda/generalized_hough.cu new file mode 100644 index 0000000000..9ae5a595bb --- /dev/null +++ b/modules/gpuimgproc/src/cuda/generalized_hough.cu @@ -0,0 +1,1085 @@ +/*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*/ + +#if !defined CUDA_DISABLER + +#include +#include + +#include "opencv2/core/cuda/common.hpp" +#include "opencv2/core/cuda/emulation.hpp" +#include "opencv2/core/cuda/vec_math.hpp" + +#include "opencv2/opencv_modules.hpp" + +#ifdef HAVE_OPENCV_GPUARITHM + +namespace cv { namespace gpu { namespace cudev +{ + namespace ght + { + __device__ int g_counter; + + template + __global__ void buildEdgePointList(const PtrStepSzb edges, const PtrStep dx, const PtrStep dy, + unsigned int* coordList, float* thetaList) + { + __shared__ unsigned int s_coordLists[4][32 * PIXELS_PER_THREAD]; + __shared__ float s_thetaLists[4][32 * PIXELS_PER_THREAD]; + __shared__ int s_sizes[4]; + __shared__ int s_globStart[4]; + + const int x = blockIdx.x * blockDim.x * PIXELS_PER_THREAD + threadIdx.x; + const int y = blockIdx.y * blockDim.y + threadIdx.y; + + if (threadIdx.x == 0) + s_sizes[threadIdx.y] = 0; + __syncthreads(); + + if (y < edges.rows) + { + // fill the queue + const uchar* edgesRow = edges.ptr(y); + const T* dxRow = dx.ptr(y); + const T* dyRow = dy.ptr(y); + + for (int i = 0, xx = x; i < PIXELS_PER_THREAD && xx < edges.cols; ++i, xx += blockDim.x) + { + const T dxVal = dxRow[xx]; + const T dyVal = dyRow[xx]; + + if (edgesRow[xx] && (dxVal != 0 || dyVal != 0)) + { + const unsigned int coord = (y << 16) | xx; + + float theta = ::atan2f(dyVal, dxVal); + if (theta < 0) + theta += 2.0f * CV_PI_F; + + const int qidx = Emulation::smem::atomicAdd(&s_sizes[threadIdx.y], 1); + + s_coordLists[threadIdx.y][qidx] = coord; + s_thetaLists[threadIdx.y][qidx] = theta; + } + } + } + + __syncthreads(); + + // let one thread reserve the space required in the global list + if (threadIdx.x == 0 && threadIdx.y == 0) + { + // find how many items are stored in each list + int totalSize = 0; + for (int i = 0; i < blockDim.y; ++i) + { + s_globStart[i] = totalSize; + totalSize += s_sizes[i]; + } + + // calculate the offset in the global list + const int globalOffset = atomicAdd(&g_counter, totalSize); + for (int i = 0; i < blockDim.y; ++i) + s_globStart[i] += globalOffset; + } + + __syncthreads(); + + // copy local queues to global queue + const int qsize = s_sizes[threadIdx.y]; + int gidx = s_globStart[threadIdx.y] + threadIdx.x; + for(int i = threadIdx.x; i < qsize; i += blockDim.x, gidx += blockDim.x) + { + coordList[gidx] = s_coordLists[threadIdx.y][i]; + thetaList[gidx] = s_thetaLists[threadIdx.y][i]; + } + } + + template + int buildEdgePointList_gpu(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList) + { + const int PIXELS_PER_THREAD = 8; + + void* counterPtr; + cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); + + cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); + + const dim3 block(32, 4); + const dim3 grid(divUp(edges.cols, block.x * PIXELS_PER_THREAD), divUp(edges.rows, block.y)); + + cudaSafeCall( cudaFuncSetCacheConfig(buildEdgePointList, cudaFuncCachePreferShared) ); + + buildEdgePointList<<>>(edges, (PtrStepSz) dx, (PtrStepSz) dy, coordList, thetaList); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + + int totalCount; + cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); + + return totalCount; + } + + template int buildEdgePointList_gpu(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList); + template int buildEdgePointList_gpu(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList); + template int buildEdgePointList_gpu(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList); + + __global__ void buildRTable(const unsigned int* coordList, const float* thetaList, const int pointsCount, + PtrStep r_table, int* r_sizes, int maxSize, + const short2 templCenter, const float thetaScale) + { + const int tid = blockIdx.x * blockDim.x + threadIdx.x; + + if (tid >= pointsCount) + return; + + const unsigned int coord = coordList[tid]; + short2 p; + p.x = (coord & 0xFFFF); + p.y = (coord >> 16) & 0xFFFF; + + const float theta = thetaList[tid]; + const int n = __float2int_rn(theta * thetaScale); + + const int ind = ::atomicAdd(r_sizes + n, 1); + if (ind < maxSize) + r_table(n, ind) = p - templCenter; + } + + void buildRTable_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, + PtrStepSz r_table, int* r_sizes, + short2 templCenter, int levels) + { + const dim3 block(256); + const dim3 grid(divUp(pointsCount, block.x)); + + const float thetaScale = levels / (2.0f * CV_PI_F); + + buildRTable<<>>(coordList, thetaList, pointsCount, r_table, r_sizes, r_table.cols, templCenter, thetaScale); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + } + + //////////////////////////////////////////////////////////////////////// + // Ballard_Pos + + __global__ void Ballard_Pos_calcHist(const unsigned int* coordList, const float* thetaList, const int pointsCount, + const PtrStep r_table, const int* r_sizes, + PtrStepSzi hist, + const float idp, const float thetaScale) + { + const int tid = blockIdx.x * blockDim.x + threadIdx.x; + + if (tid >= pointsCount) + return; + + const unsigned int coord = coordList[tid]; + short2 p; + p.x = (coord & 0xFFFF); + p.y = (coord >> 16) & 0xFFFF; + + const float theta = thetaList[tid]; + const int n = __float2int_rn(theta * thetaScale); + + const short2* r_row = r_table.ptr(n); + const int r_row_size = r_sizes[n]; + + for (int j = 0; j < r_row_size; ++j) + { + short2 c = p - r_row[j]; + + c.x = __float2int_rn(c.x * idp); + c.y = __float2int_rn(c.y * idp); + + if (c.x >= 0 && c.x < hist.cols - 2 && c.y >= 0 && c.y < hist.rows - 2) + ::atomicAdd(hist.ptr(c.y + 1) + c.x + 1, 1); + } + } + + void Ballard_Pos_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, + PtrStepSz r_table, const int* r_sizes, + PtrStepSzi hist, + float dp, int levels) + { + const dim3 block(256); + const dim3 grid(divUp(pointsCount, block.x)); + + const float idp = 1.0f / dp; + const float thetaScale = levels / (2.0f * CV_PI_F); + + Ballard_Pos_calcHist<<>>(coordList, thetaList, pointsCount, r_table, r_sizes, hist, idp, thetaScale); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + } + + __global__ void Ballard_Pos_findPosInHist(const PtrStepSzi hist, float4* out, int3* votes, + const int maxSize, const float dp, const int threshold) + { + const int x = blockIdx.x * blockDim.x + threadIdx.x; + const int y = blockIdx.y * blockDim.y + threadIdx.y; + + if (x >= hist.cols - 2 || y >= hist.rows - 2) + return; + + const int curVotes = hist(y + 1, x + 1); + + if (curVotes > threshold && + curVotes > hist(y + 1, x) && + curVotes >= hist(y + 1, x + 2) && + curVotes > hist(y, x + 1) && + curVotes >= hist(y + 2, x + 1)) + { + const int ind = ::atomicAdd(&g_counter, 1); + + if (ind < maxSize) + { + out[ind] = make_float4(x * dp, y * dp, 1.0f, 0.0f); + votes[ind] = make_int3(curVotes, 0, 0); + } + } + } + + int Ballard_Pos_findPosInHist_gpu(PtrStepSzi hist, float4* out, int3* votes, int maxSize, float dp, int threshold) + { + void* counterPtr; + cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); + + cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); + + const dim3 block(32, 8); + const dim3 grid(divUp(hist.cols - 2, block.x), divUp(hist.rows - 2, block.y)); + + cudaSafeCall( cudaFuncSetCacheConfig(Ballard_Pos_findPosInHist, cudaFuncCachePreferL1) ); + + Ballard_Pos_findPosInHist<<>>(hist, out, votes, maxSize, dp, threshold); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + + int totalCount; + cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); + + totalCount = ::min(totalCount, maxSize); + + return totalCount; + } + + //////////////////////////////////////////////////////////////////////// + // Ballard_PosScale + + __global__ void Ballard_PosScale_calcHist(const unsigned int* coordList, const float* thetaList, + PtrStep r_table, const int* r_sizes, + PtrStepi hist, const int rows, const int cols, + const float minScale, const float scaleStep, const int scaleRange, + const float idp, const float thetaScale) + { + const unsigned int coord = coordList[blockIdx.x]; + float2 p; + p.x = (coord & 0xFFFF); + p.y = (coord >> 16) & 0xFFFF; + + const float theta = thetaList[blockIdx.x]; + const int n = __float2int_rn(theta * thetaScale); + + const short2* r_row = r_table.ptr(n); + const int r_row_size = r_sizes[n]; + + for (int j = 0; j < r_row_size; ++j) + { + const float2 d = saturate_cast(r_row[j]); + + for (int s = threadIdx.x; s < scaleRange; s += blockDim.x) + { + const float scale = minScale + s * scaleStep; + + float2 c = p - scale * d; + + c.x *= idp; + c.y *= idp; + + if (c.x >= 0 && c.x < cols && c.y >= 0 && c.y < rows) + ::atomicAdd(hist.ptr((s + 1) * (rows + 2) + __float2int_rn(c.y + 1)) + __float2int_rn(c.x + 1), 1); + } + } + } + + void Ballard_PosScale_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, + PtrStepSz r_table, const int* r_sizes, + PtrStepi hist, int rows, int cols, + float minScale, float scaleStep, int scaleRange, + float dp, int levels) + { + const dim3 block(256); + const dim3 grid(pointsCount); + + const float idp = 1.0f / dp; + const float thetaScale = levels / (2.0f * CV_PI_F); + + Ballard_PosScale_calcHist<<>>(coordList, thetaList, + r_table, r_sizes, + hist, rows, cols, + minScale, scaleStep, scaleRange, + idp, thetaScale); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + } + + __global__ void Ballard_PosScale_findPosInHist(const PtrStepi hist, const int rows, const int cols, const int scaleRange, + float4* out, int3* votes, const int maxSize, + const float minScale, const float scaleStep, const float dp, const int threshold) + { + const int x = blockIdx.x * blockDim.x + threadIdx.x; + const int y = blockIdx.y * blockDim.y + threadIdx.y; + + if (x >= cols || y >= rows) + return; + + for (int s = 0; s < scaleRange; ++s) + { + const float scale = minScale + s * scaleStep; + + const int prevScaleIdx = (s) * (rows + 2); + const int curScaleIdx = (s + 1) * (rows + 2); + const int nextScaleIdx = (s + 2) * (rows + 2); + + const int curVotes = hist(curScaleIdx + y + 1, x + 1); + + if (curVotes > threshold && + curVotes > hist(curScaleIdx + y + 1, x) && + curVotes >= hist(curScaleIdx + y + 1, x + 2) && + curVotes > hist(curScaleIdx + y, x + 1) && + curVotes >= hist(curScaleIdx + y + 2, x + 1) && + curVotes > hist(prevScaleIdx + y + 1, x + 1) && + curVotes >= hist(nextScaleIdx + y + 1, x + 1)) + { + const int ind = ::atomicAdd(&g_counter, 1); + + if (ind < maxSize) + { + out[ind] = make_float4(x * dp, y * dp, scale, 0.0f); + votes[ind] = make_int3(curVotes, curVotes, 0); + } + } + } + } + + int Ballard_PosScale_findPosInHist_gpu(PtrStepi hist, int rows, int cols, int scaleRange, float4* out, int3* votes, int maxSize, + float minScale, float scaleStep, float dp, int threshold) + { + void* counterPtr; + cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); + + cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); + + const dim3 block(32, 8); + const dim3 grid(divUp(cols, block.x), divUp(rows, block.y)); + + cudaSafeCall( cudaFuncSetCacheConfig(Ballard_PosScale_findPosInHist, cudaFuncCachePreferL1) ); + + Ballard_PosScale_findPosInHist<<>>(hist, rows, cols, scaleRange, out, votes, + maxSize, minScale, scaleStep, dp, threshold); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + + int totalCount; + cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); + + totalCount = ::min(totalCount, maxSize); + + return totalCount; + } + + //////////////////////////////////////////////////////////////////////// + // Ballard_PosRotation + + __global__ void Ballard_PosRotation_calcHist(const unsigned int* coordList, const float* thetaList, + PtrStep r_table, const int* r_sizes, + PtrStepi hist, const int rows, const int cols, + const float minAngle, const float angleStep, const int angleRange, + const float idp, const float thetaScale) + { + const unsigned int coord = coordList[blockIdx.x]; + float2 p; + p.x = (coord & 0xFFFF); + p.y = (coord >> 16) & 0xFFFF; + + const float thetaVal = thetaList[blockIdx.x]; + + for (int a = threadIdx.x; a < angleRange; a += blockDim.x) + { + const float angle = (minAngle + a * angleStep) * (CV_PI_F / 180.0f); + float sinA, cosA; + sincosf(angle, &sinA, &cosA); + + float theta = thetaVal - angle; + if (theta < 0) + theta += 2.0f * CV_PI_F; + + const int n = __float2int_rn(theta * thetaScale); + + const short2* r_row = r_table.ptr(n); + const int r_row_size = r_sizes[n]; + + for (int j = 0; j < r_row_size; ++j) + { + const float2 d = saturate_cast(r_row[j]); + + const float2 dr = make_float2(d.x * cosA - d.y * sinA, d.x * sinA + d.y * cosA); + + float2 c = make_float2(p.x - dr.x, p.y - dr.y); + c.x *= idp; + c.y *= idp; + + if (c.x >= 0 && c.x < cols && c.y >= 0 && c.y < rows) + ::atomicAdd(hist.ptr((a + 1) * (rows + 2) + __float2int_rn(c.y + 1)) + __float2int_rn(c.x + 1), 1); + } + } + } + + void Ballard_PosRotation_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, + PtrStepSz r_table, const int* r_sizes, + PtrStepi hist, int rows, int cols, + float minAngle, float angleStep, int angleRange, + float dp, int levels) + { + const dim3 block(256); + const dim3 grid(pointsCount); + + const float idp = 1.0f / dp; + const float thetaScale = levels / (2.0f * CV_PI_F); + + Ballard_PosRotation_calcHist<<>>(coordList, thetaList, + r_table, r_sizes, + hist, rows, cols, + minAngle, angleStep, angleRange, + idp, thetaScale); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + } + + __global__ void Ballard_PosRotation_findPosInHist(const PtrStepi hist, const int rows, const int cols, const int angleRange, + float4* out, int3* votes, const int maxSize, + const float minAngle, const float angleStep, const float dp, const int threshold) + { + const int x = blockIdx.x * blockDim.x + threadIdx.x; + const int y = blockIdx.y * blockDim.y + threadIdx.y; + + if (x >= cols || y >= rows) + return; + + for (int a = 0; a < angleRange; ++a) + { + const float angle = minAngle + a * angleStep; + + const int prevAngleIdx = (a) * (rows + 2); + const int curAngleIdx = (a + 1) * (rows + 2); + const int nextAngleIdx = (a + 2) * (rows + 2); + + const int curVotes = hist(curAngleIdx + y + 1, x + 1); + + if (curVotes > threshold && + curVotes > hist(curAngleIdx + y + 1, x) && + curVotes >= hist(curAngleIdx + y + 1, x + 2) && + curVotes > hist(curAngleIdx + y, x + 1) && + curVotes >= hist(curAngleIdx + y + 2, x + 1) && + curVotes > hist(prevAngleIdx + y + 1, x + 1) && + curVotes >= hist(nextAngleIdx + y + 1, x + 1)) + { + const int ind = ::atomicAdd(&g_counter, 1); + + if (ind < maxSize) + { + out[ind] = make_float4(x * dp, y * dp, 1.0f, angle); + votes[ind] = make_int3(curVotes, 0, curVotes); + } + } + } + } + + int Ballard_PosRotation_findPosInHist_gpu(PtrStepi hist, int rows, int cols, int angleRange, float4* out, int3* votes, int maxSize, + float minAngle, float angleStep, float dp, int threshold) + { + void* counterPtr; + cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); + + cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); + + const dim3 block(32, 8); + const dim3 grid(divUp(cols, block.x), divUp(rows, block.y)); + + cudaSafeCall( cudaFuncSetCacheConfig(Ballard_PosRotation_findPosInHist, cudaFuncCachePreferL1) ); + + Ballard_PosRotation_findPosInHist<<>>(hist, rows, cols, angleRange, out, votes, + maxSize, minAngle, angleStep, dp, threshold); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + + int totalCount; + cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); + + totalCount = ::min(totalCount, maxSize); + + return totalCount; + } + + //////////////////////////////////////////////////////////////////////// + // Guil_Full + + struct FeatureTable + { + uchar* p1_pos_data; + size_t p1_pos_step; + + uchar* p1_theta_data; + size_t p1_theta_step; + + uchar* p2_pos_data; + size_t p2_pos_step; + + uchar* d12_data; + size_t d12_step; + + uchar* r1_data; + size_t r1_step; + + uchar* r2_data; + size_t r2_step; + }; + + __constant__ FeatureTable c_templFeatures; + __constant__ FeatureTable c_imageFeatures; + + void Guil_Full_setTemplFeatures(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2) + { + FeatureTable tbl; + + tbl.p1_pos_data = p1_pos.data; + tbl.p1_pos_step = p1_pos.step; + + tbl.p1_theta_data = p1_theta.data; + tbl.p1_theta_step = p1_theta.step; + + tbl.p2_pos_data = p2_pos.data; + tbl.p2_pos_step = p2_pos.step; + + tbl.d12_data = d12.data; + tbl.d12_step = d12.step; + + tbl.r1_data = r1.data; + tbl.r1_step = r1.step; + + tbl.r2_data = r2.data; + tbl.r2_step = r2.step; + + cudaSafeCall( cudaMemcpyToSymbol(c_templFeatures, &tbl, sizeof(FeatureTable)) ); + } + void Guil_Full_setImageFeatures(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2) + { + FeatureTable tbl; + + tbl.p1_pos_data = p1_pos.data; + tbl.p1_pos_step = p1_pos.step; + + tbl.p1_theta_data = p1_theta.data; + tbl.p1_theta_step = p1_theta.step; + + tbl.p2_pos_data = p2_pos.data; + tbl.p2_pos_step = p2_pos.step; + + tbl.d12_data = d12.data; + tbl.d12_step = d12.step; + + tbl.r1_data = r1.data; + tbl.r1_step = r1.step; + + tbl.r2_data = r2.data; + tbl.r2_step = r2.step; + + cudaSafeCall( cudaMemcpyToSymbol(c_imageFeatures, &tbl, sizeof(FeatureTable)) ); + } + + struct TemplFeatureTable + { + static __device__ float2* p1_pos(int n) + { + return (float2*)(c_templFeatures.p1_pos_data + n * c_templFeatures.p1_pos_step); + } + static __device__ float* p1_theta(int n) + { + return (float*)(c_templFeatures.p1_theta_data + n * c_templFeatures.p1_theta_step); + } + static __device__ float2* p2_pos(int n) + { + return (float2*)(c_templFeatures.p2_pos_data + n * c_templFeatures.p2_pos_step); + } + + static __device__ float* d12(int n) + { + return (float*)(c_templFeatures.d12_data + n * c_templFeatures.d12_step); + } + + static __device__ float2* r1(int n) + { + return (float2*)(c_templFeatures.r1_data + n * c_templFeatures.r1_step); + } + static __device__ float2* r2(int n) + { + return (float2*)(c_templFeatures.r2_data + n * c_templFeatures.r2_step); + } + }; + struct ImageFeatureTable + { + static __device__ float2* p1_pos(int n) + { + return (float2*)(c_imageFeatures.p1_pos_data + n * c_imageFeatures.p1_pos_step); + } + static __device__ float* p1_theta(int n) + { + return (float*)(c_imageFeatures.p1_theta_data + n * c_imageFeatures.p1_theta_step); + } + static __device__ float2* p2_pos(int n) + { + return (float2*)(c_imageFeatures.p2_pos_data + n * c_imageFeatures.p2_pos_step); + } + + static __device__ float* d12(int n) + { + return (float*)(c_imageFeatures.d12_data + n * c_imageFeatures.d12_step); + } + + static __device__ float2* r1(int n) + { + return (float2*)(c_imageFeatures.r1_data + n * c_imageFeatures.r1_step); + } + static __device__ float2* r2(int n) + { + return (float2*)(c_imageFeatures.r2_data + n * c_imageFeatures.r2_step); + } + }; + + __device__ float clampAngle(float a) + { + float res = a; + + while (res > 2.0f * CV_PI_F) + res -= 2.0f * CV_PI_F; + while (res < 0.0f) + res += 2.0f * CV_PI_F; + + return res; + } + + __device__ bool angleEq(float a, float b, float eps) + { + return (::fabs(clampAngle(a - b)) <= eps); + } + + template + __global__ void Guil_Full_buildFeatureList(const unsigned int* coordList, const float* thetaList, const int pointsCount, + int* sizes, const int maxSize, + const float xi, const float angleEpsilon, const float alphaScale, + const float2 center, const float maxDist) + { + const float p1_theta = thetaList[blockIdx.x]; + const unsigned int coord1 = coordList[blockIdx.x]; + float2 p1_pos; + p1_pos.x = (coord1 & 0xFFFF); + p1_pos.y = (coord1 >> 16) & 0xFFFF; + + for (int i = threadIdx.x; i < pointsCount; i += blockDim.x) + { + const float p2_theta = thetaList[i]; + const unsigned int coord2 = coordList[i]; + float2 p2_pos; + p2_pos.x = (coord2 & 0xFFFF); + p2_pos.y = (coord2 >> 16) & 0xFFFF; + + if (angleEq(p1_theta - p2_theta, xi, angleEpsilon)) + { + const float2 d = p1_pos - p2_pos; + + float alpha12 = clampAngle(::atan2(d.y, d.x) - p1_theta); + float d12 = ::sqrtf(d.x * d.x + d.y * d.y); + + if (d12 > maxDist) + continue; + + float2 r1 = p1_pos - center; + float2 r2 = p2_pos - center; + + const int n = __float2int_rn(alpha12 * alphaScale); + + const int ind = ::atomicAdd(sizes + n, 1); + + if (ind < maxSize) + { + if (!isTempl) + { + FT::p1_pos(n)[ind] = p1_pos; + FT::p2_pos(n)[ind] = p2_pos; + } + + FT::p1_theta(n)[ind] = p1_theta; + + FT::d12(n)[ind] = d12; + + if (isTempl) + { + FT::r1(n)[ind] = r1; + FT::r2(n)[ind] = r2; + } + } + } + } + } + + template + void Guil_Full_buildFeatureList_caller(const unsigned int* coordList, const float* thetaList, int pointsCount, + int* sizes, int maxSize, + float xi, float angleEpsilon, int levels, + float2 center, float maxDist) + { + const dim3 block(256); + const dim3 grid(pointsCount); + + const float alphaScale = levels / (2.0f * CV_PI_F); + + Guil_Full_buildFeatureList<<>>(coordList, thetaList, pointsCount, + sizes, maxSize, + xi * (CV_PI_F / 180.0f), angleEpsilon * (CV_PI_F / 180.0f), alphaScale, + center, maxDist); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + + thrust::device_ptr sizesPtr(sizes); + thrust::transform(sizesPtr, sizesPtr + levels + 1, sizesPtr, cudev::bind2nd(cudev::minimum(), maxSize)); + } + + void Guil_Full_buildTemplFeatureList_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, + int* sizes, int maxSize, + float xi, float angleEpsilon, int levels, + float2 center, float maxDist) + { + Guil_Full_buildFeatureList_caller(coordList, thetaList, pointsCount, + sizes, maxSize, + xi, angleEpsilon, levels, + center, maxDist); + } + void Guil_Full_buildImageFeatureList_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, + int* sizes, int maxSize, + float xi, float angleEpsilon, int levels, + float2 center, float maxDist) + { + Guil_Full_buildFeatureList_caller(coordList, thetaList, pointsCount, + sizes, maxSize, + xi, angleEpsilon, levels, + center, maxDist); + } + + __global__ void Guil_Full_calcOHist(const int* templSizes, const int* imageSizes, int* OHist, + const float minAngle, const float maxAngle, const float iAngleStep, const int angleRange) + { + extern __shared__ int s_OHist[]; + for (int i = threadIdx.x; i <= angleRange; i += blockDim.x) + s_OHist[i] = 0; + __syncthreads(); + + const int tIdx = blockIdx.x; + const int level = blockIdx.y; + + const int tSize = templSizes[level]; + + if (tIdx < tSize) + { + const int imSize = imageSizes[level]; + + const float t_p1_theta = TemplFeatureTable::p1_theta(level)[tIdx]; + + for (int i = threadIdx.x; i < imSize; i += blockDim.x) + { + const float im_p1_theta = ImageFeatureTable::p1_theta(level)[i]; + + const float angle = clampAngle(im_p1_theta - t_p1_theta); + + if (angle >= minAngle && angle <= maxAngle) + { + const int n = __float2int_rn((angle - minAngle) * iAngleStep); + Emulation::smem::atomicAdd(&s_OHist[n], 1); + } + } + } + __syncthreads(); + + for (int i = threadIdx.x; i <= angleRange; i += blockDim.x) + ::atomicAdd(OHist + i, s_OHist[i]); + } + + void Guil_Full_calcOHist_gpu(const int* templSizes, const int* imageSizes, int* OHist, + float minAngle, float maxAngle, float angleStep, int angleRange, + int levels, int tMaxSize) + { + const dim3 block(256); + const dim3 grid(tMaxSize, levels + 1); + + minAngle *= (CV_PI_F / 180.0f); + maxAngle *= (CV_PI_F / 180.0f); + angleStep *= (CV_PI_F / 180.0f); + + const size_t smemSize = (angleRange + 1) * sizeof(float); + + Guil_Full_calcOHist<<>>(templSizes, imageSizes, OHist, + minAngle, maxAngle, 1.0f / angleStep, angleRange); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + } + + __global__ void Guil_Full_calcSHist(const int* templSizes, const int* imageSizes, int* SHist, + const float angle, const float angleEpsilon, + const float minScale, const float maxScale, const float iScaleStep, const int scaleRange) + { + extern __shared__ int s_SHist[]; + for (int i = threadIdx.x; i <= scaleRange; i += blockDim.x) + s_SHist[i] = 0; + __syncthreads(); + + const int tIdx = blockIdx.x; + const int level = blockIdx.y; + + const int tSize = templSizes[level]; + + if (tIdx < tSize) + { + const int imSize = imageSizes[level]; + + const float t_p1_theta = TemplFeatureTable::p1_theta(level)[tIdx] + angle; + const float t_d12 = TemplFeatureTable::d12(level)[tIdx] + angle; + + for (int i = threadIdx.x; i < imSize; i += blockDim.x) + { + const float im_p1_theta = ImageFeatureTable::p1_theta(level)[i]; + const float im_d12 = ImageFeatureTable::d12(level)[i]; + + if (angleEq(im_p1_theta, t_p1_theta, angleEpsilon)) + { + const float scale = im_d12 / t_d12; + + if (scale >= minScale && scale <= maxScale) + { + const int s = __float2int_rn((scale - minScale) * iScaleStep); + Emulation::smem::atomicAdd(&s_SHist[s], 1); + } + } + } + } + __syncthreads(); + + for (int i = threadIdx.x; i <= scaleRange; i += blockDim.x) + ::atomicAdd(SHist + i, s_SHist[i]); + } + + void Guil_Full_calcSHist_gpu(const int* templSizes, const int* imageSizes, int* SHist, + float angle, float angleEpsilon, + float minScale, float maxScale, float iScaleStep, int scaleRange, + int levels, int tMaxSize) + { + const dim3 block(256); + const dim3 grid(tMaxSize, levels + 1); + + angle *= (CV_PI_F / 180.0f); + angleEpsilon *= (CV_PI_F / 180.0f); + + const size_t smemSize = (scaleRange + 1) * sizeof(float); + + Guil_Full_calcSHist<<>>(templSizes, imageSizes, SHist, + angle, angleEpsilon, + minScale, maxScale, iScaleStep, scaleRange); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + } + + __global__ void Guil_Full_calcPHist(const int* templSizes, const int* imageSizes, PtrStepSzi PHist, + const float angle, const float sinVal, const float cosVal, const float angleEpsilon, const float scale, + const float idp) + { + const int tIdx = blockIdx.x; + const int level = blockIdx.y; + + const int tSize = templSizes[level]; + + if (tIdx < tSize) + { + const int imSize = imageSizes[level]; + + const float t_p1_theta = TemplFeatureTable::p1_theta(level)[tIdx] + angle; + + float2 r1 = TemplFeatureTable::r1(level)[tIdx]; + float2 r2 = TemplFeatureTable::r2(level)[tIdx]; + + r1 = r1 * scale; + r2 = r2 * scale; + + r1 = make_float2(cosVal * r1.x - sinVal * r1.y, sinVal * r1.x + cosVal * r1.y); + r2 = make_float2(cosVal * r2.x - sinVal * r2.y, sinVal * r2.x + cosVal * r2.y); + + for (int i = threadIdx.x; i < imSize; i += blockDim.x) + { + const float im_p1_theta = ImageFeatureTable::p1_theta(level)[i]; + + const float2 im_p1_pos = ImageFeatureTable::p1_pos(level)[i]; + const float2 im_p2_pos = ImageFeatureTable::p2_pos(level)[i]; + + if (angleEq(im_p1_theta, t_p1_theta, angleEpsilon)) + { + float2 c1, c2; + + c1 = im_p1_pos - r1; + c1 = c1 * idp; + + c2 = im_p2_pos - r2; + c2 = c2 * idp; + + if (::fabs(c1.x - c2.x) > 1 || ::fabs(c1.y - c2.y) > 1) + continue; + + if (c1.y >= 0 && c1.y < PHist.rows - 2 && c1.x >= 0 && c1.x < PHist.cols - 2) + ::atomicAdd(PHist.ptr(__float2int_rn(c1.y) + 1) + __float2int_rn(c1.x) + 1, 1); + } + } + } + } + + void Guil_Full_calcPHist_gpu(const int* templSizes, const int* imageSizes, PtrStepSzi PHist, + float angle, float angleEpsilon, float scale, + float dp, + int levels, int tMaxSize) + { + const dim3 block(256); + const dim3 grid(tMaxSize, levels + 1); + + angle *= (CV_PI_F / 180.0f); + angleEpsilon *= (CV_PI_F / 180.0f); + + const float sinVal = ::sinf(angle); + const float cosVal = ::cosf(angle); + + cudaSafeCall( cudaFuncSetCacheConfig(Guil_Full_calcPHist, cudaFuncCachePreferL1) ); + + Guil_Full_calcPHist<<>>(templSizes, imageSizes, PHist, + angle, sinVal, cosVal, angleEpsilon, scale, + 1.0f / dp); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + } + + __global__ void Guil_Full_findPosInHist(const PtrStepSzi hist, float4* out, int3* votes, const int maxSize, + const float angle, const int angleVotes, const float scale, const int scaleVotes, + const float dp, const int threshold) + { + const int x = blockIdx.x * blockDim.x + threadIdx.x; + const int y = blockIdx.y * blockDim.y + threadIdx.y; + + if (x >= hist.cols - 2 || y >= hist.rows - 2) + return; + + const int curVotes = hist(y + 1, x + 1); + + if (curVotes > threshold && + curVotes > hist(y + 1, x) && + curVotes >= hist(y + 1, x + 2) && + curVotes > hist(y, x + 1) && + curVotes >= hist(y + 2, x + 1)) + { + const int ind = ::atomicAdd(&g_counter, 1); + + if (ind < maxSize) + { + out[ind] = make_float4(x * dp, y * dp, scale, angle); + votes[ind] = make_int3(curVotes, scaleVotes, angleVotes); + } + } + } + + int Guil_Full_findPosInHist_gpu(PtrStepSzi hist, float4* out, int3* votes, int curSize, int maxSize, + float angle, int angleVotes, float scale, int scaleVotes, + float dp, int threshold) + { + void* counterPtr; + cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); + + cudaSafeCall( cudaMemcpy(counterPtr, &curSize, sizeof(int), cudaMemcpyHostToDevice) ); + + const dim3 block(32, 8); + const dim3 grid(divUp(hist.cols - 2, block.x), divUp(hist.rows - 2, block.y)); + + cudaSafeCall( cudaFuncSetCacheConfig(Guil_Full_findPosInHist, cudaFuncCachePreferL1) ); + + Guil_Full_findPosInHist<<>>(hist, out, votes, maxSize, + angle, angleVotes, scale, scaleVotes, + dp, threshold); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + + int totalCount; + cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); + + totalCount = ::min(totalCount, maxSize); + + return totalCount; + } + } +}}} + +#endif // HAVE_OPENCV_GPUARITHM + +#endif /* CUDA_DISABLER */ diff --git a/modules/gpuimgproc/src/cuda/hough.cu b/modules/gpuimgproc/src/cuda/hough.cu deleted file mode 100644 index 696ed38453..0000000000 --- a/modules/gpuimgproc/src/cuda/hough.cu +++ /dev/null @@ -1,1710 +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. -// -// -// 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*/ - -#if !defined CUDA_DISABLER - -#include -#include - -#include "opencv2/core/cuda/common.hpp" -#include "opencv2/core/cuda/emulation.hpp" -#include "opencv2/core/cuda/vec_math.hpp" -#include "opencv2/core/cuda/functional.hpp" -#include "opencv2/core/cuda/limits.hpp" -#include "opencv2/core/cuda/dynamic_smem.hpp" - -namespace cv { namespace gpu { namespace cudev -{ - namespace hough - { - __device__ int g_counter; - - //////////////////////////////////////////////////////////////////////// - // buildPointList - - template - __global__ void buildPointList(const PtrStepSzb src, unsigned int* list) - { - __shared__ unsigned int s_queues[4][32 * PIXELS_PER_THREAD]; - __shared__ int s_qsize[4]; - __shared__ int s_globStart[4]; - - const int x = blockIdx.x * blockDim.x * PIXELS_PER_THREAD + threadIdx.x; - const int y = blockIdx.y * blockDim.y + threadIdx.y; - - if (threadIdx.x == 0) - s_qsize[threadIdx.y] = 0; - __syncthreads(); - - if (y < src.rows) - { - // fill the queue - const uchar* srcRow = src.ptr(y); - for (int i = 0, xx = x; i < PIXELS_PER_THREAD && xx < src.cols; ++i, xx += blockDim.x) - { - if (srcRow[xx]) - { - const unsigned int val = (y << 16) | xx; - const int qidx = Emulation::smem::atomicAdd(&s_qsize[threadIdx.y], 1); - s_queues[threadIdx.y][qidx] = val; - } - } - } - - __syncthreads(); - - // let one thread reserve the space required in the global list - if (threadIdx.x == 0 && threadIdx.y == 0) - { - // find how many items are stored in each list - int totalSize = 0; - for (int i = 0; i < blockDim.y; ++i) - { - s_globStart[i] = totalSize; - totalSize += s_qsize[i]; - } - - // calculate the offset in the global list - const int globalOffset = atomicAdd(&g_counter, totalSize); - for (int i = 0; i < blockDim.y; ++i) - s_globStart[i] += globalOffset; - } - - __syncthreads(); - - // copy local queues to global queue - const int qsize = s_qsize[threadIdx.y]; - int gidx = s_globStart[threadIdx.y] + threadIdx.x; - for(int i = threadIdx.x; i < qsize; i += blockDim.x, gidx += blockDim.x) - list[gidx] = s_queues[threadIdx.y][i]; - } - - int buildPointList_gpu(PtrStepSzb src, unsigned int* list) - { - const int PIXELS_PER_THREAD = 16; - - void* counterPtr; - cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); - - cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); - - const dim3 block(32, 4); - const dim3 grid(divUp(src.cols, block.x * PIXELS_PER_THREAD), divUp(src.rows, block.y)); - - cudaSafeCall( cudaFuncSetCacheConfig(buildPointList, cudaFuncCachePreferShared) ); - - buildPointList<<>>(src, list); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - - int totalCount; - cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); - - return totalCount; - } - - //////////////////////////////////////////////////////////////////////// - // linesAccum - - __global__ void linesAccumGlobal(const unsigned int* list, const int count, PtrStepi accum, const float irho, const float theta, const int numrho) - { - const int n = blockIdx.x; - const float ang = n * theta; - - float sinVal; - float cosVal; - sincosf(ang, &sinVal, &cosVal); - sinVal *= irho; - cosVal *= irho; - - const int shift = (numrho - 1) / 2; - - int* accumRow = accum.ptr(n + 1); - for (int i = threadIdx.x; i < count; i += blockDim.x) - { - const unsigned int val = list[i]; - - const int x = (val & 0xFFFF); - const int y = (val >> 16) & 0xFFFF; - - int r = __float2int_rn(x * cosVal + y * sinVal); - r += shift; - - ::atomicAdd(accumRow + r + 1, 1); - } - } - - __global__ void linesAccumShared(const unsigned int* list, const int count, PtrStepi accum, const float irho, const float theta, const int numrho) - { - int* smem = DynamicSharedMem(); - - for (int i = threadIdx.x; i < numrho + 1; i += blockDim.x) - smem[i] = 0; - - __syncthreads(); - - const int n = blockIdx.x; - const float ang = n * theta; - - float sinVal; - float cosVal; - sincosf(ang, &sinVal, &cosVal); - sinVal *= irho; - cosVal *= irho; - - const int shift = (numrho - 1) / 2; - - for (int i = threadIdx.x; i < count; i += blockDim.x) - { - const unsigned int val = list[i]; - - const int x = (val & 0xFFFF); - const int y = (val >> 16) & 0xFFFF; - - int r = __float2int_rn(x * cosVal + y * sinVal); - r += shift; - - Emulation::smem::atomicAdd(&smem[r + 1], 1); - } - - __syncthreads(); - - int* accumRow = accum.ptr(n + 1); - for (int i = threadIdx.x; i < numrho + 1; i += blockDim.x) - accumRow[i] = smem[i]; - } - - void linesAccum_gpu(const unsigned int* list, int count, PtrStepSzi accum, float rho, float theta, size_t sharedMemPerBlock, bool has20) - { - const dim3 block(has20 ? 1024 : 512); - const dim3 grid(accum.rows - 2); - - size_t smemSize = (accum.cols - 1) * sizeof(int); - - if (smemSize < sharedMemPerBlock - 1000) - linesAccumShared<<>>(list, count, accum, 1.0f / rho, theta, accum.cols - 2); - else - linesAccumGlobal<<>>(list, count, accum, 1.0f / rho, theta, accum.cols - 2); - - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - } - - //////////////////////////////////////////////////////////////////////// - // linesGetResult - - __global__ void linesGetResult(const PtrStepSzi accum, float2* out, int* votes, const int maxSize, const float rho, const float theta, const int threshold, const int numrho) - { - const int r = blockIdx.x * blockDim.x + threadIdx.x; - const int n = blockIdx.y * blockDim.y + threadIdx.y; - - if (r >= accum.cols - 2 || n >= accum.rows - 2) - return; - - const int curVotes = accum(n + 1, r + 1); - - if (curVotes > threshold && - curVotes > accum(n + 1, r) && - curVotes >= accum(n + 1, r + 2) && - curVotes > accum(n, r + 1) && - curVotes >= accum(n + 2, r + 1)) - { - const float radius = (r - (numrho - 1) * 0.5f) * rho; - const float angle = n * theta; - - const int ind = ::atomicAdd(&g_counter, 1); - if (ind < maxSize) - { - out[ind] = make_float2(radius, angle); - votes[ind] = curVotes; - } - } - } - - int linesGetResult_gpu(PtrStepSzi accum, float2* out, int* votes, int maxSize, float rho, float theta, int threshold, bool doSort) - { - void* counterPtr; - cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); - - cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); - - const dim3 block(32, 8); - const dim3 grid(divUp(accum.cols - 2, block.x), divUp(accum.rows - 2, block.y)); - - cudaSafeCall( cudaFuncSetCacheConfig(linesGetResult, cudaFuncCachePreferL1) ); - - linesGetResult<<>>(accum, out, votes, maxSize, rho, theta, threshold, accum.cols - 2); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - - int totalCount; - cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); - - totalCount = ::min(totalCount, maxSize); - - if (doSort && totalCount > 0) - { - thrust::device_ptr outPtr(out); - thrust::device_ptr votesPtr(votes); - thrust::sort_by_key(votesPtr, votesPtr + totalCount, outPtr, thrust::greater()); - } - - return totalCount; - } - - //////////////////////////////////////////////////////////////////////// - // houghLinesProbabilistic - - texture tex_mask(false, cudaFilterModePoint, cudaAddressModeClamp); - - __global__ void houghLinesProbabilistic(const PtrStepSzi accum, - int4* out, const int maxSize, - const float rho, const float theta, - const int lineGap, const int lineLength, - const int rows, const int cols) - { - const int r = blockIdx.x * blockDim.x + threadIdx.x; - const int n = blockIdx.y * blockDim.y + threadIdx.y; - - if (r >= accum.cols - 2 || n >= accum.rows - 2) - return; - - const int curVotes = accum(n + 1, r + 1); - - if (curVotes >= lineLength && - curVotes > accum(n, r) && - curVotes > accum(n, r + 1) && - curVotes > accum(n, r + 2) && - curVotes > accum(n + 1, r) && - curVotes > accum(n + 1, r + 2) && - curVotes > accum(n + 2, r) && - curVotes > accum(n + 2, r + 1) && - curVotes > accum(n + 2, r + 2)) - { - const float radius = (r - (accum.cols - 2 - 1) * 0.5f) * rho; - const float angle = n * theta; - - float cosa; - float sina; - sincosf(angle, &sina, &cosa); - - float2 p0 = make_float2(cosa * radius, sina * radius); - float2 dir = make_float2(-sina, cosa); - - float2 pb[4] = {make_float2(-1, -1), make_float2(-1, -1), make_float2(-1, -1), make_float2(-1, -1)}; - float a; - - if (dir.x != 0) - { - a = -p0.x / dir.x; - pb[0].x = 0; - pb[0].y = p0.y + a * dir.y; - - a = (cols - 1 - p0.x) / dir.x; - pb[1].x = cols - 1; - pb[1].y = p0.y + a * dir.y; - } - if (dir.y != 0) - { - a = -p0.y / dir.y; - pb[2].x = p0.x + a * dir.x; - pb[2].y = 0; - - a = (rows - 1 - p0.y) / dir.y; - pb[3].x = p0.x + a * dir.x; - pb[3].y = rows - 1; - } - - if (pb[0].x == 0 && (pb[0].y >= 0 && pb[0].y < rows)) - { - p0 = pb[0]; - if (dir.x < 0) - dir = -dir; - } - else if (pb[1].x == cols - 1 && (pb[0].y >= 0 && pb[0].y < rows)) - { - p0 = pb[1]; - if (dir.x > 0) - dir = -dir; - } - else if (pb[2].y == 0 && (pb[2].x >= 0 && pb[2].x < cols)) - { - p0 = pb[2]; - if (dir.y < 0) - dir = -dir; - } - else if (pb[3].y == rows - 1 && (pb[3].x >= 0 && pb[3].x < cols)) - { - p0 = pb[3]; - if (dir.y > 0) - dir = -dir; - } - - float2 d; - if (::fabsf(dir.x) > ::fabsf(dir.y)) - { - d.x = dir.x > 0 ? 1 : -1; - d.y = dir.y / ::fabsf(dir.x); - } - else - { - d.x = dir.x / ::fabsf(dir.y); - d.y = dir.y > 0 ? 1 : -1; - } - - float2 line_end[2]; - int gap; - bool inLine = false; - - float2 p1 = p0; - if (p1.x < 0 || p1.x >= cols || p1.y < 0 || p1.y >= rows) - return; - - for (;;) - { - if (tex2D(tex_mask, p1.x, p1.y)) - { - gap = 0; - - if (!inLine) - { - line_end[0] = p1; - line_end[1] = p1; - inLine = true; - } - else - { - line_end[1] = p1; - } - } - else if (inLine) - { - if (++gap > lineGap) - { - bool good_line = ::abs(line_end[1].x - line_end[0].x) >= lineLength || - ::abs(line_end[1].y - line_end[0].y) >= lineLength; - - if (good_line) - { - const int ind = ::atomicAdd(&g_counter, 1); - if (ind < maxSize) - out[ind] = make_int4(line_end[0].x, line_end[0].y, line_end[1].x, line_end[1].y); - } - - gap = 0; - inLine = false; - } - } - - p1 = p1 + d; - if (p1.x < 0 || p1.x >= cols || p1.y < 0 || p1.y >= rows) - { - if (inLine) - { - bool good_line = ::abs(line_end[1].x - line_end[0].x) >= lineLength || - ::abs(line_end[1].y - line_end[0].y) >= lineLength; - - if (good_line) - { - const int ind = ::atomicAdd(&g_counter, 1); - if (ind < maxSize) - out[ind] = make_int4(line_end[0].x, line_end[0].y, line_end[1].x, line_end[1].y); - } - - } - break; - } - } - } - } - - int houghLinesProbabilistic_gpu(PtrStepSzb mask, PtrStepSzi accum, int4* out, int maxSize, float rho, float theta, int lineGap, int lineLength) - { - void* counterPtr; - cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); - - cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); - - const dim3 block(32, 8); - const dim3 grid(divUp(accum.cols - 2, block.x), divUp(accum.rows - 2, block.y)); - - bindTexture(&tex_mask, mask); - - houghLinesProbabilistic<<>>(accum, - out, maxSize, - rho, theta, - lineGap, lineLength, - mask.rows, mask.cols); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - - int totalCount; - cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); - - totalCount = ::min(totalCount, maxSize); - - return totalCount; - } - - //////////////////////////////////////////////////////////////////////// - // circlesAccumCenters - - __global__ void circlesAccumCenters(const unsigned int* list, const int count, const PtrStepi dx, const PtrStepi dy, - PtrStepi accum, const int width, const int height, const int minRadius, const int maxRadius, const float idp) - { - const int SHIFT = 10; - const int ONE = 1 << SHIFT; - - const int tid = blockIdx.x * blockDim.x + threadIdx.x; - - if (tid >= count) - return; - - const unsigned int val = list[tid]; - - const int x = (val & 0xFFFF); - const int y = (val >> 16) & 0xFFFF; - - const int vx = dx(y, x); - const int vy = dy(y, x); - - if (vx == 0 && vy == 0) - return; - - const float mag = ::sqrtf(vx * vx + vy * vy); - - const int x0 = __float2int_rn((x * idp) * ONE); - const int y0 = __float2int_rn((y * idp) * ONE); - - int sx = __float2int_rn((vx * idp) * ONE / mag); - int sy = __float2int_rn((vy * idp) * ONE / mag); - - // Step from minRadius to maxRadius in both directions of the gradient - for (int k1 = 0; k1 < 2; ++k1) - { - int x1 = x0 + minRadius * sx; - int y1 = y0 + minRadius * sy; - - for (int r = minRadius; r <= maxRadius; x1 += sx, y1 += sy, ++r) - { - const int x2 = x1 >> SHIFT; - const int y2 = y1 >> SHIFT; - - if (x2 < 0 || x2 >= width || y2 < 0 || y2 >= height) - break; - - ::atomicAdd(accum.ptr(y2 + 1) + x2 + 1, 1); - } - - sx = -sx; - sy = -sy; - } - } - - void circlesAccumCenters_gpu(const unsigned int* list, int count, PtrStepi dx, PtrStepi dy, PtrStepSzi accum, int minRadius, int maxRadius, float idp) - { - const dim3 block(256); - const dim3 grid(divUp(count, block.x)); - - cudaSafeCall( cudaFuncSetCacheConfig(circlesAccumCenters, cudaFuncCachePreferL1) ); - - circlesAccumCenters<<>>(list, count, dx, dy, accum, accum.cols - 2, accum.rows - 2, minRadius, maxRadius, idp); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - } - - //////////////////////////////////////////////////////////////////////// - // buildCentersList - - __global__ void buildCentersList(const PtrStepSzi accum, unsigned int* centers, const int threshold) - { - const int x = blockIdx.x * blockDim.x + threadIdx.x; - const int y = blockIdx.y * blockDim.y + threadIdx.y; - - if (x < accum.cols - 2 && y < accum.rows - 2) - { - const int top = accum(y, x + 1); - - const int left = accum(y + 1, x); - const int cur = accum(y + 1, x + 1); - const int right = accum(y + 1, x + 2); - - const int bottom = accum(y + 2, x + 1); - - if (cur > threshold && cur > top && cur >= bottom && cur > left && cur >= right) - { - const unsigned int val = (y << 16) | x; - const int idx = ::atomicAdd(&g_counter, 1); - centers[idx] = val; - } - } - } - - int buildCentersList_gpu(PtrStepSzi accum, unsigned int* centers, int threshold) - { - void* counterPtr; - cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); - - cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); - - const dim3 block(32, 8); - const dim3 grid(divUp(accum.cols - 2, block.x), divUp(accum.rows - 2, block.y)); - - cudaSafeCall( cudaFuncSetCacheConfig(buildCentersList, cudaFuncCachePreferL1) ); - - buildCentersList<<>>(accum, centers, threshold); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - - int totalCount; - cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); - - return totalCount; - } - - //////////////////////////////////////////////////////////////////////// - // circlesAccumRadius - - __global__ void circlesAccumRadius(const unsigned int* centers, const unsigned int* list, const int count, - float3* circles, const int maxCircles, const float dp, - const int minRadius, const int maxRadius, const int histSize, const int threshold) - { - int* smem = DynamicSharedMem(); - - for (int i = threadIdx.x; i < histSize + 2; i += blockDim.x) - smem[i] = 0; - __syncthreads(); - - unsigned int val = centers[blockIdx.x]; - - float cx = (val & 0xFFFF); - float cy = (val >> 16) & 0xFFFF; - - cx = (cx + 0.5f) * dp; - cy = (cy + 0.5f) * dp; - - for (int i = threadIdx.x; i < count; i += blockDim.x) - { - val = list[i]; - - const int x = (val & 0xFFFF); - const int y = (val >> 16) & 0xFFFF; - - const float rad = ::sqrtf((cx - x) * (cx - x) + (cy - y) * (cy - y)); - if (rad >= minRadius && rad <= maxRadius) - { - const int r = __float2int_rn(rad - minRadius); - - Emulation::smem::atomicAdd(&smem[r + 1], 1); - } - } - - __syncthreads(); - - for (int i = threadIdx.x; i < histSize; i += blockDim.x) - { - const int curVotes = smem[i + 1]; - - if (curVotes >= threshold && curVotes > smem[i] && curVotes >= smem[i + 2]) - { - const int ind = ::atomicAdd(&g_counter, 1); - if (ind < maxCircles) - circles[ind] = make_float3(cx, cy, i + minRadius); - } - } - } - - int circlesAccumRadius_gpu(const unsigned int* centers, int centersCount, const unsigned int* list, int count, - float3* circles, int maxCircles, float dp, int minRadius, int maxRadius, int threshold, bool has20) - { - void* counterPtr; - cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); - - cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); - - const dim3 block(has20 ? 1024 : 512); - const dim3 grid(centersCount); - - const int histSize = maxRadius - minRadius + 1; - size_t smemSize = (histSize + 2) * sizeof(int); - - circlesAccumRadius<<>>(centers, list, count, circles, maxCircles, dp, minRadius, maxRadius, histSize, threshold); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - - int totalCount; - cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); - - totalCount = ::min(totalCount, maxCircles); - - return totalCount; - } - - //////////////////////////////////////////////////////////////////////// - // Generalized Hough - - template - __global__ void buildEdgePointList(const PtrStepSzb edges, const PtrStep dx, const PtrStep dy, unsigned int* coordList, float* thetaList) - { - __shared__ unsigned int s_coordLists[4][32 * PIXELS_PER_THREAD]; - __shared__ float s_thetaLists[4][32 * PIXELS_PER_THREAD]; - __shared__ int s_sizes[4]; - __shared__ int s_globStart[4]; - - const int x = blockIdx.x * blockDim.x * PIXELS_PER_THREAD + threadIdx.x; - const int y = blockIdx.y * blockDim.y + threadIdx.y; - - if (threadIdx.x == 0) - s_sizes[threadIdx.y] = 0; - __syncthreads(); - - if (y < edges.rows) - { - // fill the queue - const uchar* edgesRow = edges.ptr(y); - const T* dxRow = dx.ptr(y); - const T* dyRow = dy.ptr(y); - - for (int i = 0, xx = x; i < PIXELS_PER_THREAD && xx < edges.cols; ++i, xx += blockDim.x) - { - const T dxVal = dxRow[xx]; - const T dyVal = dyRow[xx]; - - if (edgesRow[xx] && (dxVal != 0 || dyVal != 0)) - { - const unsigned int coord = (y << 16) | xx; - - float theta = ::atan2f(dyVal, dxVal); - if (theta < 0) - theta += 2.0f * CV_PI_F; - - const int qidx = Emulation::smem::atomicAdd(&s_sizes[threadIdx.y], 1); - - s_coordLists[threadIdx.y][qidx] = coord; - s_thetaLists[threadIdx.y][qidx] = theta; - } - } - } - - __syncthreads(); - - // let one thread reserve the space required in the global list - if (threadIdx.x == 0 && threadIdx.y == 0) - { - // find how many items are stored in each list - int totalSize = 0; - for (int i = 0; i < blockDim.y; ++i) - { - s_globStart[i] = totalSize; - totalSize += s_sizes[i]; - } - - // calculate the offset in the global list - const int globalOffset = atomicAdd(&g_counter, totalSize); - for (int i = 0; i < blockDim.y; ++i) - s_globStart[i] += globalOffset; - } - - __syncthreads(); - - // copy local queues to global queue - const int qsize = s_sizes[threadIdx.y]; - int gidx = s_globStart[threadIdx.y] + threadIdx.x; - for(int i = threadIdx.x; i < qsize; i += blockDim.x, gidx += blockDim.x) - { - coordList[gidx] = s_coordLists[threadIdx.y][i]; - thetaList[gidx] = s_thetaLists[threadIdx.y][i]; - } - } - - template - int buildEdgePointList_gpu(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList) - { - const int PIXELS_PER_THREAD = 8; - - void* counterPtr; - cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); - - cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); - - const dim3 block(32, 4); - const dim3 grid(divUp(edges.cols, block.x * PIXELS_PER_THREAD), divUp(edges.rows, block.y)); - - cudaSafeCall( cudaFuncSetCacheConfig(buildEdgePointList, cudaFuncCachePreferShared) ); - - buildEdgePointList<<>>(edges, (PtrStepSz) dx, (PtrStepSz) dy, coordList, thetaList); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - - int totalCount; - cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); - - return totalCount; - } - - template int buildEdgePointList_gpu(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList); - template int buildEdgePointList_gpu(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList); - template int buildEdgePointList_gpu(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList); - - __global__ void buildRTable(const unsigned int* coordList, const float* thetaList, const int pointsCount, - PtrStep r_table, int* r_sizes, int maxSize, - const short2 templCenter, const float thetaScale) - { - const int tid = blockIdx.x * blockDim.x + threadIdx.x; - - if (tid >= pointsCount) - return; - - const unsigned int coord = coordList[tid]; - short2 p; - p.x = (coord & 0xFFFF); - p.y = (coord >> 16) & 0xFFFF; - - const float theta = thetaList[tid]; - const int n = __float2int_rn(theta * thetaScale); - - const int ind = ::atomicAdd(r_sizes + n, 1); - if (ind < maxSize) - r_table(n, ind) = saturate_cast(p - templCenter); - } - - void buildRTable_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, - PtrStepSz r_table, int* r_sizes, - short2 templCenter, int levels) - { - const dim3 block(256); - const dim3 grid(divUp(pointsCount, block.x)); - - const float thetaScale = levels / (2.0f * CV_PI_F); - - buildRTable<<>>(coordList, thetaList, pointsCount, r_table, r_sizes, r_table.cols, templCenter, thetaScale); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - } - - //////////////////////////////////////////////////////////////////////// - // GHT_Ballard_Pos - - __global__ void GHT_Ballard_Pos_calcHist(const unsigned int* coordList, const float* thetaList, const int pointsCount, - const PtrStep r_table, const int* r_sizes, - PtrStepSzi hist, - const float idp, const float thetaScale) - { - const int tid = blockIdx.x * blockDim.x + threadIdx.x; - - if (tid >= pointsCount) - return; - - const unsigned int coord = coordList[tid]; - short2 p; - p.x = (coord & 0xFFFF); - p.y = (coord >> 16) & 0xFFFF; - - const float theta = thetaList[tid]; - const int n = __float2int_rn(theta * thetaScale); - - const short2* r_row = r_table.ptr(n); - const int r_row_size = r_sizes[n]; - - for (int j = 0; j < r_row_size; ++j) - { - int2 c = p - r_row[j]; - - c.x = __float2int_rn(c.x * idp); - c.y = __float2int_rn(c.y * idp); - - if (c.x >= 0 && c.x < hist.cols - 2 && c.y >= 0 && c.y < hist.rows - 2) - ::atomicAdd(hist.ptr(c.y + 1) + c.x + 1, 1); - } - } - - void GHT_Ballard_Pos_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, - PtrStepSz r_table, const int* r_sizes, - PtrStepSzi hist, - float dp, int levels) - { - const dim3 block(256); - const dim3 grid(divUp(pointsCount, block.x)); - - const float idp = 1.0f / dp; - const float thetaScale = levels / (2.0f * CV_PI_F); - - GHT_Ballard_Pos_calcHist<<>>(coordList, thetaList, pointsCount, r_table, r_sizes, hist, idp, thetaScale); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - } - - __global__ void GHT_Ballard_Pos_findPosInHist(const PtrStepSzi hist, float4* out, int3* votes, const int maxSize, const float dp, const int threshold) - { - const int x = blockIdx.x * blockDim.x + threadIdx.x; - const int y = blockIdx.y * blockDim.y + threadIdx.y; - - if (x >= hist.cols - 2 || y >= hist.rows - 2) - return; - - const int curVotes = hist(y + 1, x + 1); - - if (curVotes > threshold && - curVotes > hist(y + 1, x) && - curVotes >= hist(y + 1, x + 2) && - curVotes > hist(y, x + 1) && - curVotes >= hist(y + 2, x + 1)) - { - const int ind = ::atomicAdd(&g_counter, 1); - - if (ind < maxSize) - { - out[ind] = make_float4(x * dp, y * dp, 1.0f, 0.0f); - votes[ind] = make_int3(curVotes, 0, 0); - } - } - } - - int GHT_Ballard_Pos_findPosInHist_gpu(PtrStepSzi hist, float4* out, int3* votes, int maxSize, float dp, int threshold) - { - void* counterPtr; - cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); - - cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); - - const dim3 block(32, 8); - const dim3 grid(divUp(hist.cols - 2, block.x), divUp(hist.rows - 2, block.y)); - - cudaSafeCall( cudaFuncSetCacheConfig(GHT_Ballard_Pos_findPosInHist, cudaFuncCachePreferL1) ); - - GHT_Ballard_Pos_findPosInHist<<>>(hist, out, votes, maxSize, dp, threshold); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - - int totalCount; - cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); - - totalCount = ::min(totalCount, maxSize); - - return totalCount; - } - - //////////////////////////////////////////////////////////////////////// - // GHT_Ballard_PosScale - - __global__ void GHT_Ballard_PosScale_calcHist(const unsigned int* coordList, const float* thetaList, - PtrStep r_table, const int* r_sizes, - PtrStepi hist, const int rows, const int cols, - const float minScale, const float scaleStep, const int scaleRange, - const float idp, const float thetaScale) - { - const unsigned int coord = coordList[blockIdx.x]; - float2 p; - p.x = (coord & 0xFFFF); - p.y = (coord >> 16) & 0xFFFF; - - const float theta = thetaList[blockIdx.x]; - const int n = __float2int_rn(theta * thetaScale); - - const short2* r_row = r_table.ptr(n); - const int r_row_size = r_sizes[n]; - - for (int j = 0; j < r_row_size; ++j) - { - const float2 d = saturate_cast(r_row[j]); - - for (int s = threadIdx.x; s < scaleRange; s += blockDim.x) - { - const float scale = minScale + s * scaleStep; - - float2 c = p - scale * d; - - c.x *= idp; - c.y *= idp; - - if (c.x >= 0 && c.x < cols && c.y >= 0 && c.y < rows) - ::atomicAdd(hist.ptr((s + 1) * (rows + 2) + __float2int_rn(c.y + 1)) + __float2int_rn(c.x + 1), 1); - } - } - } - - void GHT_Ballard_PosScale_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, - PtrStepSz r_table, const int* r_sizes, - PtrStepi hist, int rows, int cols, - float minScale, float scaleStep, int scaleRange, - float dp, int levels) - { - const dim3 block(256); - const dim3 grid(pointsCount); - - const float idp = 1.0f / dp; - const float thetaScale = levels / (2.0f * CV_PI_F); - - GHT_Ballard_PosScale_calcHist<<>>(coordList, thetaList, - r_table, r_sizes, - hist, rows, cols, - minScale, scaleStep, scaleRange, - idp, thetaScale); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - } - - __global__ void GHT_Ballard_PosScale_findPosInHist(const PtrStepi hist, const int rows, const int cols, const int scaleRange, - float4* out, int3* votes, const int maxSize, - const float minScale, const float scaleStep, const float dp, const int threshold) - { - const int x = blockIdx.x * blockDim.x + threadIdx.x; - const int y = blockIdx.y * blockDim.y + threadIdx.y; - - if (x >= cols || y >= rows) - return; - - for (int s = 0; s < scaleRange; ++s) - { - const float scale = minScale + s * scaleStep; - - const int prevScaleIdx = (s) * (rows + 2); - const int curScaleIdx = (s + 1) * (rows + 2); - const int nextScaleIdx = (s + 2) * (rows + 2); - - const int curVotes = hist(curScaleIdx + y + 1, x + 1); - - if (curVotes > threshold && - curVotes > hist(curScaleIdx + y + 1, x) && - curVotes >= hist(curScaleIdx + y + 1, x + 2) && - curVotes > hist(curScaleIdx + y, x + 1) && - curVotes >= hist(curScaleIdx + y + 2, x + 1) && - curVotes > hist(prevScaleIdx + y + 1, x + 1) && - curVotes >= hist(nextScaleIdx + y + 1, x + 1)) - { - const int ind = ::atomicAdd(&g_counter, 1); - - if (ind < maxSize) - { - out[ind] = make_float4(x * dp, y * dp, scale, 0.0f); - votes[ind] = make_int3(curVotes, curVotes, 0); - } - } - } - } - - int GHT_Ballard_PosScale_findPosInHist_gpu(PtrStepi hist, int rows, int cols, int scaleRange, float4* out, int3* votes, int maxSize, - float minScale, float scaleStep, float dp, int threshold) - { - void* counterPtr; - cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); - - cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); - - const dim3 block(32, 8); - const dim3 grid(divUp(cols, block.x), divUp(rows, block.y)); - - cudaSafeCall( cudaFuncSetCacheConfig(GHT_Ballard_PosScale_findPosInHist, cudaFuncCachePreferL1) ); - - GHT_Ballard_PosScale_findPosInHist<<>>(hist, rows, cols, scaleRange, out, votes, maxSize, minScale, scaleStep, dp, threshold); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - - int totalCount; - cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); - - totalCount = ::min(totalCount, maxSize); - - return totalCount; - } - - //////////////////////////////////////////////////////////////////////// - // GHT_Ballard_PosRotation - - __global__ void GHT_Ballard_PosRotation_calcHist(const unsigned int* coordList, const float* thetaList, - PtrStep r_table, const int* r_sizes, - PtrStepi hist, const int rows, const int cols, - const float minAngle, const float angleStep, const int angleRange, - const float idp, const float thetaScale) - { - const unsigned int coord = coordList[blockIdx.x]; - float2 p; - p.x = (coord & 0xFFFF); - p.y = (coord >> 16) & 0xFFFF; - - const float thetaVal = thetaList[blockIdx.x]; - - for (int a = threadIdx.x; a < angleRange; a += blockDim.x) - { - const float angle = (minAngle + a * angleStep) * (CV_PI_F / 180.0f); - float sinA, cosA; - sincosf(angle, &sinA, &cosA); - - float theta = thetaVal - angle; - if (theta < 0) - theta += 2.0f * CV_PI_F; - - const int n = __float2int_rn(theta * thetaScale); - - const short2* r_row = r_table.ptr(n); - const int r_row_size = r_sizes[n]; - - for (int j = 0; j < r_row_size; ++j) - { - const float2 d = saturate_cast(r_row[j]); - - const float2 dr = make_float2(d.x * cosA - d.y * sinA, d.x * sinA + d.y * cosA); - - float2 c = make_float2(p.x - dr.x, p.y - dr.y); - c.x *= idp; - c.y *= idp; - - if (c.x >= 0 && c.x < cols && c.y >= 0 && c.y < rows) - ::atomicAdd(hist.ptr((a + 1) * (rows + 2) + __float2int_rn(c.y + 1)) + __float2int_rn(c.x + 1), 1); - } - } - } - - void GHT_Ballard_PosRotation_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, - PtrStepSz r_table, const int* r_sizes, - PtrStepi hist, int rows, int cols, - float minAngle, float angleStep, int angleRange, - float dp, int levels) - { - const dim3 block(256); - const dim3 grid(pointsCount); - - const float idp = 1.0f / dp; - const float thetaScale = levels / (2.0f * CV_PI_F); - - GHT_Ballard_PosRotation_calcHist<<>>(coordList, thetaList, - r_table, r_sizes, - hist, rows, cols, - minAngle, angleStep, angleRange, - idp, thetaScale); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - } - - __global__ void GHT_Ballard_PosRotation_findPosInHist(const PtrStepi hist, const int rows, const int cols, const int angleRange, - float4* out, int3* votes, const int maxSize, - const float minAngle, const float angleStep, const float dp, const int threshold) - { - const int x = blockIdx.x * blockDim.x + threadIdx.x; - const int y = blockIdx.y * blockDim.y + threadIdx.y; - - if (x >= cols || y >= rows) - return; - - for (int a = 0; a < angleRange; ++a) - { - const float angle = minAngle + a * angleStep; - - const int prevAngleIdx = (a) * (rows + 2); - const int curAngleIdx = (a + 1) * (rows + 2); - const int nextAngleIdx = (a + 2) * (rows + 2); - - const int curVotes = hist(curAngleIdx + y + 1, x + 1); - - if (curVotes > threshold && - curVotes > hist(curAngleIdx + y + 1, x) && - curVotes >= hist(curAngleIdx + y + 1, x + 2) && - curVotes > hist(curAngleIdx + y, x + 1) && - curVotes >= hist(curAngleIdx + y + 2, x + 1) && - curVotes > hist(prevAngleIdx + y + 1, x + 1) && - curVotes >= hist(nextAngleIdx + y + 1, x + 1)) - { - const int ind = ::atomicAdd(&g_counter, 1); - - if (ind < maxSize) - { - out[ind] = make_float4(x * dp, y * dp, 1.0f, angle); - votes[ind] = make_int3(curVotes, 0, curVotes); - } - } - } - } - - int GHT_Ballard_PosRotation_findPosInHist_gpu(PtrStepi hist, int rows, int cols, int angleRange, float4* out, int3* votes, int maxSize, - float minAngle, float angleStep, float dp, int threshold) - { - void* counterPtr; - cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); - - cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); - - const dim3 block(32, 8); - const dim3 grid(divUp(cols, block.x), divUp(rows, block.y)); - - cudaSafeCall( cudaFuncSetCacheConfig(GHT_Ballard_PosRotation_findPosInHist, cudaFuncCachePreferL1) ); - - GHT_Ballard_PosRotation_findPosInHist<<>>(hist, rows, cols, angleRange, out, votes, maxSize, minAngle, angleStep, dp, threshold); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - - int totalCount; - cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); - - totalCount = ::min(totalCount, maxSize); - - return totalCount; - } - - //////////////////////////////////////////////////////////////////////// - // GHT_Guil_Full - - struct FeatureTable - { - uchar* p1_pos_data; - size_t p1_pos_step; - - uchar* p1_theta_data; - size_t p1_theta_step; - - uchar* p2_pos_data; - size_t p2_pos_step; - - uchar* d12_data; - size_t d12_step; - - uchar* r1_data; - size_t r1_step; - - uchar* r2_data; - size_t r2_step; - }; - - __constant__ FeatureTable c_templFeatures; - __constant__ FeatureTable c_imageFeatures; - - void GHT_Guil_Full_setTemplFeatures(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2) - { - FeatureTable tbl; - - tbl.p1_pos_data = p1_pos.data; - tbl.p1_pos_step = p1_pos.step; - - tbl.p1_theta_data = p1_theta.data; - tbl.p1_theta_step = p1_theta.step; - - tbl.p2_pos_data = p2_pos.data; - tbl.p2_pos_step = p2_pos.step; - - tbl.d12_data = d12.data; - tbl.d12_step = d12.step; - - tbl.r1_data = r1.data; - tbl.r1_step = r1.step; - - tbl.r2_data = r2.data; - tbl.r2_step = r2.step; - - cudaSafeCall( cudaMemcpyToSymbol(c_templFeatures, &tbl, sizeof(FeatureTable)) ); - } - void GHT_Guil_Full_setImageFeatures(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2) - { - FeatureTable tbl; - - tbl.p1_pos_data = p1_pos.data; - tbl.p1_pos_step = p1_pos.step; - - tbl.p1_theta_data = p1_theta.data; - tbl.p1_theta_step = p1_theta.step; - - tbl.p2_pos_data = p2_pos.data; - tbl.p2_pos_step = p2_pos.step; - - tbl.d12_data = d12.data; - tbl.d12_step = d12.step; - - tbl.r1_data = r1.data; - tbl.r1_step = r1.step; - - tbl.r2_data = r2.data; - tbl.r2_step = r2.step; - - cudaSafeCall( cudaMemcpyToSymbol(c_imageFeatures, &tbl, sizeof(FeatureTable)) ); - } - - struct TemplFeatureTable - { - static __device__ float2* p1_pos(int n) - { - return (float2*)(c_templFeatures.p1_pos_data + n * c_templFeatures.p1_pos_step); - } - static __device__ float* p1_theta(int n) - { - return (float*)(c_templFeatures.p1_theta_data + n * c_templFeatures.p1_theta_step); - } - static __device__ float2* p2_pos(int n) - { - return (float2*)(c_templFeatures.p2_pos_data + n * c_templFeatures.p2_pos_step); - } - - static __device__ float* d12(int n) - { - return (float*)(c_templFeatures.d12_data + n * c_templFeatures.d12_step); - } - - static __device__ float2* r1(int n) - { - return (float2*)(c_templFeatures.r1_data + n * c_templFeatures.r1_step); - } - static __device__ float2* r2(int n) - { - return (float2*)(c_templFeatures.r2_data + n * c_templFeatures.r2_step); - } - }; - struct ImageFeatureTable - { - static __device__ float2* p1_pos(int n) - { - return (float2*)(c_imageFeatures.p1_pos_data + n * c_imageFeatures.p1_pos_step); - } - static __device__ float* p1_theta(int n) - { - return (float*)(c_imageFeatures.p1_theta_data + n * c_imageFeatures.p1_theta_step); - } - static __device__ float2* p2_pos(int n) - { - return (float2*)(c_imageFeatures.p2_pos_data + n * c_imageFeatures.p2_pos_step); - } - - static __device__ float* d12(int n) - { - return (float*)(c_imageFeatures.d12_data + n * c_imageFeatures.d12_step); - } - - static __device__ float2* r1(int n) - { - return (float2*)(c_imageFeatures.r1_data + n * c_imageFeatures.r1_step); - } - static __device__ float2* r2(int n) - { - return (float2*)(c_imageFeatures.r2_data + n * c_imageFeatures.r2_step); - } - }; - - __device__ float clampAngle(float a) - { - float res = a; - - while (res > 2.0f * CV_PI_F) - res -= 2.0f * CV_PI_F; - while (res < 0.0f) - res += 2.0f * CV_PI_F; - - return res; - } - - __device__ bool angleEq(float a, float b, float eps) - { - return (::fabs(clampAngle(a - b)) <= eps); - } - - template - __global__ void GHT_Guil_Full_buildFeatureList(const unsigned int* coordList, const float* thetaList, const int pointsCount, - int* sizes, const int maxSize, - const float xi, const float angleEpsilon, const float alphaScale, - const float2 center, const float maxDist) - { - const float p1_theta = thetaList[blockIdx.x]; - const unsigned int coord1 = coordList[blockIdx.x]; - float2 p1_pos; - p1_pos.x = (coord1 & 0xFFFF); - p1_pos.y = (coord1 >> 16) & 0xFFFF; - - for (int i = threadIdx.x; i < pointsCount; i += blockDim.x) - { - const float p2_theta = thetaList[i]; - const unsigned int coord2 = coordList[i]; - float2 p2_pos; - p2_pos.x = (coord2 & 0xFFFF); - p2_pos.y = (coord2 >> 16) & 0xFFFF; - - if (angleEq(p1_theta - p2_theta, xi, angleEpsilon)) - { - const float2 d = p1_pos - p2_pos; - - float alpha12 = clampAngle(::atan2(d.y, d.x) - p1_theta); - float d12 = ::sqrtf(d.x * d.x + d.y * d.y); - - if (d12 > maxDist) - continue; - - float2 r1 = p1_pos - center; - float2 r2 = p2_pos - center; - - const int n = __float2int_rn(alpha12 * alphaScale); - - const int ind = ::atomicAdd(sizes + n, 1); - - if (ind < maxSize) - { - if (!isTempl) - { - FT::p1_pos(n)[ind] = p1_pos; - FT::p2_pos(n)[ind] = p2_pos; - } - - FT::p1_theta(n)[ind] = p1_theta; - - FT::d12(n)[ind] = d12; - - if (isTempl) - { - FT::r1(n)[ind] = r1; - FT::r2(n)[ind] = r2; - } - } - } - } - } - - template - void GHT_Guil_Full_buildFeatureList_caller(const unsigned int* coordList, const float* thetaList, int pointsCount, - int* sizes, int maxSize, - float xi, float angleEpsilon, int levels, - float2 center, float maxDist) - { - const dim3 block(256); - const dim3 grid(pointsCount); - - const float alphaScale = levels / (2.0f * CV_PI_F); - - GHT_Guil_Full_buildFeatureList<<>>(coordList, thetaList, pointsCount, - sizes, maxSize, - xi * (CV_PI_F / 180.0f), angleEpsilon * (CV_PI_F / 180.0f), alphaScale, - center, maxDist); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - - thrust::device_ptr sizesPtr(sizes); - thrust::transform(sizesPtr, sizesPtr + levels + 1, sizesPtr, cudev::bind2nd(cudev::minimum(), maxSize)); - } - - void GHT_Guil_Full_buildTemplFeatureList_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, - int* sizes, int maxSize, - float xi, float angleEpsilon, int levels, - float2 center, float maxDist) - { - GHT_Guil_Full_buildFeatureList_caller(coordList, thetaList, pointsCount, - sizes, maxSize, - xi, angleEpsilon, levels, - center, maxDist); - } - void GHT_Guil_Full_buildImageFeatureList_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, - int* sizes, int maxSize, - float xi, float angleEpsilon, int levels, - float2 center, float maxDist) - { - GHT_Guil_Full_buildFeatureList_caller(coordList, thetaList, pointsCount, - sizes, maxSize, - xi, angleEpsilon, levels, - center, maxDist); - } - - __global__ void GHT_Guil_Full_calcOHist(const int* templSizes, const int* imageSizes, int* OHist, - const float minAngle, const float maxAngle, const float iAngleStep, const int angleRange) - { - extern __shared__ int s_OHist[]; - for (int i = threadIdx.x; i <= angleRange; i += blockDim.x) - s_OHist[i] = 0; - __syncthreads(); - - const int tIdx = blockIdx.x; - const int level = blockIdx.y; - - const int tSize = templSizes[level]; - - if (tIdx < tSize) - { - const int imSize = imageSizes[level]; - - const float t_p1_theta = TemplFeatureTable::p1_theta(level)[tIdx]; - - for (int i = threadIdx.x; i < imSize; i += blockDim.x) - { - const float im_p1_theta = ImageFeatureTable::p1_theta(level)[i]; - - const float angle = clampAngle(im_p1_theta - t_p1_theta); - - if (angle >= minAngle && angle <= maxAngle) - { - const int n = __float2int_rn((angle - minAngle) * iAngleStep); - Emulation::smem::atomicAdd(&s_OHist[n], 1); - } - } - } - __syncthreads(); - - for (int i = threadIdx.x; i <= angleRange; i += blockDim.x) - ::atomicAdd(OHist + i, s_OHist[i]); - } - - void GHT_Guil_Full_calcOHist_gpu(const int* templSizes, const int* imageSizes, int* OHist, - float minAngle, float maxAngle, float angleStep, int angleRange, - int levels, int tMaxSize) - { - const dim3 block(256); - const dim3 grid(tMaxSize, levels + 1); - - minAngle *= (CV_PI_F / 180.0f); - maxAngle *= (CV_PI_F / 180.0f); - angleStep *= (CV_PI_F / 180.0f); - - const size_t smemSize = (angleRange + 1) * sizeof(float); - - GHT_Guil_Full_calcOHist<<>>(templSizes, imageSizes, OHist, - minAngle, maxAngle, 1.0f / angleStep, angleRange); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - } - - __global__ void GHT_Guil_Full_calcSHist(const int* templSizes, const int* imageSizes, int* SHist, - const float angle, const float angleEpsilon, - const float minScale, const float maxScale, const float iScaleStep, const int scaleRange) - { - extern __shared__ int s_SHist[]; - for (int i = threadIdx.x; i <= scaleRange; i += blockDim.x) - s_SHist[i] = 0; - __syncthreads(); - - const int tIdx = blockIdx.x; - const int level = blockIdx.y; - - const int tSize = templSizes[level]; - - if (tIdx < tSize) - { - const int imSize = imageSizes[level]; - - const float t_p1_theta = TemplFeatureTable::p1_theta(level)[tIdx] + angle; - const float t_d12 = TemplFeatureTable::d12(level)[tIdx] + angle; - - for (int i = threadIdx.x; i < imSize; i += blockDim.x) - { - const float im_p1_theta = ImageFeatureTable::p1_theta(level)[i]; - const float im_d12 = ImageFeatureTable::d12(level)[i]; - - if (angleEq(im_p1_theta, t_p1_theta, angleEpsilon)) - { - const float scale = im_d12 / t_d12; - - if (scale >= minScale && scale <= maxScale) - { - const int s = __float2int_rn((scale - minScale) * iScaleStep); - Emulation::smem::atomicAdd(&s_SHist[s], 1); - } - } - } - } - __syncthreads(); - - for (int i = threadIdx.x; i <= scaleRange; i += blockDim.x) - ::atomicAdd(SHist + i, s_SHist[i]); - } - - void GHT_Guil_Full_calcSHist_gpu(const int* templSizes, const int* imageSizes, int* SHist, - float angle, float angleEpsilon, - float minScale, float maxScale, float iScaleStep, int scaleRange, - int levels, int tMaxSize) - { - const dim3 block(256); - const dim3 grid(tMaxSize, levels + 1); - - angle *= (CV_PI_F / 180.0f); - angleEpsilon *= (CV_PI_F / 180.0f); - - const size_t smemSize = (scaleRange + 1) * sizeof(float); - - GHT_Guil_Full_calcSHist<<>>(templSizes, imageSizes, SHist, - angle, angleEpsilon, - minScale, maxScale, iScaleStep, scaleRange); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - } - - __global__ void GHT_Guil_Full_calcPHist(const int* templSizes, const int* imageSizes, PtrStepSzi PHist, - const float angle, const float sinVal, const float cosVal, const float angleEpsilon, const float scale, - const float idp) - { - const int tIdx = blockIdx.x; - const int level = blockIdx.y; - - const int tSize = templSizes[level]; - - if (tIdx < tSize) - { - const int imSize = imageSizes[level]; - - const float t_p1_theta = TemplFeatureTable::p1_theta(level)[tIdx] + angle; - - float2 r1 = TemplFeatureTable::r1(level)[tIdx]; - float2 r2 = TemplFeatureTable::r2(level)[tIdx]; - - r1 = r1 * scale; - r2 = r2 * scale; - - r1 = make_float2(cosVal * r1.x - sinVal * r1.y, sinVal * r1.x + cosVal * r1.y); - r2 = make_float2(cosVal * r2.x - sinVal * r2.y, sinVal * r2.x + cosVal * r2.y); - - for (int i = threadIdx.x; i < imSize; i += blockDim.x) - { - const float im_p1_theta = ImageFeatureTable::p1_theta(level)[i]; - - const float2 im_p1_pos = ImageFeatureTable::p1_pos(level)[i]; - const float2 im_p2_pos = ImageFeatureTable::p2_pos(level)[i]; - - if (angleEq(im_p1_theta, t_p1_theta, angleEpsilon)) - { - float2 c1, c2; - - c1 = im_p1_pos - r1; - c1 = c1 * idp; - - c2 = im_p2_pos - r2; - c2 = c2 * idp; - - if (::fabs(c1.x - c2.x) > 1 || ::fabs(c1.y - c2.y) > 1) - continue; - - if (c1.y >= 0 && c1.y < PHist.rows - 2 && c1.x >= 0 && c1.x < PHist.cols - 2) - ::atomicAdd(PHist.ptr(__float2int_rn(c1.y) + 1) + __float2int_rn(c1.x) + 1, 1); - } - } - } - } - - void GHT_Guil_Full_calcPHist_gpu(const int* templSizes, const int* imageSizes, PtrStepSzi PHist, - float angle, float angleEpsilon, float scale, - float dp, - int levels, int tMaxSize) - { - const dim3 block(256); - const dim3 grid(tMaxSize, levels + 1); - - angle *= (CV_PI_F / 180.0f); - angleEpsilon *= (CV_PI_F / 180.0f); - - const float sinVal = ::sinf(angle); - const float cosVal = ::cosf(angle); - - cudaSafeCall( cudaFuncSetCacheConfig(GHT_Guil_Full_calcPHist, cudaFuncCachePreferL1) ); - - GHT_Guil_Full_calcPHist<<>>(templSizes, imageSizes, PHist, - angle, sinVal, cosVal, angleEpsilon, scale, - 1.0f / dp); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - } - - __global__ void GHT_Guil_Full_findPosInHist(const PtrStepSzi hist, float4* out, int3* votes, const int maxSize, - const float angle, const int angleVotes, const float scale, const int scaleVotes, - const float dp, const int threshold) - { - const int x = blockIdx.x * blockDim.x + threadIdx.x; - const int y = blockIdx.y * blockDim.y + threadIdx.y; - - if (x >= hist.cols - 2 || y >= hist.rows - 2) - return; - - const int curVotes = hist(y + 1, x + 1); - - if (curVotes > threshold && - curVotes > hist(y + 1, x) && - curVotes >= hist(y + 1, x + 2) && - curVotes > hist(y, x + 1) && - curVotes >= hist(y + 2, x + 1)) - { - const int ind = ::atomicAdd(&g_counter, 1); - - if (ind < maxSize) - { - out[ind] = make_float4(x * dp, y * dp, scale, angle); - votes[ind] = make_int3(curVotes, scaleVotes, angleVotes); - } - } - } - - int GHT_Guil_Full_findPosInHist_gpu(PtrStepSzi hist, float4* out, int3* votes, int curSize, int maxSize, - float angle, int angleVotes, float scale, int scaleVotes, - float dp, int threshold) - { - void* counterPtr; - cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); - - cudaSafeCall( cudaMemcpy(counterPtr, &curSize, sizeof(int), cudaMemcpyHostToDevice) ); - - const dim3 block(32, 8); - const dim3 grid(divUp(hist.cols - 2, block.x), divUp(hist.rows - 2, block.y)); - - cudaSafeCall( cudaFuncSetCacheConfig(GHT_Guil_Full_findPosInHist, cudaFuncCachePreferL1) ); - - GHT_Guil_Full_findPosInHist<<>>(hist, out, votes, maxSize, - angle, angleVotes, scale, scaleVotes, - dp, threshold); - cudaSafeCall( cudaGetLastError() ); - - cudaSafeCall( cudaDeviceSynchronize() ); - - int totalCount; - cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); - - totalCount = ::min(totalCount, maxSize); - - return totalCount; - } - } -}}} - - -#endif /* CUDA_DISABLER */ diff --git a/modules/gpuimgproc/src/cuda/hough_circles.cu b/modules/gpuimgproc/src/cuda/hough_circles.cu new file mode 100644 index 0000000000..1b6b103362 --- /dev/null +++ b/modules/gpuimgproc/src/cuda/hough_circles.cu @@ -0,0 +1,255 @@ +/*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*/ + +#if !defined CUDA_DISABLER + +#include "opencv2/core/cuda/common.hpp" +#include "opencv2/core/cuda/emulation.hpp" +#include "opencv2/core/cuda/dynamic_smem.hpp" + +namespace cv { namespace gpu { namespace cudev +{ + namespace hough_circles + { + __device__ int g_counter; + + //////////////////////////////////////////////////////////////////////// + // circlesAccumCenters + + __global__ void circlesAccumCenters(const unsigned int* list, const int count, const PtrStepi dx, const PtrStepi dy, + PtrStepi accum, const int width, const int height, const int minRadius, const int maxRadius, const float idp) + { + const int SHIFT = 10; + const int ONE = 1 << SHIFT; + + const int tid = blockIdx.x * blockDim.x + threadIdx.x; + + if (tid >= count) + return; + + const unsigned int val = list[tid]; + + const int x = (val & 0xFFFF); + const int y = (val >> 16) & 0xFFFF; + + const int vx = dx(y, x); + const int vy = dy(y, x); + + if (vx == 0 && vy == 0) + return; + + const float mag = ::sqrtf(vx * vx + vy * vy); + + const int x0 = __float2int_rn((x * idp) * ONE); + const int y0 = __float2int_rn((y * idp) * ONE); + + int sx = __float2int_rn((vx * idp) * ONE / mag); + int sy = __float2int_rn((vy * idp) * ONE / mag); + + // Step from minRadius to maxRadius in both directions of the gradient + for (int k1 = 0; k1 < 2; ++k1) + { + int x1 = x0 + minRadius * sx; + int y1 = y0 + minRadius * sy; + + for (int r = minRadius; r <= maxRadius; x1 += sx, y1 += sy, ++r) + { + const int x2 = x1 >> SHIFT; + const int y2 = y1 >> SHIFT; + + if (x2 < 0 || x2 >= width || y2 < 0 || y2 >= height) + break; + + ::atomicAdd(accum.ptr(y2 + 1) + x2 + 1, 1); + } + + sx = -sx; + sy = -sy; + } + } + + void circlesAccumCenters_gpu(const unsigned int* list, int count, PtrStepi dx, PtrStepi dy, PtrStepSzi accum, int minRadius, int maxRadius, float idp) + { + const dim3 block(256); + const dim3 grid(divUp(count, block.x)); + + cudaSafeCall( cudaFuncSetCacheConfig(circlesAccumCenters, cudaFuncCachePreferL1) ); + + circlesAccumCenters<<>>(list, count, dx, dy, accum, accum.cols - 2, accum.rows - 2, minRadius, maxRadius, idp); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + } + + //////////////////////////////////////////////////////////////////////// + // buildCentersList + + __global__ void buildCentersList(const PtrStepSzi accum, unsigned int* centers, const int threshold) + { + const int x = blockIdx.x * blockDim.x + threadIdx.x; + const int y = blockIdx.y * blockDim.y + threadIdx.y; + + if (x < accum.cols - 2 && y < accum.rows - 2) + { + const int top = accum(y, x + 1); + + const int left = accum(y + 1, x); + const int cur = accum(y + 1, x + 1); + const int right = accum(y + 1, x + 2); + + const int bottom = accum(y + 2, x + 1); + + if (cur > threshold && cur > top && cur >= bottom && cur > left && cur >= right) + { + const unsigned int val = (y << 16) | x; + const int idx = ::atomicAdd(&g_counter, 1); + centers[idx] = val; + } + } + } + + int buildCentersList_gpu(PtrStepSzi accum, unsigned int* centers, int threshold) + { + void* counterPtr; + cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); + + cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); + + const dim3 block(32, 8); + const dim3 grid(divUp(accum.cols - 2, block.x), divUp(accum.rows - 2, block.y)); + + cudaSafeCall( cudaFuncSetCacheConfig(buildCentersList, cudaFuncCachePreferL1) ); + + buildCentersList<<>>(accum, centers, threshold); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + + int totalCount; + cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); + + return totalCount; + } + + //////////////////////////////////////////////////////////////////////// + // circlesAccumRadius + + __global__ void circlesAccumRadius(const unsigned int* centers, const unsigned int* list, const int count, + float3* circles, const int maxCircles, const float dp, + const int minRadius, const int maxRadius, const int histSize, const int threshold) + { + int* smem = DynamicSharedMem(); + + for (int i = threadIdx.x; i < histSize + 2; i += blockDim.x) + smem[i] = 0; + __syncthreads(); + + unsigned int val = centers[blockIdx.x]; + + float cx = (val & 0xFFFF); + float cy = (val >> 16) & 0xFFFF; + + cx = (cx + 0.5f) * dp; + cy = (cy + 0.5f) * dp; + + for (int i = threadIdx.x; i < count; i += blockDim.x) + { + val = list[i]; + + const int x = (val & 0xFFFF); + const int y = (val >> 16) & 0xFFFF; + + const float rad = ::sqrtf((cx - x) * (cx - x) + (cy - y) * (cy - y)); + if (rad >= minRadius && rad <= maxRadius) + { + const int r = __float2int_rn(rad - minRadius); + + Emulation::smem::atomicAdd(&smem[r + 1], 1); + } + } + + __syncthreads(); + + for (int i = threadIdx.x; i < histSize; i += blockDim.x) + { + const int curVotes = smem[i + 1]; + + if (curVotes >= threshold && curVotes > smem[i] && curVotes >= smem[i + 2]) + { + const int ind = ::atomicAdd(&g_counter, 1); + if (ind < maxCircles) + circles[ind] = make_float3(cx, cy, i + minRadius); + } + } + } + + int circlesAccumRadius_gpu(const unsigned int* centers, int centersCount, const unsigned int* list, int count, + float3* circles, int maxCircles, float dp, int minRadius, int maxRadius, int threshold, bool has20) + { + void* counterPtr; + cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); + + cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); + + const dim3 block(has20 ? 1024 : 512); + const dim3 grid(centersCount); + + const int histSize = maxRadius - minRadius + 1; + size_t smemSize = (histSize + 2) * sizeof(int); + + circlesAccumRadius<<>>(centers, list, count, circles, maxCircles, dp, minRadius, maxRadius, histSize, threshold); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + + int totalCount; + cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); + + totalCount = ::min(totalCount, maxCircles); + + return totalCount; + } + } +}}} + + +#endif /* CUDA_DISABLER */ diff --git a/modules/gpuimgproc/src/cuda/hough_lines.cu b/modules/gpuimgproc/src/cuda/hough_lines.cu new file mode 100644 index 0000000000..0cee0a43d2 --- /dev/null +++ b/modules/gpuimgproc/src/cuda/hough_lines.cu @@ -0,0 +1,212 @@ +/*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*/ + +#if !defined CUDA_DISABLER + +#include +#include + +#include "opencv2/core/cuda/common.hpp" +#include "opencv2/core/cuda/emulation.hpp" +#include "opencv2/core/cuda/dynamic_smem.hpp" + +namespace cv { namespace gpu { namespace cudev +{ + namespace hough_lines + { + __device__ int g_counter; + + //////////////////////////////////////////////////////////////////////// + // linesAccum + + __global__ void linesAccumGlobal(const unsigned int* list, const int count, PtrStepi accum, const float irho, const float theta, const int numrho) + { + const int n = blockIdx.x; + const float ang = n * theta; + + float sinVal; + float cosVal; + sincosf(ang, &sinVal, &cosVal); + sinVal *= irho; + cosVal *= irho; + + const int shift = (numrho - 1) / 2; + + int* accumRow = accum.ptr(n + 1); + for (int i = threadIdx.x; i < count; i += blockDim.x) + { + const unsigned int val = list[i]; + + const int x = (val & 0xFFFF); + const int y = (val >> 16) & 0xFFFF; + + int r = __float2int_rn(x * cosVal + y * sinVal); + r += shift; + + ::atomicAdd(accumRow + r + 1, 1); + } + } + + __global__ void linesAccumShared(const unsigned int* list, const int count, PtrStepi accum, const float irho, const float theta, const int numrho) + { + int* smem = DynamicSharedMem(); + + for (int i = threadIdx.x; i < numrho + 1; i += blockDim.x) + smem[i] = 0; + + __syncthreads(); + + const int n = blockIdx.x; + const float ang = n * theta; + + float sinVal; + float cosVal; + sincosf(ang, &sinVal, &cosVal); + sinVal *= irho; + cosVal *= irho; + + const int shift = (numrho - 1) / 2; + + for (int i = threadIdx.x; i < count; i += blockDim.x) + { + const unsigned int val = list[i]; + + const int x = (val & 0xFFFF); + const int y = (val >> 16) & 0xFFFF; + + int r = __float2int_rn(x * cosVal + y * sinVal); + r += shift; + + Emulation::smem::atomicAdd(&smem[r + 1], 1); + } + + __syncthreads(); + + int* accumRow = accum.ptr(n + 1); + for (int i = threadIdx.x; i < numrho + 1; i += blockDim.x) + accumRow[i] = smem[i]; + } + + void linesAccum_gpu(const unsigned int* list, int count, PtrStepSzi accum, float rho, float theta, size_t sharedMemPerBlock, bool has20) + { + const dim3 block(has20 ? 1024 : 512); + const dim3 grid(accum.rows - 2); + + size_t smemSize = (accum.cols - 1) * sizeof(int); + + if (smemSize < sharedMemPerBlock - 1000) + linesAccumShared<<>>(list, count, accum, 1.0f / rho, theta, accum.cols - 2); + else + linesAccumGlobal<<>>(list, count, accum, 1.0f / rho, theta, accum.cols - 2); + + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + } + + //////////////////////////////////////////////////////////////////////// + // linesGetResult + + __global__ void linesGetResult(const PtrStepSzi accum, float2* out, int* votes, const int maxSize, const float rho, const float theta, const int threshold, const int numrho) + { + const int r = blockIdx.x * blockDim.x + threadIdx.x; + const int n = blockIdx.y * blockDim.y + threadIdx.y; + + if (r >= accum.cols - 2 || n >= accum.rows - 2) + return; + + const int curVotes = accum(n + 1, r + 1); + + if (curVotes > threshold && + curVotes > accum(n + 1, r) && + curVotes >= accum(n + 1, r + 2) && + curVotes > accum(n, r + 1) && + curVotes >= accum(n + 2, r + 1)) + { + const float radius = (r - (numrho - 1) * 0.5f) * rho; + const float angle = n * theta; + + const int ind = ::atomicAdd(&g_counter, 1); + if (ind < maxSize) + { + out[ind] = make_float2(radius, angle); + votes[ind] = curVotes; + } + } + } + + int linesGetResult_gpu(PtrStepSzi accum, float2* out, int* votes, int maxSize, float rho, float theta, int threshold, bool doSort) + { + void* counterPtr; + cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); + + cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); + + const dim3 block(32, 8); + const dim3 grid(divUp(accum.cols - 2, block.x), divUp(accum.rows - 2, block.y)); + + cudaSafeCall( cudaFuncSetCacheConfig(linesGetResult, cudaFuncCachePreferL1) ); + + linesGetResult<<>>(accum, out, votes, maxSize, rho, theta, threshold, accum.cols - 2); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + + int totalCount; + cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); + + totalCount = ::min(totalCount, maxSize); + + if (doSort && totalCount > 0) + { + thrust::device_ptr outPtr(out); + thrust::device_ptr votesPtr(votes); + thrust::sort_by_key(votesPtr, votesPtr + totalCount, outPtr, thrust::greater()); + } + + return totalCount; + } + } +}}} + + +#endif /* CUDA_DISABLER */ diff --git a/modules/gpuimgproc/src/cuda/hough_segments.cu b/modules/gpuimgproc/src/cuda/hough_segments.cu new file mode 100644 index 0000000000..e420449fae --- /dev/null +++ b/modules/gpuimgproc/src/cuda/hough_segments.cu @@ -0,0 +1,249 @@ +/*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*/ + +#if !defined CUDA_DISABLER + +#include "opencv2/core/cuda/common.hpp" +#include "opencv2/core/cuda/vec_math.hpp" + +namespace cv { namespace gpu { namespace cudev +{ + namespace hough_segments + { + __device__ int g_counter; + + texture tex_mask(false, cudaFilterModePoint, cudaAddressModeClamp); + + __global__ void houghLinesProbabilistic(const PtrStepSzi accum, + int4* out, const int maxSize, + const float rho, const float theta, + const int lineGap, const int lineLength, + const int rows, const int cols) + { + const int r = blockIdx.x * blockDim.x + threadIdx.x; + const int n = blockIdx.y * blockDim.y + threadIdx.y; + + if (r >= accum.cols - 2 || n >= accum.rows - 2) + return; + + const int curVotes = accum(n + 1, r + 1); + + if (curVotes >= lineLength && + curVotes > accum(n, r) && + curVotes > accum(n, r + 1) && + curVotes > accum(n, r + 2) && + curVotes > accum(n + 1, r) && + curVotes > accum(n + 1, r + 2) && + curVotes > accum(n + 2, r) && + curVotes > accum(n + 2, r + 1) && + curVotes > accum(n + 2, r + 2)) + { + const float radius = (r - (accum.cols - 2 - 1) * 0.5f) * rho; + const float angle = n * theta; + + float cosa; + float sina; + sincosf(angle, &sina, &cosa); + + float2 p0 = make_float2(cosa * radius, sina * radius); + float2 dir = make_float2(-sina, cosa); + + float2 pb[4] = {make_float2(-1, -1), make_float2(-1, -1), make_float2(-1, -1), make_float2(-1, -1)}; + float a; + + if (dir.x != 0) + { + a = -p0.x / dir.x; + pb[0].x = 0; + pb[0].y = p0.y + a * dir.y; + + a = (cols - 1 - p0.x) / dir.x; + pb[1].x = cols - 1; + pb[1].y = p0.y + a * dir.y; + } + if (dir.y != 0) + { + a = -p0.y / dir.y; + pb[2].x = p0.x + a * dir.x; + pb[2].y = 0; + + a = (rows - 1 - p0.y) / dir.y; + pb[3].x = p0.x + a * dir.x; + pb[3].y = rows - 1; + } + + if (pb[0].x == 0 && (pb[0].y >= 0 && pb[0].y < rows)) + { + p0 = pb[0]; + if (dir.x < 0) + dir = -dir; + } + else if (pb[1].x == cols - 1 && (pb[0].y >= 0 && pb[0].y < rows)) + { + p0 = pb[1]; + if (dir.x > 0) + dir = -dir; + } + else if (pb[2].y == 0 && (pb[2].x >= 0 && pb[2].x < cols)) + { + p0 = pb[2]; + if (dir.y < 0) + dir = -dir; + } + else if (pb[3].y == rows - 1 && (pb[3].x >= 0 && pb[3].x < cols)) + { + p0 = pb[3]; + if (dir.y > 0) + dir = -dir; + } + + float2 d; + if (::fabsf(dir.x) > ::fabsf(dir.y)) + { + d.x = dir.x > 0 ? 1 : -1; + d.y = dir.y / ::fabsf(dir.x); + } + else + { + d.x = dir.x / ::fabsf(dir.y); + d.y = dir.y > 0 ? 1 : -1; + } + + float2 line_end[2]; + int gap; + bool inLine = false; + + float2 p1 = p0; + if (p1.x < 0 || p1.x >= cols || p1.y < 0 || p1.y >= rows) + return; + + for (;;) + { + if (tex2D(tex_mask, p1.x, p1.y)) + { + gap = 0; + + if (!inLine) + { + line_end[0] = p1; + line_end[1] = p1; + inLine = true; + } + else + { + line_end[1] = p1; + } + } + else if (inLine) + { + if (++gap > lineGap) + { + bool good_line = ::abs(line_end[1].x - line_end[0].x) >= lineLength || + ::abs(line_end[1].y - line_end[0].y) >= lineLength; + + if (good_line) + { + const int ind = ::atomicAdd(&g_counter, 1); + if (ind < maxSize) + out[ind] = make_int4(line_end[0].x, line_end[0].y, line_end[1].x, line_end[1].y); + } + + gap = 0; + inLine = false; + } + } + + p1 = p1 + d; + if (p1.x < 0 || p1.x >= cols || p1.y < 0 || p1.y >= rows) + { + if (inLine) + { + bool good_line = ::abs(line_end[1].x - line_end[0].x) >= lineLength || + ::abs(line_end[1].y - line_end[0].y) >= lineLength; + + if (good_line) + { + const int ind = ::atomicAdd(&g_counter, 1); + if (ind < maxSize) + out[ind] = make_int4(line_end[0].x, line_end[0].y, line_end[1].x, line_end[1].y); + } + + } + break; + } + } + } + } + + int houghLinesProbabilistic_gpu(PtrStepSzb mask, PtrStepSzi accum, int4* out, int maxSize, float rho, float theta, int lineGap, int lineLength) + { + void* counterPtr; + cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) ); + + cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) ); + + const dim3 block(32, 8); + const dim3 grid(divUp(accum.cols - 2, block.x), divUp(accum.rows - 2, block.y)); + + bindTexture(&tex_mask, mask); + + houghLinesProbabilistic<<>>(accum, + out, maxSize, + rho, theta, + lineGap, lineLength, + mask.rows, mask.cols); + cudaSafeCall( cudaGetLastError() ); + + cudaSafeCall( cudaDeviceSynchronize() ); + + int totalCount; + cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) ); + + totalCount = ::min(totalCount, maxSize); + + return totalCount; + } + } +}}} + + +#endif /* CUDA_DISABLER */ diff --git a/modules/gpuimgproc/src/hough.cpp b/modules/gpuimgproc/src/generalized_hough.cpp similarity index 58% rename from modules/gpuimgproc/src/hough.cpp rename to modules/gpuimgproc/src/generalized_hough.cpp index 90b0261bd7..1bc0574b13 100644 --- a/modules/gpuimgproc/src/hough.cpp +++ b/modules/gpuimgproc/src/generalized_hough.cpp @@ -45,539 +45,15 @@ using namespace cv; using namespace cv::gpu; -#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) - -Ptr cv::gpu::createHoughLinesDetector(float, float, int, bool, int) { throw_no_cuda(); return Ptr(); } - -Ptr cv::gpu::createHoughSegmentDetector(float, float, int, int, int) { throw_no_cuda(); return Ptr(); } - -Ptr cv::gpu::createHoughCirclesDetector(float, float, int, int, int, int, int) { throw_no_cuda(); return Ptr(); } +#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) || !defined(HAVE_OPENCV_GPUARITHM) Ptr cv::gpu::GeneralizedHough::create(int) { throw_no_cuda(); return Ptr(); } #else /* !defined (HAVE_CUDA) */ -#include "opencv2/core/utility.hpp" - namespace cv { namespace gpu { namespace cudev { - namespace hough - { - int buildPointList_gpu(PtrStepSzb src, unsigned int* list); - } -}}} - -////////////////////////////////////////////////////////// -// HoughLinesDetector - -namespace cv { namespace gpu { namespace cudev -{ - namespace hough - { - void linesAccum_gpu(const unsigned int* list, int count, PtrStepSzi accum, float rho, float theta, size_t sharedMemPerBlock, bool has20); - int linesGetResult_gpu(PtrStepSzi accum, float2* out, int* votes, int maxSize, float rho, float theta, int threshold, bool doSort); - } -}}} - -namespace -{ - class HoughLinesDetectorImpl : public HoughLinesDetector - { - public: - HoughLinesDetectorImpl(float rho, float theta, int threshold, bool doSort, int maxLines) : - rho_(rho), theta_(theta), threshold_(threshold), doSort_(doSort), maxLines_(maxLines) - { - } - - void detect(InputArray src, OutputArray lines); - void downloadResults(InputArray d_lines, OutputArray h_lines, OutputArray h_votes = noArray()); - - void setRho(float rho) { rho_ = rho; } - float getRho() const { return rho_; } - - void setTheta(float theta) { theta_ = theta; } - float getTheta() const { return theta_; } - - void setThreshold(int threshold) { threshold_ = threshold; } - int getThreshold() const { return threshold_; } - - void setDoSort(bool doSort) { doSort_ = doSort; } - bool getDoSort() const { return doSort_; } - - void setMaxLines(int maxLines) { maxLines_ = maxLines; } - int getMaxLines() const { return maxLines_; } - - void write(FileStorage& fs) const - { - fs << "name" << "HoughLinesDetector_GPU" - << "rho" << rho_ - << "theta" << theta_ - << "threshold" << threshold_ - << "doSort" << doSort_ - << "maxLines" << maxLines_; - } - - void read(const FileNode& fn) - { - CV_Assert( String(fn["name"]) == "HoughLinesDetector_GPU" ); - rho_ = (float)fn["rho"]; - theta_ = (float)fn["theta"]; - threshold_ = (int)fn["threshold"]; - doSort_ = (int)fn["doSort"] != 0; - maxLines_ = (int)fn["maxLines"]; - } - - private: - float rho_; - float theta_; - int threshold_; - bool doSort_; - int maxLines_; - - GpuMat accum_; - GpuMat list_; - GpuMat result_; - }; - - void HoughLinesDetectorImpl::detect(InputArray _src, OutputArray lines) - { - using namespace cv::gpu::cudev::hough; - - GpuMat src = _src.getGpuMat(); - - CV_Assert( src.type() == CV_8UC1 ); - CV_Assert( src.cols < std::numeric_limits::max() ); - CV_Assert( src.rows < std::numeric_limits::max() ); - - ensureSizeIsEnough(1, src.size().area(), CV_32SC1, list_); - unsigned int* srcPoints = list_.ptr(); - - const int pointsCount = buildPointList_gpu(src, srcPoints); - if (pointsCount == 0) - { - lines.release(); - return; - } - - const int numangle = cvRound(CV_PI / theta_); - const int numrho = cvRound(((src.cols + src.rows) * 2 + 1) / rho_); - CV_Assert( numangle > 0 && numrho > 0 ); - - ensureSizeIsEnough(numangle + 2, numrho + 2, CV_32SC1, accum_); - accum_.setTo(Scalar::all(0)); - - DeviceInfo devInfo; - linesAccum_gpu(srcPoints, pointsCount, accum_, rho_, theta_, devInfo.sharedMemPerBlock(), devInfo.supports(FEATURE_SET_COMPUTE_20)); - - ensureSizeIsEnough(2, maxLines_, CV_32FC2, result_); - - int linesCount = linesGetResult_gpu(accum_, result_.ptr(0), result_.ptr(1), maxLines_, rho_, theta_, threshold_, doSort_); - - if (linesCount == 0) - { - lines.release(); - return; - } - - result_.cols = linesCount; - result_.copyTo(lines); - } - - void HoughLinesDetectorImpl::downloadResults(InputArray _d_lines, OutputArray h_lines, OutputArray h_votes) - { - GpuMat d_lines = _d_lines.getGpuMat(); - - if (d_lines.empty()) - { - h_lines.release(); - if (h_votes.needed()) - h_votes.release(); - return; - } - - CV_Assert( d_lines.rows == 2 && d_lines.type() == CV_32FC2 ); - - d_lines.row(0).download(h_lines); - - if (h_votes.needed()) - { - GpuMat d_votes(1, d_lines.cols, CV_32SC1, d_lines.ptr(1)); - d_votes.download(h_votes); - } - } -} - -Ptr cv::gpu::createHoughLinesDetector(float rho, float theta, int threshold, bool doSort, int maxLines) -{ - return new HoughLinesDetectorImpl(rho, theta, threshold, doSort, maxLines); -} - -////////////////////////////////////////////////////////// -// HoughLinesP - -namespace cv { namespace gpu { namespace cudev -{ - namespace hough - { - int houghLinesProbabilistic_gpu(PtrStepSzb mask, PtrStepSzi accum, int4* out, int maxSize, float rho, float theta, int lineGap, int lineLength); - } -}}} - -namespace -{ - class PHoughLinesDetectorImpl : public HoughSegmentDetector - { - public: - PHoughLinesDetectorImpl(float rho, float theta, int minLineLength, int maxLineGap, int maxLines) : - rho_(rho), theta_(theta), minLineLength_(minLineLength), maxLineGap_(maxLineGap), maxLines_(maxLines) - { - } - - void detect(InputArray src, OutputArray lines); - - void setRho(float rho) { rho_ = rho; } - float getRho() const { return rho_; } - - void setTheta(float theta) { theta_ = theta; } - float getTheta() const { return theta_; } - - void setMinLineLength(int minLineLength) { minLineLength_ = minLineLength; } - int getMinLineLength() const { return minLineLength_; } - - void setMaxLineGap(int maxLineGap) { maxLineGap_ = maxLineGap; } - int getMaxLineGap() const { return maxLineGap_; } - - void setMaxLines(int maxLines) { maxLines_ = maxLines; } - int getMaxLines() const { return maxLines_; } - - void write(FileStorage& fs) const - { - fs << "name" << "PHoughLinesDetector_GPU" - << "rho" << rho_ - << "theta" << theta_ - << "minLineLength" << minLineLength_ - << "maxLineGap" << maxLineGap_ - << "maxLines" << maxLines_; - } - - void read(const FileNode& fn) - { - CV_Assert( String(fn["name"]) == "PHoughLinesDetector_GPU" ); - rho_ = (float)fn["rho"]; - theta_ = (float)fn["theta"]; - minLineLength_ = (int)fn["minLineLength"]; - maxLineGap_ = (int)fn["maxLineGap"]; - maxLines_ = (int)fn["maxLines"]; - } - - private: - float rho_; - float theta_; - int minLineLength_; - int maxLineGap_; - int maxLines_; - - GpuMat accum_; - GpuMat list_; - GpuMat result_; - }; - - void PHoughLinesDetectorImpl::detect(InputArray _src, OutputArray lines) - { - using namespace cv::gpu::cudev::hough; - - GpuMat src = _src.getGpuMat(); - - CV_Assert( src.type() == CV_8UC1 ); - CV_Assert( src.cols < std::numeric_limits::max() ); - CV_Assert( src.rows < std::numeric_limits::max() ); - - ensureSizeIsEnough(1, src.size().area(), CV_32SC1, list_); - unsigned int* srcPoints = list_.ptr(); - - const int pointsCount = buildPointList_gpu(src, srcPoints); - if (pointsCount == 0) - { - lines.release(); - return; - } - - const int numangle = cvRound(CV_PI / theta_); - const int numrho = cvRound(((src.cols + src.rows) * 2 + 1) / rho_); - CV_Assert( numangle > 0 && numrho > 0 ); - - ensureSizeIsEnough(numangle + 2, numrho + 2, CV_32SC1, accum_); - accum_.setTo(Scalar::all(0)); - - DeviceInfo devInfo; - linesAccum_gpu(srcPoints, pointsCount, accum_, rho_, theta_, devInfo.sharedMemPerBlock(), devInfo.supports(FEATURE_SET_COMPUTE_20)); - - ensureSizeIsEnough(1, maxLines_, CV_32SC4, result_); - - int linesCount = houghLinesProbabilistic_gpu(src, accum_, result_.ptr(), maxLines_, rho_, theta_, maxLineGap_, minLineLength_); - - if (linesCount == 0) - { - lines.release(); - return; - } - - result_.cols = linesCount; - result_.copyTo(lines); - } -} - -Ptr cv::gpu::createHoughSegmentDetector(float rho, float theta, int minLineLength, int maxLineGap, int maxLines) -{ - return new PHoughLinesDetectorImpl(rho, theta, minLineLength, maxLineGap, maxLines); -} - -////////////////////////////////////////////////////////// -// HoughCircles - -namespace cv { namespace gpu { namespace cudev -{ - namespace hough - { - void circlesAccumCenters_gpu(const unsigned int* list, int count, PtrStepi dx, PtrStepi dy, PtrStepSzi accum, int minRadius, int maxRadius, float idp); - int buildCentersList_gpu(PtrStepSzi accum, unsigned int* centers, int threshold); - int circlesAccumRadius_gpu(const unsigned int* centers, int centersCount, const unsigned int* list, int count, - float3* circles, int maxCircles, float dp, int minRadius, int maxRadius, int threshold, bool has20); - } -}}} - -namespace -{ - class HoughCirclesDetectorImpl : public HoughCirclesDetector - { - public: - HoughCirclesDetectorImpl(float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles); - - void detect(InputArray src, OutputArray circles); - - void setDp(float dp) { dp_ = dp; } - float getDp() const { return dp_; } - - void setMinDist(float minDist) { minDist_ = minDist; } - float getMinDist() const { return minDist_; } - - void setCannyThreshold(int cannyThreshold) { cannyThreshold_ = cannyThreshold; } - int getCannyThreshold() const { return cannyThreshold_; } - - void setVotesThreshold(int votesThreshold) { votesThreshold_ = votesThreshold; } - int getVotesThreshold() const { return votesThreshold_; } - - void setMinRadius(int minRadius) { minRadius_ = minRadius; } - int getMinRadius() const { return minRadius_; } - - void setMaxRadius(int maxRadius) { maxRadius_ = maxRadius; } - int getMaxRadius() const { return maxRadius_; } - - void setMaxCircles(int maxCircles) { maxCircles_ = maxCircles; } - int getMaxCircles() const { return maxCircles_; } - - void write(FileStorage& fs) const - { - fs << "name" << "HoughCirclesDetector_GPU" - << "dp" << dp_ - << "minDist" << minDist_ - << "cannyThreshold" << cannyThreshold_ - << "votesThreshold" << votesThreshold_ - << "minRadius" << minRadius_ - << "maxRadius" << maxRadius_ - << "maxCircles" << maxCircles_; - } - - void read(const FileNode& fn) - { - CV_Assert( String(fn["name"]) == "HoughCirclesDetector_GPU" ); - dp_ = (float)fn["dp"]; - minDist_ = (float)fn["minDist"]; - cannyThreshold_ = (int)fn["cannyThreshold"]; - votesThreshold_ = (int)fn["votesThreshold"]; - minRadius_ = (int)fn["minRadius"]; - maxRadius_ = (int)fn["maxRadius"]; - maxCircles_ = (int)fn["maxCircles"]; - } - - private: - float dp_; - float minDist_; - int cannyThreshold_; - int votesThreshold_; - int minRadius_; - int maxRadius_; - int maxCircles_; - - GpuMat dx_, dy_; - GpuMat edges_; - GpuMat accum_; - GpuMat list_; - GpuMat result_; - Ptr filterDx_; - Ptr filterDy_; - Ptr canny_; - }; - - HoughCirclesDetectorImpl::HoughCirclesDetectorImpl(float dp, float minDist, int cannyThreshold, int votesThreshold, - int minRadius, int maxRadius, int maxCircles) : - dp_(dp), minDist_(minDist), cannyThreshold_(cannyThreshold), votesThreshold_(votesThreshold), - minRadius_(minRadius), maxRadius_(maxRadius), maxCircles_(maxCircles) - { - canny_ = gpu::createCannyEdgeDetector(std::max(cannyThreshold_ / 2, 1), cannyThreshold_); - - filterDx_ = gpu::createSobelFilter(CV_8UC1, CV_32S, 1, 0); - filterDy_ = gpu::createSobelFilter(CV_8UC1, CV_32S, 0, 1); - } - - void HoughCirclesDetectorImpl::detect(InputArray _src, OutputArray circles) - { - using namespace cv::gpu::cudev::hough; - - GpuMat src = _src.getGpuMat(); - - CV_Assert( src.type() == CV_8UC1 ); - CV_Assert( src.cols < std::numeric_limits::max() ); - CV_Assert( src.rows < std::numeric_limits::max() ); - CV_Assert( dp_ > 0 ); - CV_Assert( minRadius_ > 0 && maxRadius_ > minRadius_ ); - CV_Assert( cannyThreshold_ > 0 ); - CV_Assert( votesThreshold_ > 0 ); - CV_Assert( maxCircles_ > 0 ); - - const float idp = 1.0f / dp_; - - filterDx_->apply(src, dx_); - filterDy_->apply(src, dy_); - - canny_->setLowThreshold(std::max(cannyThreshold_ / 2, 1)); - canny_->setHighThreshold(cannyThreshold_); - - canny_->detect(dx_, dy_, edges_); - - ensureSizeIsEnough(2, src.size().area(), CV_32SC1, list_); - unsigned int* srcPoints = list_.ptr(0); - unsigned int* centers = list_.ptr(1); - - const int pointsCount = buildPointList_gpu(edges_, srcPoints); - if (pointsCount == 0) - { - circles.release(); - return; - } - - ensureSizeIsEnough(cvCeil(src.rows * idp) + 2, cvCeil(src.cols * idp) + 2, CV_32SC1, accum_); - accum_.setTo(Scalar::all(0)); - - circlesAccumCenters_gpu(srcPoints, pointsCount, dx_, dy_, accum_, minRadius_, maxRadius_, idp); - - int centersCount = buildCentersList_gpu(accum_, centers, votesThreshold_); - if (centersCount == 0) - { - circles.release(); - return; - } - - if (minDist_ > 1) - { - AutoBuffer oldBuf_(centersCount); - AutoBuffer newBuf_(centersCount); - int newCount = 0; - - ushort2* oldBuf = oldBuf_; - ushort2* newBuf = newBuf_; - - cudaSafeCall( cudaMemcpy(oldBuf, centers, centersCount * sizeof(ushort2), cudaMemcpyDeviceToHost) ); - - const int cellSize = cvRound(minDist_); - const int gridWidth = (src.cols + cellSize - 1) / cellSize; - const int gridHeight = (src.rows + cellSize - 1) / cellSize; - - std::vector< std::vector > grid(gridWidth * gridHeight); - - const float minDist2 = minDist_ * minDist_; - - for (int i = 0; i < centersCount; ++i) - { - ushort2 p = oldBuf[i]; - - bool good = true; - - int xCell = static_cast(p.x / cellSize); - int yCell = static_cast(p.y / cellSize); - - int x1 = xCell - 1; - int y1 = yCell - 1; - int x2 = xCell + 1; - int y2 = yCell + 1; - - // boundary check - x1 = std::max(0, x1); - y1 = std::max(0, y1); - x2 = std::min(gridWidth - 1, x2); - y2 = std::min(gridHeight - 1, y2); - - for (int yy = y1; yy <= y2; ++yy) - { - for (int xx = x1; xx <= x2; ++xx) - { - std::vector& m = grid[yy * gridWidth + xx]; - - for(size_t j = 0; j < m.size(); ++j) - { - float dx = (float)(p.x - m[j].x); - float dy = (float)(p.y - m[j].y); - - if (dx * dx + dy * dy < minDist2) - { - good = false; - goto break_out; - } - } - } - } - - break_out: - - if(good) - { - grid[yCell * gridWidth + xCell].push_back(p); - - newBuf[newCount++] = p; - } - } - - cudaSafeCall( cudaMemcpy(centers, newBuf, newCount * sizeof(unsigned int), cudaMemcpyHostToDevice) ); - centersCount = newCount; - } - - ensureSizeIsEnough(1, maxCircles_, CV_32FC3, result_); - - int circlesCount = circlesAccumRadius_gpu(centers, centersCount, srcPoints, pointsCount, result_.ptr(), maxCircles_, - dp_, minRadius_, maxRadius_, votesThreshold_, deviceSupports(FEATURE_SET_COMPUTE_20)); - - if (circlesCount == 0) - { - circles.release(); - return; - } - - result_.cols = circlesCount; - result_.copyTo(circles); - } -} - -Ptr cv::gpu::createHoughCirclesDetector(float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles) -{ - return new HoughCirclesDetectorImpl(dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius, maxCircles); -} - -////////////////////////////////////////////////////////// -// GeneralizedHough - -namespace cv { namespace gpu { namespace cudev -{ - namespace hough + namespace ght { template int buildEdgePointList_gpu(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList); @@ -585,52 +61,52 @@ namespace cv { namespace gpu { namespace cudev PtrStepSz r_table, int* r_sizes, short2 templCenter, int levels); - void GHT_Ballard_Pos_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, - PtrStepSz r_table, const int* r_sizes, - PtrStepSzi hist, - float dp, int levels); - int GHT_Ballard_Pos_findPosInHist_gpu(PtrStepSzi hist, float4* out, int3* votes, int maxSize, float dp, int threshold); - - void GHT_Ballard_PosScale_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, - PtrStepSz r_table, const int* r_sizes, - PtrStepi hist, int rows, int cols, - float minScale, float scaleStep, int scaleRange, - float dp, int levels); - int GHT_Ballard_PosScale_findPosInHist_gpu(PtrStepi hist, int rows, int cols, int scaleRange, float4* out, int3* votes, int maxSize, - float minScale, float scaleStep, float dp, int threshold); - - void GHT_Ballard_PosRotation_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, - PtrStepSz r_table, const int* r_sizes, - PtrStepi hist, int rows, int cols, - float minAngle, float angleStep, int angleRange, - float dp, int levels); - int GHT_Ballard_PosRotation_findPosInHist_gpu(PtrStepi hist, int rows, int cols, int angleRange, float4* out, int3* votes, int maxSize, - float minAngle, float angleStep, float dp, int threshold); - - void GHT_Guil_Full_setTemplFeatures(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2); - void GHT_Guil_Full_setImageFeatures(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2); - void GHT_Guil_Full_buildTemplFeatureList_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, - int* sizes, int maxSize, - float xi, float angleEpsilon, int levels, - float2 center, float maxDist); - void GHT_Guil_Full_buildImageFeatureList_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, - int* sizes, int maxSize, - float xi, float angleEpsilon, int levels, - float2 center, float maxDist); - void GHT_Guil_Full_calcOHist_gpu(const int* templSizes, const int* imageSizes, int* OHist, - float minAngle, float maxAngle, float angleStep, int angleRange, - int levels, int tMaxSize); - void GHT_Guil_Full_calcSHist_gpu(const int* templSizes, const int* imageSizes, int* SHist, - float angle, float angleEpsilon, - float minScale, float maxScale, float iScaleStep, int scaleRange, - int levels, int tMaxSize); - void GHT_Guil_Full_calcPHist_gpu(const int* templSizes, const int* imageSizes, PtrStepSzi PHist, - float angle, float angleEpsilon, float scale, - float dp, - int levels, int tMaxSize); - int GHT_Guil_Full_findPosInHist_gpu(PtrStepSzi hist, float4* out, int3* votes, int curSize, int maxSize, - float angle, int angleVotes, float scale, int scaleVotes, - float dp, int threshold); + void Ballard_Pos_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, + PtrStepSz r_table, const int* r_sizes, + PtrStepSzi hist, + float dp, int levels); + int Ballard_Pos_findPosInHist_gpu(PtrStepSzi hist, float4* out, int3* votes, int maxSize, float dp, int threshold); + + void Ballard_PosScale_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, + PtrStepSz r_table, const int* r_sizes, + PtrStepi hist, int rows, int cols, + float minScale, float scaleStep, int scaleRange, + float dp, int levels); + int Ballard_PosScale_findPosInHist_gpu(PtrStepi hist, int rows, int cols, int scaleRange, float4* out, int3* votes, int maxSize, + float minScale, float scaleStep, float dp, int threshold); + + void Ballard_PosRotation_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, + PtrStepSz r_table, const int* r_sizes, + PtrStepi hist, int rows, int cols, + float minAngle, float angleStep, int angleRange, + float dp, int levels); + int Ballard_PosRotation_findPosInHist_gpu(PtrStepi hist, int rows, int cols, int angleRange, float4* out, int3* votes, int maxSize, + float minAngle, float angleStep, float dp, int threshold); + + void Guil_Full_setTemplFeatures(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2); + void Guil_Full_setImageFeatures(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2); + void Guil_Full_buildTemplFeatureList_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, + int* sizes, int maxSize, + float xi, float angleEpsilon, int levels, + float2 center, float maxDist); + void Guil_Full_buildImageFeatureList_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, + int* sizes, int maxSize, + float xi, float angleEpsilon, int levels, + float2 center, float maxDist); + void Guil_Full_calcOHist_gpu(const int* templSizes, const int* imageSizes, int* OHist, + float minAngle, float maxAngle, float angleStep, int angleRange, + int levels, int tMaxSize); + void Guil_Full_calcSHist_gpu(const int* templSizes, const int* imageSizes, int* SHist, + float angle, float angleEpsilon, + float minScale, float maxScale, float iScaleStep, int scaleRange, + int levels, int tMaxSize); + void Guil_Full_calcPHist_gpu(const int* templSizes, const int* imageSizes, PtrStepSzi PHist, + float angle, float angleEpsilon, float scale, + float dp, + int levels, int tMaxSize); + int Guil_Full_findPosInHist_gpu(PtrStepSzi hist, float4* out, int3* votes, int curSize, int maxSize, + float angle, int angleVotes, float scale, int scaleVotes, + float dp, int threshold); } }}} @@ -889,7 +365,7 @@ namespace void GHT_Pos::buildEdgePointList(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy) { - using namespace cv::gpu::cudev::hough; + using namespace cv::gpu::cudev::ght; typedef int (*func_t)(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList); static const func_t funcs[] = @@ -1077,7 +553,7 @@ namespace void GHT_Ballard_Pos::processTempl() { - using namespace cv::gpu::cudev::hough; + using namespace cv::gpu::cudev::ght; CV_Assert(levels > 0); @@ -1103,7 +579,7 @@ namespace void GHT_Ballard_Pos::calcHist() { - using namespace cv::gpu::cudev::hough; + using namespace cv::gpu::cudev::ght; CV_Assert(levels > 0 && r_table.rows == (levels + 1) && r_sizes.cols == (levels + 1)); CV_Assert(dp > 0.0); @@ -1117,22 +593,22 @@ namespace if (edgePointList.cols > 0) { - GHT_Ballard_Pos_calcHist_gpu(edgePointList.ptr(0), edgePointList.ptr(1), edgePointList.cols, - r_table, r_sizes.ptr(), - hist, - (float)dp, levels); + Ballard_Pos_calcHist_gpu(edgePointList.ptr(0), edgePointList.ptr(1), edgePointList.cols, + r_table, r_sizes.ptr(), + hist, + (float)dp, levels); } } void GHT_Ballard_Pos::findPosInHist() { - using namespace cv::gpu::cudev::hough; + using namespace cv::gpu::cudev::ght; CV_Assert(votesThreshold > 0); ensureSizeIsEnough(2, maxSize, CV_32FC4, outBuf); - posCount = GHT_Ballard_Pos_findPosInHist_gpu(hist, outBuf.ptr(0), outBuf.ptr(1), maxSize, (float)dp, votesThreshold); + posCount = Ballard_Pos_findPosInHist_gpu(hist, outBuf.ptr(0), outBuf.ptr(1), maxSize, (float)dp, votesThreshold); } ///////////////////////////////////// @@ -1181,7 +657,7 @@ namespace void GHT_Ballard_PosScale::calcHist() { - using namespace cv::gpu::cudev::hough; + using namespace cv::gpu::cudev::ght; CV_Assert(levels > 0 && r_table.rows == (levels + 1) && r_sizes.cols == (levels + 1)); CV_Assert(dp > 0.0); @@ -1200,16 +676,16 @@ namespace if (edgePointList.cols > 0) { - GHT_Ballard_PosScale_calcHist_gpu(edgePointList.ptr(0), edgePointList.ptr(1), edgePointList.cols, - r_table, r_sizes.ptr(), - hist, rows, cols, - (float)minScale, (float)scaleStep, scaleRange, (float)dp, levels); + Ballard_PosScale_calcHist_gpu(edgePointList.ptr(0), edgePointList.ptr(1), edgePointList.cols, + r_table, r_sizes.ptr(), + hist, rows, cols, + (float)minScale, (float)scaleStep, scaleRange, (float)dp, levels); } } void GHT_Ballard_PosScale::findPosInHist() { - using namespace cv::gpu::cudev::hough; + using namespace cv::gpu::cudev::ght; CV_Assert(votesThreshold > 0); @@ -1220,7 +696,7 @@ namespace ensureSizeIsEnough(2, maxSize, CV_32FC4, outBuf); - posCount = GHT_Ballard_PosScale_findPosInHist_gpu(hist, rows, cols, scaleRange, outBuf.ptr(0), outBuf.ptr(1), maxSize, (float)minScale, (float)scaleStep, (float)dp, votesThreshold); + posCount = Ballard_PosScale_findPosInHist_gpu(hist, rows, cols, scaleRange, outBuf.ptr(0), outBuf.ptr(1), maxSize, (float)minScale, (float)scaleStep, (float)dp, votesThreshold); } ///////////////////////////////////// @@ -1269,7 +745,7 @@ namespace void GHT_Ballard_PosRotation::calcHist() { - using namespace cv::gpu::cudev::hough; + using namespace cv::gpu::cudev::ght; CV_Assert(levels > 0 && r_table.rows == (levels + 1) && r_sizes.cols == (levels + 1)); CV_Assert(dp > 0.0); @@ -1288,16 +764,16 @@ namespace if (edgePointList.cols > 0) { - GHT_Ballard_PosRotation_calcHist_gpu(edgePointList.ptr(0), edgePointList.ptr(1), edgePointList.cols, - r_table, r_sizes.ptr(), - hist, rows, cols, - (float)minAngle, (float)angleStep, angleRange, (float)dp, levels); + Ballard_PosRotation_calcHist_gpu(edgePointList.ptr(0), edgePointList.ptr(1), edgePointList.cols, + r_table, r_sizes.ptr(), + hist, rows, cols, + (float)minAngle, (float)angleStep, angleRange, (float)dp, levels); } } void GHT_Ballard_PosRotation::findPosInHist() { - using namespace cv::gpu::cudev::hough; + using namespace cv::gpu::cudev::ght; CV_Assert(votesThreshold > 0); @@ -1308,7 +784,7 @@ namespace ensureSizeIsEnough(2, maxSize, CV_32FC4, outBuf); - posCount = GHT_Ballard_PosRotation_findPosInHist_gpu(hist, rows, cols, angleRange, outBuf.ptr(0), outBuf.ptr(1), maxSize, (float)minAngle, (float)angleStep, (float)dp, votesThreshold); + posCount = Ballard_PosRotation_findPosInHist_gpu(hist, rows, cols, angleRange, outBuf.ptr(0), outBuf.ptr(1), maxSize, (float)minAngle, (float)angleStep, (float)dp, votesThreshold); } ///////////////////////////////////////// @@ -1476,10 +952,10 @@ namespace void GHT_Guil_Full::processTempl() { - using namespace cv::gpu::cudev::hough; + using namespace cv::gpu::cudev::ght; buildFeatureList(templEdges, templDx, templDy, templFeatures, - GHT_Guil_Full_setTemplFeatures, GHT_Guil_Full_buildTemplFeatureList_gpu, + Guil_Full_setTemplFeatures, Guil_Full_buildTemplFeatureList_gpu, true, templCenter); h_buf.resize(templFeatures.sizes.cols); @@ -1489,7 +965,7 @@ namespace void GHT_Guil_Full::processImage() { - using namespace cv::gpu::cudev::hough; + using namespace cv::gpu::cudev::ght; CV_Assert(levels > 0); CV_Assert(templFeatures.sizes.cols == levels + 1); @@ -1518,7 +994,7 @@ namespace ensureSizeIsEnough(2, maxSize, CV_32FC4, outBuf); buildFeatureList(imageEdges, imageDx, imageDy, imageFeatures, - GHT_Guil_Full_setImageFeatures, GHT_Guil_Full_buildImageFeatureList_gpu, + Guil_Full_setImageFeatures, Guil_Full_buildImageFeatureList_gpu, false); calcOrientation(); @@ -1601,14 +1077,14 @@ namespace void GHT_Guil_Full::calcOrientation() { - using namespace cv::gpu::cudev::hough; + using namespace cv::gpu::cudev::ght; const double iAngleStep = 1.0 / angleStep; const int angleRange = cvCeil((maxAngle - minAngle) * iAngleStep); hist.setTo(Scalar::all(0)); - GHT_Guil_Full_calcOHist_gpu(templFeatures.sizes.ptr(), imageFeatures.sizes.ptr(0), - hist.ptr(), (float)minAngle, (float)maxAngle, (float)angleStep, angleRange, levels, templFeatures.maxSize); + Guil_Full_calcOHist_gpu(templFeatures.sizes.ptr(), imageFeatures.sizes.ptr(0), hist.ptr(), + (float)minAngle, (float)maxAngle, (float)angleStep, angleRange, levels, templFeatures.maxSize); cudaSafeCall( cudaMemcpy(&h_buf[0], hist.data, h_buf.size() * sizeof(int), cudaMemcpyDeviceToHost) ); angles.clear(); @@ -1625,14 +1101,15 @@ namespace void GHT_Guil_Full::calcScale(double angle) { - using namespace cv::gpu::cudev::hough; + using namespace cv::gpu::cudev::ght; const double iScaleStep = 1.0 / scaleStep; const int scaleRange = cvCeil((maxScale - minScale) * iScaleStep); hist.setTo(Scalar::all(0)); - GHT_Guil_Full_calcSHist_gpu(templFeatures.sizes.ptr(), imageFeatures.sizes.ptr(0), - hist.ptr(), (float)angle, (float)angleEpsilon, (float)minScale, (float)maxScale, (float)iScaleStep, scaleRange, levels, templFeatures.maxSize); + Guil_Full_calcSHist_gpu(templFeatures.sizes.ptr(), imageFeatures.sizes.ptr(0), hist.ptr(), + (float)angle, (float)angleEpsilon, (float)minScale, (float)maxScale, + (float)iScaleStep, scaleRange, levels, templFeatures.maxSize); cudaSafeCall( cudaMemcpy(&h_buf[0], hist.data, h_buf.size() * sizeof(int), cudaMemcpyDeviceToHost) ); scales.clear(); @@ -1649,14 +1126,15 @@ namespace void GHT_Guil_Full::calcPosition(double angle, int angleVotes, double scale, int scaleVotes) { - using namespace cv::gpu::cudev::hough; + using namespace cv::gpu::cudev::ght; hist.setTo(Scalar::all(0)); - GHT_Guil_Full_calcPHist_gpu(templFeatures.sizes.ptr(), imageFeatures.sizes.ptr(0), - hist,(float) (float)angle, (float)angleEpsilon, (float)scale, (float)dp, levels, templFeatures.maxSize); + Guil_Full_calcPHist_gpu(templFeatures.sizes.ptr(), imageFeatures.sizes.ptr(0), hist, + (float)angle, (float)angleEpsilon, (float)scale, (float)dp, levels, templFeatures.maxSize); - posCount = GHT_Guil_Full_findPosInHist_gpu(hist, outBuf.ptr(0), outBuf.ptr(1), - posCount, maxSize, (float)angle, angleVotes, (float)scale, scaleVotes, (float)dp, posThresh); + posCount = Guil_Full_findPosInHist_gpu(hist, outBuf.ptr(0), outBuf.ptr(1), + posCount, maxSize, (float)angle, angleVotes, + (float)scale, scaleVotes, (float)dp, posThresh); } } @@ -1679,10 +1157,11 @@ Ptr cv::gpu::GeneralizedHough::create(int method) case (cv::GeneralizedHough::GHT_POSITION | cv::GeneralizedHough::GHT_SCALE | cv::GeneralizedHough::GHT_ROTATION): CV_Assert( !GHT_Guil_Full_info_auto.name().empty() ); return new GHT_Guil_Full(); - } - CV_Error(Error::StsBadArg, "Unsupported method"); - return Ptr(); + default: + CV_Error(Error::StsBadArg, "Unsupported method"); + return Ptr(); + } } #endif /* !defined (HAVE_CUDA) */ diff --git a/modules/gpuimgproc/src/hough_circles.cpp b/modules/gpuimgproc/src/hough_circles.cpp new file mode 100644 index 0000000000..3f1e771740 --- /dev/null +++ b/modules/gpuimgproc/src/hough_circles.cpp @@ -0,0 +1,297 @@ +/*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) || defined (CUDA_DISABLER) + +Ptr cv::gpu::createHoughCirclesDetector(float, float, int, int, int, int, int) { throw_no_cuda(); return Ptr(); } + +#else /* !defined (HAVE_CUDA) */ + +namespace cv { namespace gpu { namespace cudev +{ + namespace hough + { + int buildPointList_gpu(PtrStepSzb src, unsigned int* list); + } + + namespace hough_circles + { + void circlesAccumCenters_gpu(const unsigned int* list, int count, PtrStepi dx, PtrStepi dy, PtrStepSzi accum, int minRadius, int maxRadius, float idp); + int buildCentersList_gpu(PtrStepSzi accum, unsigned int* centers, int threshold); + int circlesAccumRadius_gpu(const unsigned int* centers, int centersCount, const unsigned int* list, int count, + float3* circles, int maxCircles, float dp, int minRadius, int maxRadius, int threshold, bool has20); + } +}}} + +namespace +{ + class HoughCirclesDetectorImpl : public HoughCirclesDetector + { + public: + HoughCirclesDetectorImpl(float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles); + + void detect(InputArray src, OutputArray circles); + + void setDp(float dp) { dp_ = dp; } + float getDp() const { return dp_; } + + void setMinDist(float minDist) { minDist_ = minDist; } + float getMinDist() const { return minDist_; } + + void setCannyThreshold(int cannyThreshold) { cannyThreshold_ = cannyThreshold; } + int getCannyThreshold() const { return cannyThreshold_; } + + void setVotesThreshold(int votesThreshold) { votesThreshold_ = votesThreshold; } + int getVotesThreshold() const { return votesThreshold_; } + + void setMinRadius(int minRadius) { minRadius_ = minRadius; } + int getMinRadius() const { return minRadius_; } + + void setMaxRadius(int maxRadius) { maxRadius_ = maxRadius; } + int getMaxRadius() const { return maxRadius_; } + + void setMaxCircles(int maxCircles) { maxCircles_ = maxCircles; } + int getMaxCircles() const { return maxCircles_; } + + void write(FileStorage& fs) const + { + fs << "name" << "HoughCirclesDetector_GPU" + << "dp" << dp_ + << "minDist" << minDist_ + << "cannyThreshold" << cannyThreshold_ + << "votesThreshold" << votesThreshold_ + << "minRadius" << minRadius_ + << "maxRadius" << maxRadius_ + << "maxCircles" << maxCircles_; + } + + void read(const FileNode& fn) + { + CV_Assert( String(fn["name"]) == "HoughCirclesDetector_GPU" ); + dp_ = (float)fn["dp"]; + minDist_ = (float)fn["minDist"]; + cannyThreshold_ = (int)fn["cannyThreshold"]; + votesThreshold_ = (int)fn["votesThreshold"]; + minRadius_ = (int)fn["minRadius"]; + maxRadius_ = (int)fn["maxRadius"]; + maxCircles_ = (int)fn["maxCircles"]; + } + + private: + float dp_; + float minDist_; + int cannyThreshold_; + int votesThreshold_; + int minRadius_; + int maxRadius_; + int maxCircles_; + + GpuMat dx_, dy_; + GpuMat edges_; + GpuMat accum_; + GpuMat list_; + GpuMat result_; + Ptr filterDx_; + Ptr filterDy_; + Ptr canny_; + }; + + HoughCirclesDetectorImpl::HoughCirclesDetectorImpl(float dp, float minDist, int cannyThreshold, int votesThreshold, + int minRadius, int maxRadius, int maxCircles) : + dp_(dp), minDist_(minDist), cannyThreshold_(cannyThreshold), votesThreshold_(votesThreshold), + minRadius_(minRadius), maxRadius_(maxRadius), maxCircles_(maxCircles) + { + canny_ = gpu::createCannyEdgeDetector(std::max(cannyThreshold_ / 2, 1), cannyThreshold_); + + filterDx_ = gpu::createSobelFilter(CV_8UC1, CV_32S, 1, 0); + filterDy_ = gpu::createSobelFilter(CV_8UC1, CV_32S, 0, 1); + } + + void HoughCirclesDetectorImpl::detect(InputArray _src, OutputArray circles) + { + using namespace cv::gpu::cudev::hough; + using namespace cv::gpu::cudev::hough_circles; + + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.type() == CV_8UC1 ); + CV_Assert( src.cols < std::numeric_limits::max() ); + CV_Assert( src.rows < std::numeric_limits::max() ); + CV_Assert( dp_ > 0 ); + CV_Assert( minRadius_ > 0 && maxRadius_ > minRadius_ ); + CV_Assert( cannyThreshold_ > 0 ); + CV_Assert( votesThreshold_ > 0 ); + CV_Assert( maxCircles_ > 0 ); + + const float idp = 1.0f / dp_; + + filterDx_->apply(src, dx_); + filterDy_->apply(src, dy_); + + canny_->setLowThreshold(std::max(cannyThreshold_ / 2, 1)); + canny_->setHighThreshold(cannyThreshold_); + + canny_->detect(dx_, dy_, edges_); + + ensureSizeIsEnough(2, src.size().area(), CV_32SC1, list_); + unsigned int* srcPoints = list_.ptr(0); + unsigned int* centers = list_.ptr(1); + + const int pointsCount = buildPointList_gpu(edges_, srcPoints); + if (pointsCount == 0) + { + circles.release(); + return; + } + + ensureSizeIsEnough(cvCeil(src.rows * idp) + 2, cvCeil(src.cols * idp) + 2, CV_32SC1, accum_); + accum_.setTo(Scalar::all(0)); + + circlesAccumCenters_gpu(srcPoints, pointsCount, dx_, dy_, accum_, minRadius_, maxRadius_, idp); + + int centersCount = buildCentersList_gpu(accum_, centers, votesThreshold_); + if (centersCount == 0) + { + circles.release(); + return; + } + + if (minDist_ > 1) + { + AutoBuffer oldBuf_(centersCount); + AutoBuffer newBuf_(centersCount); + int newCount = 0; + + ushort2* oldBuf = oldBuf_; + ushort2* newBuf = newBuf_; + + cudaSafeCall( cudaMemcpy(oldBuf, centers, centersCount * sizeof(ushort2), cudaMemcpyDeviceToHost) ); + + const int cellSize = cvRound(minDist_); + const int gridWidth = (src.cols + cellSize - 1) / cellSize; + const int gridHeight = (src.rows + cellSize - 1) / cellSize; + + std::vector< std::vector > grid(gridWidth * gridHeight); + + const float minDist2 = minDist_ * minDist_; + + for (int i = 0; i < centersCount; ++i) + { + ushort2 p = oldBuf[i]; + + bool good = true; + + int xCell = static_cast(p.x / cellSize); + int yCell = static_cast(p.y / cellSize); + + int x1 = xCell - 1; + int y1 = yCell - 1; + int x2 = xCell + 1; + int y2 = yCell + 1; + + // boundary check + x1 = std::max(0, x1); + y1 = std::max(0, y1); + x2 = std::min(gridWidth - 1, x2); + y2 = std::min(gridHeight - 1, y2); + + for (int yy = y1; yy <= y2; ++yy) + { + for (int xx = x1; xx <= x2; ++xx) + { + std::vector& m = grid[yy * gridWidth + xx]; + + for(size_t j = 0; j < m.size(); ++j) + { + float dx = (float)(p.x - m[j].x); + float dy = (float)(p.y - m[j].y); + + if (dx * dx + dy * dy < minDist2) + { + good = false; + goto break_out; + } + } + } + } + + break_out: + + if(good) + { + grid[yCell * gridWidth + xCell].push_back(p); + + newBuf[newCount++] = p; + } + } + + cudaSafeCall( cudaMemcpy(centers, newBuf, newCount * sizeof(unsigned int), cudaMemcpyHostToDevice) ); + centersCount = newCount; + } + + ensureSizeIsEnough(1, maxCircles_, CV_32FC3, result_); + + int circlesCount = circlesAccumRadius_gpu(centers, centersCount, srcPoints, pointsCount, result_.ptr(), maxCircles_, + dp_, minRadius_, maxRadius_, votesThreshold_, deviceSupports(FEATURE_SET_COMPUTE_20)); + + if (circlesCount == 0) + { + circles.release(); + return; + } + + result_.cols = circlesCount; + result_.copyTo(circles); + } +} + +Ptr cv::gpu::createHoughCirclesDetector(float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles) +{ + return new HoughCirclesDetectorImpl(dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius, maxCircles); +} + +#endif /* !defined (HAVE_CUDA) */ diff --git a/modules/gpuimgproc/src/hough_lines.cpp b/modules/gpuimgproc/src/hough_lines.cpp new file mode 100644 index 0000000000..e0dec305d9 --- /dev/null +++ b/modules/gpuimgproc/src/hough_lines.cpp @@ -0,0 +1,202 @@ +/*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) || defined (CUDA_DISABLER) + +Ptr cv::gpu::createHoughLinesDetector(float, float, int, bool, int) { throw_no_cuda(); return Ptr(); } + +#else /* !defined (HAVE_CUDA) */ + +namespace cv { namespace gpu { namespace cudev +{ + namespace hough + { + int buildPointList_gpu(PtrStepSzb src, unsigned int* list); + } + + namespace hough_lines + { + void linesAccum_gpu(const unsigned int* list, int count, PtrStepSzi accum, float rho, float theta, size_t sharedMemPerBlock, bool has20); + int linesGetResult_gpu(PtrStepSzi accum, float2* out, int* votes, int maxSize, float rho, float theta, int threshold, bool doSort); + } +}}} + +namespace +{ + class HoughLinesDetectorImpl : public HoughLinesDetector + { + public: + HoughLinesDetectorImpl(float rho, float theta, int threshold, bool doSort, int maxLines) : + rho_(rho), theta_(theta), threshold_(threshold), doSort_(doSort), maxLines_(maxLines) + { + } + + void detect(InputArray src, OutputArray lines); + void downloadResults(InputArray d_lines, OutputArray h_lines, OutputArray h_votes = noArray()); + + void setRho(float rho) { rho_ = rho; } + float getRho() const { return rho_; } + + void setTheta(float theta) { theta_ = theta; } + float getTheta() const { return theta_; } + + void setThreshold(int threshold) { threshold_ = threshold; } + int getThreshold() const { return threshold_; } + + void setDoSort(bool doSort) { doSort_ = doSort; } + bool getDoSort() const { return doSort_; } + + void setMaxLines(int maxLines) { maxLines_ = maxLines; } + int getMaxLines() const { return maxLines_; } + + void write(FileStorage& fs) const + { + fs << "name" << "HoughLinesDetector_GPU" + << "rho" << rho_ + << "theta" << theta_ + << "threshold" << threshold_ + << "doSort" << doSort_ + << "maxLines" << maxLines_; + } + + void read(const FileNode& fn) + { + CV_Assert( String(fn["name"]) == "HoughLinesDetector_GPU" ); + rho_ = (float)fn["rho"]; + theta_ = (float)fn["theta"]; + threshold_ = (int)fn["threshold"]; + doSort_ = (int)fn["doSort"] != 0; + maxLines_ = (int)fn["maxLines"]; + } + + private: + float rho_; + float theta_; + int threshold_; + bool doSort_; + int maxLines_; + + GpuMat accum_; + GpuMat list_; + GpuMat result_; + }; + + void HoughLinesDetectorImpl::detect(InputArray _src, OutputArray lines) + { + using namespace cv::gpu::cudev::hough; + using namespace cv::gpu::cudev::hough_lines; + + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.type() == CV_8UC1 ); + CV_Assert( src.cols < std::numeric_limits::max() ); + CV_Assert( src.rows < std::numeric_limits::max() ); + + ensureSizeIsEnough(1, src.size().area(), CV_32SC1, list_); + unsigned int* srcPoints = list_.ptr(); + + const int pointsCount = buildPointList_gpu(src, srcPoints); + if (pointsCount == 0) + { + lines.release(); + return; + } + + const int numangle = cvRound(CV_PI / theta_); + const int numrho = cvRound(((src.cols + src.rows) * 2 + 1) / rho_); + CV_Assert( numangle > 0 && numrho > 0 ); + + ensureSizeIsEnough(numangle + 2, numrho + 2, CV_32SC1, accum_); + accum_.setTo(Scalar::all(0)); + + DeviceInfo devInfo; + linesAccum_gpu(srcPoints, pointsCount, accum_, rho_, theta_, devInfo.sharedMemPerBlock(), devInfo.supports(FEATURE_SET_COMPUTE_20)); + + ensureSizeIsEnough(2, maxLines_, CV_32FC2, result_); + + int linesCount = linesGetResult_gpu(accum_, result_.ptr(0), result_.ptr(1), maxLines_, rho_, theta_, threshold_, doSort_); + + if (linesCount == 0) + { + lines.release(); + return; + } + + result_.cols = linesCount; + result_.copyTo(lines); + } + + void HoughLinesDetectorImpl::downloadResults(InputArray _d_lines, OutputArray h_lines, OutputArray h_votes) + { + GpuMat d_lines = _d_lines.getGpuMat(); + + if (d_lines.empty()) + { + h_lines.release(); + if (h_votes.needed()) + h_votes.release(); + return; + } + + CV_Assert( d_lines.rows == 2 && d_lines.type() == CV_32FC2 ); + + d_lines.row(0).download(h_lines); + + if (h_votes.needed()) + { + GpuMat d_votes(1, d_lines.cols, CV_32SC1, d_lines.ptr(1)); + d_votes.download(h_votes); + } + } +} + +Ptr cv::gpu::createHoughLinesDetector(float rho, float theta, int threshold, bool doSort, int maxLines) +{ + return new HoughLinesDetectorImpl(rho, theta, threshold, doSort, maxLines); +} + +#endif /* !defined (HAVE_CUDA) */ diff --git a/modules/gpuimgproc/src/hough_segments.cpp b/modules/gpuimgproc/src/hough_segments.cpp new file mode 100644 index 0000000000..1f11be68b2 --- /dev/null +++ b/modules/gpuimgproc/src/hough_segments.cpp @@ -0,0 +1,183 @@ +/*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) || defined (CUDA_DISABLER) + +Ptr cv::gpu::createHoughSegmentDetector(float, float, int, int, int) { throw_no_cuda(); return Ptr(); } + +#else /* !defined (HAVE_CUDA) */ + +namespace cv { namespace gpu { namespace cudev +{ + namespace hough + { + int buildPointList_gpu(PtrStepSzb src, unsigned int* list); + } + + namespace hough_lines + { + void linesAccum_gpu(const unsigned int* list, int count, PtrStepSzi accum, float rho, float theta, size_t sharedMemPerBlock, bool has20); + } + + namespace hough_segments + { + int houghLinesProbabilistic_gpu(PtrStepSzb mask, PtrStepSzi accum, int4* out, int maxSize, float rho, float theta, int lineGap, int lineLength); + } +}}} + +namespace +{ + class HoughSegmentDetectorImpl : public HoughSegmentDetector + { + public: + HoughSegmentDetectorImpl(float rho, float theta, int minLineLength, int maxLineGap, int maxLines) : + rho_(rho), theta_(theta), minLineLength_(minLineLength), maxLineGap_(maxLineGap), maxLines_(maxLines) + { + } + + void detect(InputArray src, OutputArray lines); + + void setRho(float rho) { rho_ = rho; } + float getRho() const { return rho_; } + + void setTheta(float theta) { theta_ = theta; } + float getTheta() const { return theta_; } + + void setMinLineLength(int minLineLength) { minLineLength_ = minLineLength; } + int getMinLineLength() const { return minLineLength_; } + + void setMaxLineGap(int maxLineGap) { maxLineGap_ = maxLineGap; } + int getMaxLineGap() const { return maxLineGap_; } + + void setMaxLines(int maxLines) { maxLines_ = maxLines; } + int getMaxLines() const { return maxLines_; } + + void write(FileStorage& fs) const + { + fs << "name" << "PHoughLinesDetector_GPU" + << "rho" << rho_ + << "theta" << theta_ + << "minLineLength" << minLineLength_ + << "maxLineGap" << maxLineGap_ + << "maxLines" << maxLines_; + } + + void read(const FileNode& fn) + { + CV_Assert( String(fn["name"]) == "PHoughLinesDetector_GPU" ); + rho_ = (float)fn["rho"]; + theta_ = (float)fn["theta"]; + minLineLength_ = (int)fn["minLineLength"]; + maxLineGap_ = (int)fn["maxLineGap"]; + maxLines_ = (int)fn["maxLines"]; + } + + private: + float rho_; + float theta_; + int minLineLength_; + int maxLineGap_; + int maxLines_; + + GpuMat accum_; + GpuMat list_; + GpuMat result_; + }; + + void HoughSegmentDetectorImpl::detect(InputArray _src, OutputArray lines) + { + using namespace cv::gpu::cudev::hough; + using namespace cv::gpu::cudev::hough_lines; + using namespace cv::gpu::cudev::hough_segments; + + GpuMat src = _src.getGpuMat(); + + CV_Assert( src.type() == CV_8UC1 ); + CV_Assert( src.cols < std::numeric_limits::max() ); + CV_Assert( src.rows < std::numeric_limits::max() ); + + ensureSizeIsEnough(1, src.size().area(), CV_32SC1, list_); + unsigned int* srcPoints = list_.ptr(); + + const int pointsCount = buildPointList_gpu(src, srcPoints); + if (pointsCount == 0) + { + lines.release(); + return; + } + + const int numangle = cvRound(CV_PI / theta_); + const int numrho = cvRound(((src.cols + src.rows) * 2 + 1) / rho_); + CV_Assert( numangle > 0 && numrho > 0 ); + + ensureSizeIsEnough(numangle + 2, numrho + 2, CV_32SC1, accum_); + accum_.setTo(Scalar::all(0)); + + DeviceInfo devInfo; + linesAccum_gpu(srcPoints, pointsCount, accum_, rho_, theta_, devInfo.sharedMemPerBlock(), devInfo.supports(FEATURE_SET_COMPUTE_20)); + + ensureSizeIsEnough(1, maxLines_, CV_32SC4, result_); + + int linesCount = houghLinesProbabilistic_gpu(src, accum_, result_.ptr(), maxLines_, rho_, theta_, maxLineGap_, minLineLength_); + + if (linesCount == 0) + { + lines.release(); + return; + } + + result_.cols = linesCount; + result_.copyTo(lines); + } +} + +Ptr cv::gpu::createHoughSegmentDetector(float rho, float theta, int minLineLength, int maxLineGap, int maxLines) +{ + return new HoughSegmentDetectorImpl(rho, theta, minLineLength, maxLineGap, maxLines); +} + +#endif /* !defined (HAVE_CUDA) */ diff --git a/modules/gpuimgproc/src/precomp.hpp b/modules/gpuimgproc/src/precomp.hpp index 1417c874bb..27068d4cca 100644 --- a/modules/gpuimgproc/src/precomp.hpp +++ b/modules/gpuimgproc/src/precomp.hpp @@ -46,6 +46,7 @@ #include "opencv2/gpuimgproc.hpp" #include "opencv2/gpufilters.hpp" +#include "opencv2/core/utility.hpp" #include "opencv2/core/private.hpp" #include "opencv2/core/private.gpu.hpp" From 5da724001f1d9aeb4e4bc26a08dc85926b6bbffc Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Mon, 6 May 2013 15:33:32 +0400 Subject: [PATCH 15/17] made dependecy from gpufilters optional --- modules/gpuimgproc/CMakeLists.txt | 2 +- modules/gpuimgproc/src/canny.cpp | 8 ++++++++ modules/gpuimgproc/src/corners.cpp | 2 +- modules/gpuimgproc/src/cuda/corners.cu | 8 +++++++- modules/gpuimgproc/src/cuda/hough_circles.cu | 5 +++++ modules/gpuimgproc/src/generalized_hough.cpp | 18 ++++++++++++++++++ modules/gpuimgproc/src/hough_circles.cpp | 2 +- modules/gpuimgproc/src/precomp.hpp | 5 ++++- 8 files changed, 45 insertions(+), 5 deletions(-) diff --git a/modules/gpuimgproc/CMakeLists.txt b/modules/gpuimgproc/CMakeLists.txt index 3b9bd07258..dfecf1d219 100644 --- a/modules/gpuimgproc/CMakeLists.txt +++ b/modules/gpuimgproc/CMakeLists.txt @@ -6,4 +6,4 @@ set(the_description "GPU-accelerated Image Processing") ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4127 /wd4100 /wd4324 /wd4512 /wd4515 -Wundef -Wmissing-declarations -Wshadow -Wunused-parameter) -ocv_define_module(gpuimgproc opencv_imgproc opencv_gpufilters OPTIONAL opencv_gpuarithm) +ocv_define_module(gpuimgproc opencv_imgproc OPTIONAL opencv_gpuarithm opencv_gpufilters) diff --git a/modules/gpuimgproc/src/canny.cpp b/modules/gpuimgproc/src/canny.cpp index 3976bbd671..d6f5e6b032 100644 --- a/modules/gpuimgproc/src/canny.cpp +++ b/modules/gpuimgproc/src/canny.cpp @@ -122,7 +122,9 @@ namespace GpuMat mag_; GpuMat map_; GpuMat st1_, st2_; +#ifdef HAVE_OPENCV_GPUFILTERS Ptr filterDX_, filterDY_; +#endif int old_apperture_size_; }; @@ -152,10 +154,14 @@ namespace } else { +#ifndef HAVE_OPENCV_GPUFILTERS + throw_no_cuda(); +#else filterDX_->apply(image, dx_); filterDY_->apply(image, dy_); canny::calcMagnitude(dx_, dy_, mag_, L2gradient_); +#endif } CannyCaller(edges); @@ -191,12 +197,14 @@ namespace ensureSizeIsEnough(image_size, CV_32SC1, dx_); ensureSizeIsEnough(image_size, CV_32SC1, dy_); +#ifdef HAVE_OPENCV_GPUFILTERS if (apperture_size_ != 3 && apperture_size_ != old_apperture_size_) { filterDX_ = gpu::createDerivFilter(CV_8UC1, CV_32S, 1, 0, apperture_size_, false, 1, BORDER_REPLICATE); filterDY_ = gpu::createDerivFilter(CV_8UC1, CV_32S, 0, 1, apperture_size_, false, 1, BORDER_REPLICATE); old_apperture_size_ = apperture_size_; } +#endif ensureSizeIsEnough(image_size, CV_32FC1, mag_); ensureSizeIsEnough(image_size, CV_32SC1, map_); diff --git a/modules/gpuimgproc/src/corners.cpp b/modules/gpuimgproc/src/corners.cpp index 1a72bd7c8a..5df5063274 100644 --- a/modules/gpuimgproc/src/corners.cpp +++ b/modules/gpuimgproc/src/corners.cpp @@ -45,7 +45,7 @@ using namespace cv; using namespace cv::gpu; -#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) +#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) || !defined(HAVE_OPENCV_GPUFILTERS) Ptr cv::gpu::createHarrisCorner(int, int, int, double, int) { throw_no_cuda(); return Ptr(); } Ptr cv::gpu::createMinEigenValCorner(int, int, int, int) { throw_no_cuda(); return Ptr(); } diff --git a/modules/gpuimgproc/src/cuda/corners.cu b/modules/gpuimgproc/src/cuda/corners.cu index 39e7cdc5d7..aa65ac8f8b 100644 --- a/modules/gpuimgproc/src/cuda/corners.cu +++ b/modules/gpuimgproc/src/cuda/corners.cu @@ -48,6 +48,10 @@ #include "opencv2/core/cuda/saturate_cast.hpp" #include "opencv2/core/cuda/border_interpolate.hpp" +#include "opencv2/opencv_modules.hpp" + +#ifdef HAVE_OPENCV_GPUFILTERS + namespace cv { namespace gpu { namespace cudev { namespace imgproc @@ -271,4 +275,6 @@ namespace cv { namespace gpu { namespace cudev } }}} -#endif +#endif // HAVE_OPENCV_GPUFILTERS + +#endif // CUDA_DISABLER diff --git a/modules/gpuimgproc/src/cuda/hough_circles.cu b/modules/gpuimgproc/src/cuda/hough_circles.cu index 1b6b103362..6757e430b6 100644 --- a/modules/gpuimgproc/src/cuda/hough_circles.cu +++ b/modules/gpuimgproc/src/cuda/hough_circles.cu @@ -46,6 +46,10 @@ #include "opencv2/core/cuda/emulation.hpp" #include "opencv2/core/cuda/dynamic_smem.hpp" +#include "opencv2/opencv_modules.hpp" + +#ifdef HAVE_OPENCV_GPUFILTERS + namespace cv { namespace gpu { namespace cudev { namespace hough_circles @@ -251,5 +255,6 @@ namespace cv { namespace gpu { namespace cudev } }}} +#endif // HAVE_OPENCV_GPUFILTERS #endif /* CUDA_DISABLER */ diff --git a/modules/gpuimgproc/src/generalized_hough.cpp b/modules/gpuimgproc/src/generalized_hough.cpp index 1bc0574b13..0d01301744 100644 --- a/modules/gpuimgproc/src/generalized_hough.cpp +++ b/modules/gpuimgproc/src/generalized_hough.cpp @@ -133,22 +133,32 @@ namespace virtual void detectImpl(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, OutputArray positions) = 0; private: +#ifdef HAVE_OPENCV_GPUFILTERS GpuMat dx_, dy_; GpuMat edges_; Ptr canny_; Ptr filterDx_; Ptr filterDy_; +#endif }; GeneralizedHoughBase::GeneralizedHoughBase() { +#ifdef HAVE_OPENCV_GPUFILTERS canny_ = gpu::createCannyEdgeDetector(50, 100); filterDx_ = gpu::createSobelFilter(CV_8UC1, CV_32S, 1, 0); filterDy_ = gpu::createSobelFilter(CV_8UC1, CV_32S, 0, 1); +#endif } void GeneralizedHoughBase::setTemplate(InputArray _templ, int cannyThreshold, Point templCenter) { +#ifndef HAVE_OPENCV_GPUFILTERS + (void) _templ; + (void) cannyThreshold; + (void) templCenter; + throw_no_cuda(); +#else GpuMat templ = _templ.getGpuMat(); CV_Assert( templ.type() == CV_8UC1 ); @@ -170,6 +180,7 @@ namespace templCenter = Point(templ.cols / 2, templ.rows / 2); setTemplateImpl(edges_, dx_, dy_, templCenter); +#endif } void GeneralizedHoughBase::setTemplate(InputArray _edges, InputArray _dx, InputArray _dy, Point templCenter) @@ -186,6 +197,12 @@ namespace void GeneralizedHoughBase::detect(InputArray _image, OutputArray positions, int cannyThreshold) { +#ifndef HAVE_OPENCV_GPUFILTERS + (void) _image; + (void) positions; + (void) cannyThreshold; + throw_no_cuda(); +#else GpuMat image = _image.getGpuMat(); CV_Assert( image.type() == CV_8UC1 ); @@ -204,6 +221,7 @@ namespace canny_->detect(dx_, dy_, edges_); detectImpl(edges_, dx_, dy_, positions); +#endif } void GeneralizedHoughBase::detect(InputArray _edges, InputArray _dx, InputArray _dy, OutputArray positions) diff --git a/modules/gpuimgproc/src/hough_circles.cpp b/modules/gpuimgproc/src/hough_circles.cpp index 3f1e771740..fa583c09c7 100644 --- a/modules/gpuimgproc/src/hough_circles.cpp +++ b/modules/gpuimgproc/src/hough_circles.cpp @@ -45,7 +45,7 @@ using namespace cv; using namespace cv::gpu; -#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) +#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) || !defined(HAVE_OPENCV_GPUFILTERS) Ptr cv::gpu::createHoughCirclesDetector(float, float, int, int, int, int, int) { throw_no_cuda(); return Ptr(); } diff --git a/modules/gpuimgproc/src/precomp.hpp b/modules/gpuimgproc/src/precomp.hpp index 27068d4cca..b1edbf1239 100644 --- a/modules/gpuimgproc/src/precomp.hpp +++ b/modules/gpuimgproc/src/precomp.hpp @@ -44,7 +44,6 @@ #define __OPENCV_PRECOMP_H__ #include "opencv2/gpuimgproc.hpp" -#include "opencv2/gpufilters.hpp" #include "opencv2/core/utility.hpp" #include "opencv2/core/private.hpp" @@ -56,4 +55,8 @@ # include "opencv2/gpuarithm.hpp" #endif +#ifdef HAVE_OPENCV_GPUFILTERS +# include "opencv2/gpufilters.hpp" +#endif + #endif /* __OPENCV_PRECOMP_H__ */ From 59edad5a003c43634a6daf6215d591d2da8fa0a7 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Mon, 24 Jun 2013 14:32:45 +0400 Subject: [PATCH 16/17] removed obsolete API --- .../gpuimgproc/include/opencv2/gpuimgproc.hpp | 91 ------------------- 1 file changed, 91 deletions(-) diff --git a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp index 2aaef9b6f3..330476560d 100644 --- a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp +++ b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp @@ -50,17 +50,6 @@ #include "opencv2/core/gpu.hpp" #include "opencv2/imgproc.hpp" -#if defined __GNUC__ - #define __OPENCV_GPUIMGPROC_DEPR_BEFORE__ - #define __OPENCV_GPUIMGPROC_DEPR_AFTER__ __attribute__ ((deprecated)) -#elif (defined WIN32 || defined _WIN32) - #define __OPENCV_GPUIMGPROC_DEPR_BEFORE__ __declspec(deprecated) - #define __OPENCV_GPUIMGPROC_DEPR_AFTER__ -#else - #define __OPENCV_GPUIMGPROC_DEPR_BEFORE__ - #define __OPENCV_GPUIMGPROC_DEPR_AFTER__ -#endif - namespace cv { namespace gpu { /////////////////////////// Color Processing /////////////////////////// @@ -202,22 +191,6 @@ public: CV_EXPORTS Ptr createCannyEdgeDetector(double low_thresh, double high_thresh, int apperture_size = 3, bool L2gradient = false); -// obsolete - -__OPENCV_GPUIMGPROC_DEPR_BEFORE__ void Canny(InputArray image, OutputArray edges, - double low_thresh, double high_thresh, int apperture_size = 3, bool L2gradient = false) __OPENCV_GPUIMGPROC_DEPR_AFTER__; -inline void Canny(InputArray image, OutputArray edges, double low_thresh, double high_thresh, int apperture_size, bool L2gradient) -{ - gpu::createCannyEdgeDetector(low_thresh, high_thresh, apperture_size, L2gradient)->detect(image, edges); -} - -__OPENCV_GPUIMGPROC_DEPR_BEFORE__ void Canny(InputArray dx, InputArray dy, OutputArray edges, - double low_thresh, double high_thresh, bool L2gradient = false) __OPENCV_GPUIMGPROC_DEPR_AFTER__; -inline void Canny(InputArray dx, InputArray dy, OutputArray edges, double low_thresh, double high_thresh, bool L2gradient) -{ - gpu::createCannyEdgeDetector(low_thresh, high_thresh, 3, L2gradient)->detect(dx, dy, edges); -} - /////////////////////////// Hough Transform //////////////////////////// ////////////////////////////////////// @@ -247,15 +220,6 @@ public: CV_EXPORTS Ptr createHoughLinesDetector(float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096); -// obsolete - -__OPENCV_GPUIMGPROC_DEPR_BEFORE__ void HoughLines(InputArray src, OutputArray lines, float rho, float theta, int threshold, - bool doSort = false, int maxLines = 4096) __OPENCV_GPUIMGPROC_DEPR_AFTER__; - -inline void HoughLines(InputArray src, OutputArray lines, float rho, float theta, int threshold, bool doSort, int maxLines) -{ - gpu::createHoughLinesDetector(rho, theta, threshold, doSort, maxLines)->detect(src, lines); -} ////////////////////////////////////// // HoughLinesP @@ -284,16 +248,6 @@ public: CV_EXPORTS Ptr createHoughSegmentDetector(float rho, float theta, int minLineLength, int maxLineGap, int maxLines = 4096); -// obsolete - -__OPENCV_GPUIMGPROC_DEPR_BEFORE__ void HoughLinesP(InputArray src, OutputArray lines, - float rho, float theta, int minLineLength, int maxLineGap, int maxLines = 4096) __OPENCV_GPUIMGPROC_DEPR_AFTER__; - -inline void HoughLinesP(InputArray src, OutputArray lines, float rho, float theta, int minLineLength, int maxLineGap, int maxLines) -{ - gpu::createHoughSegmentDetector(rho, theta, minLineLength, maxLineGap, maxLines)->detect(src, lines); -} - ////////////////////////////////////// // HoughCircles @@ -326,18 +280,6 @@ public: CV_EXPORTS Ptr createHoughCirclesDetector(float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles = 4096); -// obsolete - -__OPENCV_GPUIMGPROC_DEPR_BEFORE__ void HoughCircles(InputArray src, OutputArray circles, - int method, float dp, float minDist, int cannyThreshold, int votesThreshold, - int minRadius, int maxRadius, int maxCircles = 4096) __OPENCV_GPUIMGPROC_DEPR_AFTER__; - -inline void HoughCircles(InputArray src, OutputArray circles, int /*method*/, float dp, float minDist, - int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles) -{ - gpu::createHoughCirclesDetector(dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius, maxCircles)->detect(src, circles); -} - ////////////////////////////////////// // GeneralizedHough @@ -374,26 +316,6 @@ CV_EXPORTS Ptr createHarrisCorner(int srcType, int blockSize //! computes minimum eigen value of 2x2 derivative covariation matrix at each pixel - the cornerness criteria CV_EXPORTS Ptr createMinEigenValCorner(int srcType, int blockSize, int ksize, int borderType = BORDER_REFLECT101); -// obsolete - -__OPENCV_GPUIMGPROC_DEPR_BEFORE__ void cornerHarris(InputArray src, OutputArray dst, - int blockSize, int ksize, double k, int borderType = BORDER_REFLECT101, - Stream& stream = Stream::Null()) __OPENCV_GPUIMGPROC_DEPR_AFTER__; - -inline void cornerHarris(InputArray src, OutputArray dst, int blockSize, int ksize, double k, int borderType, Stream& stream) -{ - gpu::createHarrisCorner(src.type(), blockSize, ksize, k, borderType)->compute(src, dst, stream); -} - -__OPENCV_GPUIMGPROC_DEPR_BEFORE__ void cornerMinEigenVal(InputArray src, OutputArray dst, - int blockSize, int ksize, int borderType = BORDER_REFLECT101, - Stream& stream = Stream::Null()) __OPENCV_GPUIMGPROC_DEPR_AFTER__; - -inline void cornerMinEigenVal(InputArray src, OutputArray dst, int blockSize, int ksize, int borderType, Stream& stream) -{ - gpu::createMinEigenValCorner(src.type(), blockSize, ksize, borderType)->compute(src, dst, stream); -} - ////////////////////////// Corners Detection /////////////////////////// class CV_EXPORTS CornersDetector : public Algorithm @@ -433,16 +355,6 @@ public: CV_EXPORTS Ptr createTemplateMatching(int srcType, int method, Size user_block_size = Size()); -// obsolete - -__OPENCV_GPUIMGPROC_DEPR_BEFORE__ void matchTemplate(InputArray image, InputArray templ, OutputArray result, - int method, Stream& stream = Stream::Null()) __OPENCV_GPUIMGPROC_DEPR_AFTER__; - -inline void matchTemplate(InputArray image, InputArray templ, OutputArray result, int method, Stream& stream) -{ - gpu::createTemplateMatching(image.type(), method)->match(image, templ, result, stream); -} - ////////////////////////// Bilateral Filter /////////////////////////// //! Performa bilateral filtering of passsed image @@ -458,7 +370,4 @@ CV_EXPORTS void blendLinear(InputArray img1, InputArray img2, InputArray weights }} // namespace cv { namespace gpu { -#undef __OPENCV_GPUIMGPROC_DEPR_BEFORE__ -#undef __OPENCV_GPUIMGPROC_DEPR_AFTER__ - #endif /* __OPENCV_GPUIMGPROC_HPP__ */ From 39a25115e006c3143877b5661b7c379f77a0d1e0 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Mon, 24 Jun 2013 16:19:37 +0400 Subject: [PATCH 17/17] fixed compilation --- modules/gpuimgproc/src/cuda/generalized_hough.cu | 5 +++-- samples/gpu/cascadeclassifier.cpp | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/gpuimgproc/src/cuda/generalized_hough.cu b/modules/gpuimgproc/src/cuda/generalized_hough.cu index 9ae5a595bb..14c8600104 100644 --- a/modules/gpuimgproc/src/cuda/generalized_hough.cu +++ b/modules/gpuimgproc/src/cuda/generalized_hough.cu @@ -48,6 +48,7 @@ #include "opencv2/core/cuda/common.hpp" #include "opencv2/core/cuda/emulation.hpp" #include "opencv2/core/cuda/vec_math.hpp" +#include "opencv2/core/cuda/functional.hpp" #include "opencv2/opencv_modules.hpp" @@ -183,7 +184,7 @@ namespace cv { namespace gpu { namespace cudev const int ind = ::atomicAdd(r_sizes + n, 1); if (ind < maxSize) - r_table(n, ind) = p - templCenter; + r_table(n, ind) = saturate_cast(p - templCenter); } void buildRTable_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, @@ -227,7 +228,7 @@ namespace cv { namespace gpu { namespace cudev for (int j = 0; j < r_row_size; ++j) { - short2 c = p - r_row[j]; + short2 c = saturate_cast(p - r_row[j]); c.x = __float2int_rn(c.x * idp); c.y = __float2int_rn(c.y * idp); diff --git a/samples/gpu/cascadeclassifier.cpp b/samples/gpu/cascadeclassifier.cpp index 929fd3085e..e27186c271 100644 --- a/samples/gpu/cascadeclassifier.cpp +++ b/samples/gpu/cascadeclassifier.cpp @@ -51,7 +51,7 @@ static void convertAndResize(const GpuMat& src, GpuMat& gray, GpuMat& resized, d { if (src.channels() == 3) { - gpu::cvtColor( src, gray, COLOR_BGR2GRAY ); + cv::gpu::cvtColor( src, gray, COLOR_BGR2GRAY ); } else { @@ -62,7 +62,7 @@ static void convertAndResize(const GpuMat& src, GpuMat& gray, GpuMat& resized, d if (scale != 1) { - gpu::resize(gray, resized, sz); + cv::gpu::resize(gray, resized, sz); } else {