diff --git a/modules/gpu/perf4au/main.cpp b/modules/gpu/perf4au/main.cpp index d86f7b8f3..df8a793ac 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 ea68590b5..d9b9d2703 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 a4aac0d02..f58940287 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 a91725fff..0e5b255b7 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,72 +88,137 @@ 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 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); + } + } } -void cv::gpu::HoughLines(const GpuMat& src, GpuMat& lines, HoughLinesBuf& buf, float rho, float theta, int threshold, bool doSort, int maxLines) +Ptr cv::gpu::createHoughLinesDetector(float rho, float theta, int threshold, bool doSort, int maxLines) { - 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()); - - ensureSizeIsEnough(1, src.size().area(), CV_32SC1, buf.list); - unsigned int* srcPoints = buf.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, buf.accum); - buf.accum.setTo(Scalar::all(0)); - - DeviceInfo devInfo; - linesAccum_gpu(srcPoints, pointsCount, buf.accum, rho, theta, devInfo.sharedMemPerBlock(), devInfo.supports(FEATURE_SET_COMPUTE_20)); - - ensureSizeIsEnough(2, maxLines, CV_32FC2, lines); - - 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(); -} - -void cv::gpu::HoughLinesDownload(const GpuMat& d_lines, OutputArray h_lines_, OutputArray h_votes_) -{ - 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); - - h_lines_.create(1, d_lines.cols, CV_32FC2); - Mat h_lines = h_lines_.getMat(); - d_lines.row(0).download(h_lines); - - if (h_votes_.needed()) - { - 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); - } + return new HoughLinesDetectorImpl(rho, theta, threshold, doSort, maxLines); } ////////////////////////////////////////////////////////// @@ -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; - - 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, buf.list); - unsigned int* srcPoints = buf.list.ptr(); - - const int pointsCount = buildPointList_gpu(src, srcPoints); - if (pointsCount == 0) + class PHoughLinesDetectorImpl : public HoughSegmentDetector { - lines.release(); - return; + 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); } +} - 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, buf.accum); - buf.accum.setTo(Scalar::all(0)); - - DeviceInfo devInfo; - linesAccum_gpu(srcPoints, pointsCount, buf.accum, rho, theta, devInfo.sharedMemPerBlock(), devInfo.supports(FEATURE_SET_COMPUTE_20)); - - ensureSizeIsEnough(1, maxLines, CV_32SC4, lines); - - int linesCount = houghLinesProbabilistic_gpu(src, buf.accum, lines.ptr(), maxLines, rho, theta, maxLineGap, minLineLength); - - if (linesCount > 0) - lines.cols = linesCount; - else - lines.release(); +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 a04490104..6e03eaad2 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 38d9c8298..4ede50b70 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;