1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
20 // * Redistribution's of source code must retain the above copyright notice,
21 // this list of conditions and the following disclaimer.
23 // * Redistribution's in binary form must reproduce the above copyright notice,
24 // this list of conditions and the following disclaimer in the documentation
25 // and/or other materials provided with the distribution.
27 // * The name of the copyright holders may not be used to endorse or promote products
28 // derived from this software without specific prior written permission.
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
43 #include "precomp.hpp"
47 using namespace cv::gpu;
49 #if !defined (HAVE_CUDA)
51 void cv::gpu::HoughLines(const GpuMat&, GpuMat&, float, float, int, bool, int) { throw_nogpu(); }
52 void cv::gpu::HoughLines(const GpuMat&, GpuMat&, HoughLinesBuf&, float, float, int, bool, int) { throw_nogpu(); }
53 void cv::gpu::HoughLinesDownload(const GpuMat&, OutputArray, OutputArray) { throw_nogpu(); }
55 void cv::gpu::HoughCircles(const GpuMat&, GpuMat&, int, float, float, int, int, int, int, int) { throw_nogpu(); }
56 void cv::gpu::HoughCircles(const GpuMat&, GpuMat&, HoughCirclesBuf&, int, float, float, int, int, int, int, int) { throw_nogpu(); }
57 void cv::gpu::HoughCirclesDownload(const GpuMat&, OutputArray) { throw_nogpu(); }
59 Ptr<GeneralizedHough_GPU> cv::gpu::GeneralizedHough_GPU::create(int) { throw_nogpu(); return Ptr<GeneralizedHough_GPU>(); }
60 cv::gpu::GeneralizedHough_GPU::~GeneralizedHough_GPU() {}
61 void cv::gpu::GeneralizedHough_GPU::setTemplate(const GpuMat&, int, Point) { throw_nogpu(); }
62 void cv::gpu::GeneralizedHough_GPU::setTemplate(const GpuMat&, const GpuMat&, const GpuMat&, Point) { throw_nogpu(); }
63 void cv::gpu::GeneralizedHough_GPU::detect(const GpuMat&, GpuMat&, int) { throw_nogpu(); }
64 void cv::gpu::GeneralizedHough_GPU::detect(const GpuMat&, const GpuMat&, const GpuMat&, GpuMat&) { throw_nogpu(); }
65 void cv::gpu::GeneralizedHough_GPU::download(const GpuMat&, OutputArray, OutputArray) { throw_nogpu(); }
66 void cv::gpu::GeneralizedHough_GPU::release() {}
68 #else /* !defined (HAVE_CUDA) */
70 namespace cv { namespace gpu { namespace device
74 int buildPointList_gpu(PtrStepSzb src, unsigned int* list);
78 //////////////////////////////////////////////////////////
81 namespace cv { namespace gpu { namespace device
85 void linesAccum_gpu(const unsigned int* list, int count, PtrStepSzi accum, float rho, float theta, size_t sharedMemPerBlock, bool has20);
86 int linesGetResult_gpu(PtrStepSzi accum, float2* out, int* votes, int maxSize, float rho, float theta, int threshold, bool doSort);
90 void cv::gpu::HoughLines(const GpuMat& src, GpuMat& lines, float rho, float theta, int threshold, bool doSort, int maxLines)
93 HoughLines(src, lines, buf, rho, theta, threshold, doSort, maxLines);
96 void cv::gpu::HoughLines(const GpuMat& src, GpuMat& lines, HoughLinesBuf& buf, float rho, float theta, int threshold, bool doSort, int maxLines)
98 using namespace cv::gpu::device::hough;
100 CV_Assert(src.type() == CV_8UC1);
101 CV_Assert(src.cols < std::numeric_limits<unsigned short>::max());
102 CV_Assert(src.rows < std::numeric_limits<unsigned short>::max());
104 ensureSizeIsEnough(1, src.size().area(), CV_32SC1, buf.list);
105 unsigned int* srcPoints = buf.list.ptr<unsigned int>();
107 const int pointsCount = buildPointList_gpu(src, srcPoints);
108 if (pointsCount == 0)
114 const int numangle = cvRound(CV_PI / theta);
115 const int numrho = cvRound(((src.cols + src.rows) * 2 + 1) / rho);
116 CV_Assert(numangle > 0 && numrho > 0);
118 ensureSizeIsEnough(numangle + 2, numrho + 2, CV_32SC1, buf.accum);
119 buf.accum.setTo(Scalar::all(0));
122 linesAccum_gpu(srcPoints, pointsCount, buf.accum, rho, theta, devInfo.sharedMemPerBlock(), devInfo.supports(FEATURE_SET_COMPUTE_20));
124 ensureSizeIsEnough(2, maxLines, CV_32FC2, lines);
126 int linesCount = linesGetResult_gpu(buf.accum, lines.ptr<float2>(0), lines.ptr<int>(1), maxLines, rho, theta, threshold, doSort);
128 lines.cols = linesCount;
133 void cv::gpu::HoughLinesDownload(const GpuMat& d_lines, OutputArray h_lines_, OutputArray h_votes_)
138 if (h_votes_.needed())
143 CV_Assert(d_lines.rows == 2 && d_lines.type() == CV_32FC2);
145 h_lines_.create(1, d_lines.cols, CV_32FC2);
146 Mat h_lines = h_lines_.getMat();
147 d_lines.row(0).download(h_lines);
149 if (h_votes_.needed())
151 h_votes_.create(1, d_lines.cols, CV_32SC1);
152 Mat h_votes = h_votes_.getMat();
153 GpuMat d_votes(1, d_lines.cols, CV_32SC1, const_cast<int*>(d_lines.ptr<int>(1)));
154 d_votes.download(h_votes);
158 //////////////////////////////////////////////////////////
161 namespace cv { namespace gpu { namespace device
165 void circlesAccumCenters_gpu(const unsigned int* list, int count, PtrStepi dx, PtrStepi dy, PtrStepSzi accum, int minRadius, int maxRadius, float idp);
166 int buildCentersList_gpu(PtrStepSzi accum, unsigned int* centers, int threshold);
167 int circlesAccumRadius_gpu(const unsigned int* centers, int centersCount, const unsigned int* list, int count,
168 float3* circles, int maxCircles, float dp, int minRadius, int maxRadius, int threshold, bool has20);
172 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)
175 HoughCircles(src, circles, buf, method, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius, maxCircles);
178 void cv::gpu::HoughCircles(const GpuMat& src, GpuMat& circles, HoughCirclesBuf& buf, int method,
179 float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles)
181 using namespace cv::gpu::device::hough;
183 CV_Assert(src.type() == CV_8UC1);
184 CV_Assert(src.cols < std::numeric_limits<unsigned short>::max());
185 CV_Assert(src.rows < std::numeric_limits<unsigned short>::max());
186 CV_Assert(method == CV_HOUGH_GRADIENT);
188 CV_Assert(minRadius > 0 && maxRadius > minRadius);
189 CV_Assert(cannyThreshold > 0);
190 CV_Assert(votesThreshold > 0);
191 CV_Assert(maxCircles > 0);
193 const float idp = 1.0f / dp;
195 cv::gpu::Canny(src, buf.cannyBuf, buf.edges, std::max(cannyThreshold / 2, 1), cannyThreshold);
197 ensureSizeIsEnough(2, src.size().area(), CV_32SC1, buf.list);
198 unsigned int* srcPoints = buf.list.ptr<unsigned int>(0);
199 unsigned int* centers = buf.list.ptr<unsigned int>(1);
201 const int pointsCount = buildPointList_gpu(buf.edges, srcPoints);
202 if (pointsCount == 0)
208 ensureSizeIsEnough(cvCeil(src.rows * idp) + 2, cvCeil(src.cols * idp) + 2, CV_32SC1, buf.accum);
209 buf.accum.setTo(Scalar::all(0));
211 circlesAccumCenters_gpu(srcPoints, pointsCount, buf.cannyBuf.dx, buf.cannyBuf.dy, buf.accum, minRadius, maxRadius, idp);
213 int centersCount = buildCentersList_gpu(buf.accum, centers, votesThreshold);
214 if (centersCount == 0)
222 cv::AutoBuffer<ushort2> oldBuf_(centersCount);
223 cv::AutoBuffer<ushort2> newBuf_(centersCount);
226 ushort2* oldBuf = oldBuf_;
227 ushort2* newBuf = newBuf_;
229 cudaSafeCall( cudaMemcpy(oldBuf, centers, centersCount * sizeof(ushort2), cudaMemcpyDeviceToHost) );
231 const int cellSize = cvRound(minDist);
232 const int gridWidth = (src.cols + cellSize - 1) / cellSize;
233 const int gridHeight = (src.rows + cellSize - 1) / cellSize;
235 std::vector< std::vector<ushort2> > grid(gridWidth * gridHeight);
237 const float minDist2 = minDist * minDist;
239 for (int i = 0; i < centersCount; ++i)
241 ushort2 p = oldBuf[i];
245 int xCell = static_cast<int>(p.x / cellSize);
246 int yCell = static_cast<int>(p.y / cellSize);
254 x1 = std::max(0, x1);
255 y1 = std::max(0, y1);
256 x2 = std::min(gridWidth - 1, x2);
257 y2 = std::min(gridHeight - 1, y2);
259 for (int yy = y1; yy <= y2; ++yy)
261 for (int xx = x1; xx <= x2; ++xx)
263 vector<ushort2>& m = grid[yy * gridWidth + xx];
265 for(size_t j = 0; j < m.size(); ++j)
267 float dx = (float)(p.x - m[j].x);
268 float dy = (float)(p.y - m[j].y);
270 if (dx * dx + dy * dy < minDist2)
283 grid[yCell * gridWidth + xCell].push_back(p);
285 newBuf[newCount++] = p;
289 cudaSafeCall( cudaMemcpy(centers, newBuf, newCount * sizeof(unsigned int), cudaMemcpyHostToDevice) );
290 centersCount = newCount;
293 ensureSizeIsEnough(1, maxCircles, CV_32FC3, circles);
296 const int circlesCount = circlesAccumRadius_gpu(centers, centersCount, srcPoints, pointsCount, circles.ptr<float3>(), maxCircles,
297 dp, minRadius, maxRadius, votesThreshold, devInfo.supports(FEATURE_SET_COMPUTE_20));
299 if (circlesCount > 0)
300 circles.cols = circlesCount;
305 void cv::gpu::HoughCirclesDownload(const GpuMat& d_circles, cv::OutputArray h_circles_)
307 if (d_circles.empty())
309 h_circles_.release();
313 CV_Assert(d_circles.rows == 1 && d_circles.type() == CV_32FC3);
315 h_circles_.create(1, d_circles.cols, CV_32FC3);
316 Mat h_circles = h_circles_.getMat();
317 d_circles.download(h_circles);
320 //////////////////////////////////////////////////////////
323 namespace cv { namespace gpu { namespace device
327 template <typename T>
328 int buildEdgePointList_gpu(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList);
329 void buildRTable_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount,
330 PtrStepSz<short2> r_table, int* r_sizes,
331 short2 templCenter, int levels);
333 void GHT_Ballard_Pos_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount,
334 PtrStepSz<short2> r_table, const int* r_sizes,
336 float dp, int levels);
337 int GHT_Ballard_Pos_findPosInHist_gpu(PtrStepSzi hist, float4* out, int3* votes, int maxSize, float dp, int threshold);
339 void GHT_Ballard_PosScale_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount,
340 PtrStepSz<short2> r_table, const int* r_sizes,
341 PtrStepi hist, int rows, int cols,
342 float minScale, float scaleStep, int scaleRange,
343 float dp, int levels);
344 int GHT_Ballard_PosScale_findPosInHist_gpu(PtrStepi hist, int rows, int cols, int scaleRange, float4* out, int3* votes, int maxSize,
345 float minScale, float scaleStep, float dp, int threshold);
347 void GHT_Ballard_PosRotation_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount,
348 PtrStepSz<short2> r_table, const int* r_sizes,
349 PtrStepi hist, int rows, int cols,
350 float minAngle, float angleStep, int angleRange,
351 float dp, int levels);
352 int GHT_Ballard_PosRotation_findPosInHist_gpu(PtrStepi hist, int rows, int cols, int angleRange, float4* out, int3* votes, int maxSize,
353 float minAngle, float angleStep, float dp, int threshold);
355 void GHT_Guil_Full_setTemplFeatures(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2);
356 void GHT_Guil_Full_setImageFeatures(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2);
357 void GHT_Guil_Full_buildTemplFeatureList_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount,
358 int* sizes, int maxSize,
359 float xi, float angleEpsilon, int levels,
360 float2 center, float maxDist);
361 void GHT_Guil_Full_buildImageFeatureList_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount,
362 int* sizes, int maxSize,
363 float xi, float angleEpsilon, int levels,
364 float2 center, float maxDist);
365 void GHT_Guil_Full_calcOHist_gpu(const int* templSizes, const int* imageSizes, int* OHist,
366 float minAngle, float maxAngle, float angleStep, int angleRange,
367 int levels, int tMaxSize);
368 void GHT_Guil_Full_calcSHist_gpu(const int* templSizes, const int* imageSizes, int* SHist,
369 float angle, float angleEpsilon,
370 float minScale, float maxScale, float iScaleStep, int scaleRange,
371 int levels, int tMaxSize);
372 void GHT_Guil_Full_calcPHist_gpu(const int* templSizes, const int* imageSizes, PtrStepSzi PHist,
373 float angle, float angleEpsilon, float scale,
375 int levels, int tMaxSize);
376 int GHT_Guil_Full_findPosInHist_gpu(PtrStepSzi hist, float4* out, int3* votes, int curSize, int maxSize,
377 float angle, int angleVotes, float scale, int scaleVotes,
378 float dp, int threshold);
384 /////////////////////////////////////
387 template <typename T, class A> void releaseVector(vector<T, A>& v)
393 class GHT_Pos : public GeneralizedHough_GPU
399 void setTemplateImpl(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, Point templCenter);
400 void detectImpl(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, GpuMat& positions);
403 virtual void processTempl() = 0;
404 virtual void processImage() = 0;
406 void buildEdgePointList(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy);
407 void filterMinDist();
408 void convertTo(GpuMat& positions);
424 GpuMat edgePointList;
429 vector<float4> oldPosBuf;
430 vector<int3> oldVoteBuf;
431 vector<float4> newPosBuf;
432 vector<int3> newVoteBuf;
433 vector<int> indexies;
442 void GHT_Pos::setTemplateImpl(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, Point templCenter_)
444 templSize = edges.size();
445 templCenter = templCenter_;
447 ensureSizeIsEnough(templSize, edges.type(), templEdges);
448 ensureSizeIsEnough(templSize, dx.type(), templDx);
449 ensureSizeIsEnough(templSize, dy.type(), templDy);
451 edges.copyTo(templEdges);
458 void GHT_Pos::detectImpl(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, GpuMat& positions)
460 imageSize = edges.size();
462 ensureSizeIsEnough(imageSize, edges.type(), imageEdges);
463 ensureSizeIsEnough(imageSize, dx.type(), imageDx);
464 ensureSizeIsEnough(imageSize, dy.type(), imageDy);
466 edges.copyTo(imageEdges);
480 convertTo(positions);
484 void GHT_Pos::releaseImpl()
487 templCenter = Point(-1, -1);
488 templEdges.release();
493 imageEdges.release();
497 edgePointList.release();
502 releaseVector(oldPosBuf);
503 releaseVector(oldVoteBuf);
504 releaseVector(newPosBuf);
505 releaseVector(newVoteBuf);
506 releaseVector(indexies);
509 void GHT_Pos::buildEdgePointList(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy)
511 using namespace cv::gpu::device::hough;
513 typedef int (*func_t)(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList);
514 static const func_t funcs[] =
519 buildEdgePointList_gpu<short>,
520 buildEdgePointList_gpu<int>,
521 buildEdgePointList_gpu<float>,
525 CV_Assert(edges.type() == CV_8UC1);
526 CV_Assert(dx.size() == edges.size());
527 CV_Assert(dy.type() == dx.type() && dy.size() == edges.size());
529 const func_t func = funcs[dx.depth()];
530 CV_Assert(func != 0);
532 edgePointList.cols = edgePointList.step / sizeof(int);
533 ensureSizeIsEnough(2, edges.size().area(), CV_32SC1, edgePointList);
535 edgePointList.cols = func(edges, dx, dy, edgePointList.ptr<unsigned int>(0), edgePointList.ptr<float>(1));
538 #define votes_cmp_gt(l1, l2) (aux[l1].x > aux[l2].x)
539 static CV_IMPLEMENT_QSORT_EX( sortIndexies, int, votes_cmp_gt, const int3* )
541 void GHT_Pos::filterMinDist()
543 oldPosBuf.resize(posCount);
544 oldVoteBuf.resize(posCount);
546 cudaSafeCall( cudaMemcpy(&oldPosBuf[0], outBuf.ptr(0), posCount * sizeof(float4), cudaMemcpyDeviceToHost) );
547 cudaSafeCall( cudaMemcpy(&oldVoteBuf[0], outBuf.ptr(1), posCount * sizeof(int3), cudaMemcpyDeviceToHost) );
549 indexies.resize(posCount);
550 for (int i = 0; i < posCount; ++i)
552 sortIndexies(&indexies[0], posCount, &oldVoteBuf[0]);
556 newPosBuf.reserve(posCount);
557 newVoteBuf.reserve(posCount);
559 const int cellSize = cvRound(minDist);
560 const int gridWidth = (imageSize.width + cellSize - 1) / cellSize;
561 const int gridHeight = (imageSize.height + cellSize - 1) / cellSize;
563 vector< vector<Point2f> > grid(gridWidth * gridHeight);
565 const double minDist2 = minDist * minDist;
567 for (int i = 0; i < posCount; ++i)
569 const int ind = indexies[i];
571 Point2f p(oldPosBuf[ind].x, oldPosBuf[ind].y);
575 const int xCell = static_cast<int>(p.x / cellSize);
576 const int yCell = static_cast<int>(p.y / cellSize);
584 x1 = std::max(0, x1);
585 y1 = std::max(0, y1);
586 x2 = std::min(gridWidth - 1, x2);
587 y2 = std::min(gridHeight - 1, y2);
589 for (int yy = y1; yy <= y2; ++yy)
591 for (int xx = x1; xx <= x2; ++xx)
593 const vector<Point2f>& m = grid[yy * gridWidth + xx];
595 for(size_t j = 0; j < m.size(); ++j)
597 const Point2f d = p - m[j];
599 if (d.ddot(d) < minDist2)
612 grid[yCell * gridWidth + xCell].push_back(p);
614 newPosBuf.push_back(oldPosBuf[ind]);
615 newVoteBuf.push_back(oldVoteBuf[ind]);
619 posCount = static_cast<int>(newPosBuf.size());
620 cudaSafeCall( cudaMemcpy(outBuf.ptr(0), &newPosBuf[0], posCount * sizeof(float4), cudaMemcpyHostToDevice) );
621 cudaSafeCall( cudaMemcpy(outBuf.ptr(1), &newVoteBuf[0], posCount * sizeof(int3), cudaMemcpyHostToDevice) );
624 void GHT_Pos::convertTo(GpuMat& positions)
626 ensureSizeIsEnough(2, posCount, CV_32FC4, positions);
627 GpuMat(2, posCount, CV_32FC4, outBuf.data, outBuf.step).copyTo(positions);
630 /////////////////////////////////////
633 class GHT_Ballard_Pos : public GHT_Pos
636 AlgorithmInfo* info() const;
646 virtual void calcHist();
647 virtual void findPosInHist();
659 CV_INIT_ALGORITHM(GHT_Ballard_Pos, "GeneralizedHough_GPU.POSITION",
660 obj.info()->addParam(obj, "maxSize", obj.maxSize, false, 0, 0,
661 "Maximal size of inner buffers.");
662 obj.info()->addParam(obj, "minDist", obj.minDist, false, 0, 0,
663 "Minimum distance between the centers of the detected objects.");
664 obj.info()->addParam(obj, "levels", obj.levels, false, 0, 0,
666 obj.info()->addParam(obj, "votesThreshold", obj.votesThreshold, false, 0, 0,
667 "The accumulator threshold for the template centers at the detection stage. The smaller it is, the more false positions may be detected.");
668 obj.info()->addParam(obj, "dp", obj.dp, false, 0, 0,
669 "Inverse ratio of the accumulator resolution to the image resolution."));
671 GHT_Ballard_Pos::GHT_Ballard_Pos()
674 votesThreshold = 100;
678 void GHT_Ballard_Pos::releaseImpl()
680 GHT_Pos::releaseImpl();
688 void GHT_Ballard_Pos::processTempl()
690 using namespace cv::gpu::device::hough;
692 CV_Assert(levels > 0);
694 buildEdgePointList(templEdges, templDx, templDy);
696 ensureSizeIsEnough(levels + 1, maxSize, CV_16SC2, r_table);
697 ensureSizeIsEnough(1, levels + 1, CV_32SC1, r_sizes);
698 r_sizes.setTo(Scalar::all(0));
700 if (edgePointList.cols > 0)
702 buildRTable_gpu(edgePointList.ptr<unsigned int>(0), edgePointList.ptr<float>(1), edgePointList.cols,
703 r_table, r_sizes.ptr<int>(), make_short2(templCenter.x, templCenter.y), levels);
704 min(r_sizes, maxSize, r_sizes);
708 void GHT_Ballard_Pos::processImage()
714 void GHT_Ballard_Pos::calcHist()
716 using namespace cv::gpu::device::hough;
718 CV_Assert(levels > 0 && r_table.rows == (levels + 1) && r_sizes.cols == (levels + 1));
721 const double idp = 1.0 / dp;
723 buildEdgePointList(imageEdges, imageDx, imageDy);
725 ensureSizeIsEnough(cvCeil(imageSize.height * idp) + 2, cvCeil(imageSize.width * idp) + 2, CV_32SC1, hist);
726 hist.setTo(Scalar::all(0));
728 if (edgePointList.cols > 0)
730 GHT_Ballard_Pos_calcHist_gpu(edgePointList.ptr<unsigned int>(0), edgePointList.ptr<float>(1), edgePointList.cols,
731 r_table, r_sizes.ptr<int>(),
737 void GHT_Ballard_Pos::findPosInHist()
739 using namespace cv::gpu::device::hough;
741 CV_Assert(votesThreshold > 0);
743 ensureSizeIsEnough(2, maxSize, CV_32FC4, outBuf);
745 posCount = GHT_Ballard_Pos_findPosInHist_gpu(hist, outBuf.ptr<float4>(0), outBuf.ptr<int3>(1), maxSize, dp, votesThreshold);
748 /////////////////////////////////////
751 class GHT_Ballard_PosScale : public GHT_Ballard_Pos
754 AlgorithmInfo* info() const;
756 GHT_Ballard_PosScale();
760 void findPosInHist();
767 CV_INIT_ALGORITHM(GHT_Ballard_PosScale, "GeneralizedHough_GPU.POSITION_SCALE",
768 obj.info()->addParam(obj, "maxSize", obj.maxSize, false, 0, 0,
769 "Maximal size of inner buffers.");
770 obj.info()->addParam(obj, "minDist", obj.minDist, false, 0, 0,
771 "Minimum distance between the centers of the detected objects.");
772 obj.info()->addParam(obj, "levels", obj.levels, false, 0, 0,
774 obj.info()->addParam(obj, "votesThreshold", obj.votesThreshold, false, 0, 0,
775 "The accumulator threshold for the template centers at the detection stage. The smaller it is, the more false positions may be detected.");
776 obj.info()->addParam(obj, "dp", obj.dp, false, 0, 0,
777 "Inverse ratio of the accumulator resolution to the image resolution.");
778 obj.info()->addParam(obj, "minScale", obj.minScale, false, 0, 0,
779 "Minimal scale to detect.");
780 obj.info()->addParam(obj, "maxScale", obj.maxScale, false, 0, 0,
781 "Maximal scale to detect.");
782 obj.info()->addParam(obj, "scaleStep", obj.scaleStep, false, 0, 0,
785 GHT_Ballard_PosScale::GHT_Ballard_PosScale()
792 void GHT_Ballard_PosScale::calcHist()
794 using namespace cv::gpu::device::hough;
796 CV_Assert(levels > 0 && r_table.rows == (levels + 1) && r_sizes.cols == (levels + 1));
798 CV_Assert(minScale > 0.0 && minScale < maxScale);
799 CV_Assert(scaleStep > 0.0);
801 const double idp = 1.0 / dp;
802 const int scaleRange = cvCeil((maxScale - minScale) / scaleStep);
803 const int rows = cvCeil(imageSize.height * idp);
804 const int cols = cvCeil(imageSize.width * idp);
806 buildEdgePointList(imageEdges, imageDx, imageDy);
808 ensureSizeIsEnough((scaleRange + 2) * (rows + 2), cols + 2, CV_32SC1, hist);
809 hist.setTo(Scalar::all(0));
811 if (edgePointList.cols > 0)
813 GHT_Ballard_PosScale_calcHist_gpu(edgePointList.ptr<unsigned int>(0), edgePointList.ptr<float>(1), edgePointList.cols,
814 r_table, r_sizes.ptr<int>(),
816 minScale, scaleStep, scaleRange, dp, levels);
820 void GHT_Ballard_PosScale::findPosInHist()
822 using namespace cv::gpu::device::hough;
824 CV_Assert(votesThreshold > 0);
826 const double idp = 1.0 / dp;
827 const int scaleRange = cvCeil((maxScale - minScale) / scaleStep);
828 const int rows = cvCeil(imageSize.height * idp);
829 const int cols = cvCeil(imageSize.width * idp);
831 ensureSizeIsEnough(2, maxSize, CV_32FC4, outBuf);
833 posCount = GHT_Ballard_PosScale_findPosInHist_gpu(hist, rows, cols, scaleRange, outBuf.ptr<float4>(0), outBuf.ptr<int3>(1), maxSize, minScale, scaleStep, dp, votesThreshold);
836 /////////////////////////////////////
837 // POSITION & Rotation
839 class GHT_Ballard_PosRotation : public GHT_Ballard_Pos
842 AlgorithmInfo* info() const;
844 GHT_Ballard_PosRotation();
848 void findPosInHist();
855 CV_INIT_ALGORITHM(GHT_Ballard_PosRotation, "GeneralizedHough_GPU.POSITION_ROTATION",
856 obj.info()->addParam(obj, "maxSize", obj.maxSize, false, 0, 0,
857 "Maximal size of inner buffers.");
858 obj.info()->addParam(obj, "minDist", obj.minDist, false, 0, 0,
859 "Minimum distance between the centers of the detected objects.");
860 obj.info()->addParam(obj, "levels", obj.levels, false, 0, 0,
862 obj.info()->addParam(obj, "votesThreshold", obj.votesThreshold, false, 0, 0,
863 "The accumulator threshold for the template centers at the detection stage. The smaller it is, the more false positions may be detected.");
864 obj.info()->addParam(obj, "dp", obj.dp, false, 0, 0,
865 "Inverse ratio of the accumulator resolution to the image resolution.");
866 obj.info()->addParam(obj, "minAngle", obj.minAngle, false, 0, 0,
867 "Minimal rotation angle to detect in degrees.");
868 obj.info()->addParam(obj, "maxAngle", obj.maxAngle, false, 0, 0,
869 "Maximal rotation angle to detect in degrees.");
870 obj.info()->addParam(obj, "angleStep", obj.angleStep, false, 0, 0,
871 "Angle step in degrees."));
873 GHT_Ballard_PosRotation::GHT_Ballard_PosRotation()
880 void GHT_Ballard_PosRotation::calcHist()
882 using namespace cv::gpu::device::hough;
884 CV_Assert(levels > 0 && r_table.rows == (levels + 1) && r_sizes.cols == (levels + 1));
886 CV_Assert(minAngle >= 0.0 && minAngle < maxAngle && maxAngle <= 360.0);
887 CV_Assert(angleStep > 0.0 && angleStep < 360.0);
889 const double idp = 1.0 / dp;
890 const int angleRange = cvCeil((maxAngle - minAngle) / angleStep);
891 const int rows = cvCeil(imageSize.height * idp);
892 const int cols = cvCeil(imageSize.width * idp);
894 buildEdgePointList(imageEdges, imageDx, imageDy);
896 ensureSizeIsEnough((angleRange + 2) * (rows + 2), cols + 2, CV_32SC1, hist);
897 hist.setTo(Scalar::all(0));
899 if (edgePointList.cols > 0)
901 GHT_Ballard_PosRotation_calcHist_gpu(edgePointList.ptr<unsigned int>(0), edgePointList.ptr<float>(1), edgePointList.cols,
902 r_table, r_sizes.ptr<int>(),
904 minAngle, angleStep, angleRange, dp, levels);
908 void GHT_Ballard_PosRotation::findPosInHist()
910 using namespace cv::gpu::device::hough;
912 CV_Assert(votesThreshold > 0);
914 const double idp = 1.0 / dp;
915 const int angleRange = cvCeil((maxAngle - minAngle) / angleStep);
916 const int rows = cvCeil(imageSize.height * idp);
917 const int cols = cvCeil(imageSize.width * idp);
919 ensureSizeIsEnough(2, maxSize, CV_32FC4, outBuf);
921 posCount = GHT_Ballard_PosRotation_findPosInHist_gpu(hist, rows, cols, angleRange, outBuf.ptr<float4>(0), outBuf.ptr<int3>(1), maxSize, minAngle, angleStep, dp, votesThreshold);
924 /////////////////////////////////////////
925 // POSITION & SCALE & ROTATION
927 double toRad(double a)
929 return a * CV_PI / 180.0;
932 double clampAngle(double a)
944 bool angleEq(double a, double b, double eps = 1.0)
946 return (fabs(clampAngle(a - b)) <= eps);
949 class GHT_Guil_Full : public GHT_Pos
952 AlgorithmInfo* info() const;
976 void create(int levels, int maxCapacity, bool isTempl);
980 typedef void (*set_func_t)(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2);
981 typedef void (*build_func_t)(const unsigned int* coordList, const float* thetaList, int pointsCount,
982 int* sizes, int maxSize,
983 float xi, float angleEpsilon, int levels,
984 float2 center, float maxDist);
986 void buildFeatureList(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, Feature& features,
987 set_func_t set_func, build_func_t build_func, bool isTempl, Point2d center = Point2d());
989 void calcOrientation();
990 void calcScale(double angle);
991 void calcPosition(double angle, int angleVotes, double scale, int scaleVotes);
1010 Feature templFeatures;
1011 Feature imageFeatures;
1013 vector< pair<double, int> > angles;
1014 vector< pair<double, int> > scales;
1020 CV_INIT_ALGORITHM(GHT_Guil_Full, "GeneralizedHough_GPU.POSITION_SCALE_ROTATION",
1021 obj.info()->addParam(obj, "minDist", obj.minDist, false, 0, 0,
1022 "Minimum distance between the centers of the detected objects.");
1023 obj.info()->addParam(obj, "maxSize", obj.maxSize, false, 0, 0,
1024 "Maximal size of inner buffers.");
1025 obj.info()->addParam(obj, "xi", obj.xi, false, 0, 0,
1026 "Angle difference in degrees between two points in feature.");
1027 obj.info()->addParam(obj, "levels", obj.levels, false, 0, 0,
1028 "Feature table levels.");
1029 obj.info()->addParam(obj, "angleEpsilon", obj.angleEpsilon, false, 0, 0,
1030 "Maximal difference between angles that treated as equal.");
1031 obj.info()->addParam(obj, "minAngle", obj.minAngle, false, 0, 0,
1032 "Minimal rotation angle to detect in degrees.");
1033 obj.info()->addParam(obj, "maxAngle", obj.maxAngle, false, 0, 0,
1034 "Maximal rotation angle to detect in degrees.");
1035 obj.info()->addParam(obj, "angleStep", obj.angleStep, false, 0, 0,
1036 "Angle step in degrees.");
1037 obj.info()->addParam(obj, "angleThresh", obj.angleThresh, false, 0, 0,
1038 "Angle threshold.");
1039 obj.info()->addParam(obj, "minScale", obj.minScale, false, 0, 0,
1040 "Minimal scale to detect.");
1041 obj.info()->addParam(obj, "maxScale", obj.maxScale, false, 0, 0,
1042 "Maximal scale to detect.");
1043 obj.info()->addParam(obj, "scaleStep", obj.scaleStep, false, 0, 0,
1045 obj.info()->addParam(obj, "scaleThresh", obj.scaleThresh, false, 0, 0,
1046 "Scale threshold.");
1047 obj.info()->addParam(obj, "dp", obj.dp, false, 0, 0,
1048 "Inverse ratio of the accumulator resolution to the image resolution.");
1049 obj.info()->addParam(obj, "posThresh", obj.posThresh, false, 0, 0,
1050 "Position threshold."));
1052 GHT_Guil_Full::GHT_Guil_Full()
1062 angleThresh = 15000;
1073 void GHT_Guil_Full::releaseImpl()
1075 GHT_Pos::releaseImpl();
1077 templFeatures.release();
1078 imageFeatures.release();
1080 releaseVector(angles);
1081 releaseVector(scales);
1084 releaseVector(h_buf);
1087 void GHT_Guil_Full::processTempl()
1089 using namespace cv::gpu::device::hough;
1091 buildFeatureList(templEdges, templDx, templDy, templFeatures,
1092 GHT_Guil_Full_setTemplFeatures, GHT_Guil_Full_buildTemplFeatureList_gpu,
1095 h_buf.resize(templFeatures.sizes.cols);
1096 cudaSafeCall( cudaMemcpy(&h_buf[0], templFeatures.sizes.data, h_buf.size() * sizeof(int), cudaMemcpyDeviceToHost) );
1097 templFeatures.maxSize = *max_element(h_buf.begin(), h_buf.end());
1100 void GHT_Guil_Full::processImage()
1102 using namespace cv::gpu::device::hough;
1104 CV_Assert(levels > 0);
1105 CV_Assert(templFeatures.sizes.cols == levels + 1);
1106 CV_Assert(minAngle >= 0.0 && minAngle < maxAngle && maxAngle <= 360.0);
1107 CV_Assert(angleStep > 0.0 && angleStep < 360.0);
1108 CV_Assert(angleThresh > 0);
1109 CV_Assert(minScale > 0.0 && minScale < maxScale);
1110 CV_Assert(scaleStep > 0.0);
1111 CV_Assert(scaleThresh > 0);
1112 CV_Assert(dp > 0.0);
1113 CV_Assert(posThresh > 0);
1115 const double iAngleStep = 1.0 / angleStep;
1116 const int angleRange = cvCeil((maxAngle - minAngle) * iAngleStep);
1118 const double iScaleStep = 1.0 / scaleStep;
1119 const int scaleRange = cvCeil((maxScale - minScale) * iScaleStep);
1121 const double idp = 1.0 / dp;
1122 const int histRows = cvCeil(imageSize.height * idp);
1123 const int histCols = cvCeil(imageSize.width * idp);
1125 ensureSizeIsEnough(histRows + 2, std::max(angleRange + 1, std::max(scaleRange + 1, histCols + 2)), CV_32SC1, hist);
1126 h_buf.resize(std::max(angleRange + 1, scaleRange + 1));
1128 ensureSizeIsEnough(2, maxSize, CV_32FC4, outBuf);
1130 buildFeatureList(imageEdges, imageDx, imageDy, imageFeatures,
1131 GHT_Guil_Full_setImageFeatures, GHT_Guil_Full_buildImageFeatureList_gpu,
1136 for (size_t i = 0; i < angles.size(); ++i)
1138 const double angle = angles[i].first;
1139 const int angleVotes = angles[i].second;
1143 for (size_t j = 0; j < scales.size(); ++j)
1145 const double scale = scales[j].first;
1146 const int scaleVotes = scales[j].second;
1148 calcPosition(angle, angleVotes, scale, scaleVotes);
1153 void GHT_Guil_Full::Feature::create(int levels, int maxCapacity, bool isTempl)
1157 ensureSizeIsEnough(levels + 1, maxCapacity, CV_32FC2, p1_pos);
1158 ensureSizeIsEnough(levels + 1, maxCapacity, CV_32FC2, p2_pos);
1161 ensureSizeIsEnough(levels + 1, maxCapacity, CV_32FC1, p1_theta);
1163 ensureSizeIsEnough(levels + 1, maxCapacity, CV_32FC1, d12);
1167 ensureSizeIsEnough(levels + 1, maxCapacity, CV_32FC2, r1);
1168 ensureSizeIsEnough(levels + 1, maxCapacity, CV_32FC2, r2);
1171 ensureSizeIsEnough(1, levels + 1, CV_32SC1, sizes);
1172 sizes.setTo(Scalar::all(0));
1177 void GHT_Guil_Full::Feature::release()
1193 void GHT_Guil_Full::buildFeatureList(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, Feature& features,
1194 set_func_t set_func, build_func_t build_func, bool isTempl, Point2d center)
1196 CV_Assert(levels > 0);
1198 const double maxDist = sqrt((double) templSize.width * templSize.width + templSize.height * templSize.height) * maxScale;
1200 features.create(levels, maxSize, isTempl);
1201 set_func(features.p1_pos, features.p1_theta, features.p2_pos, features.d12, features.r1, features.r2);
1203 buildEdgePointList(edges, dx, dy);
1205 if (edgePointList.cols > 0)
1207 build_func(edgePointList.ptr<unsigned int>(0), edgePointList.ptr<float>(1), edgePointList.cols,
1208 features.sizes.ptr<int>(), maxSize, xi, angleEpsilon, levels, make_float2(center.x, center.y), maxDist);
1212 void GHT_Guil_Full::calcOrientation()
1214 using namespace cv::gpu::device::hough;
1216 const double iAngleStep = 1.0 / angleStep;
1217 const int angleRange = cvCeil((maxAngle - minAngle) * iAngleStep);
1219 hist.setTo(Scalar::all(0));
1220 GHT_Guil_Full_calcOHist_gpu(templFeatures.sizes.ptr<int>(), imageFeatures.sizes.ptr<int>(0),
1221 hist.ptr<int>(), minAngle, maxAngle, angleStep, angleRange, levels, templFeatures.maxSize);
1222 cudaSafeCall( cudaMemcpy(&h_buf[0], hist.data, h_buf.size() * sizeof(int), cudaMemcpyDeviceToHost) );
1226 for (int n = 0; n < angleRange; ++n)
1228 if (h_buf[n] >= angleThresh)
1230 const double angle = minAngle + n * angleStep;
1231 angles.push_back(make_pair(angle, h_buf[n]));
1236 void GHT_Guil_Full::calcScale(double angle)
1238 using namespace cv::gpu::device::hough;
1240 const double iScaleStep = 1.0 / scaleStep;
1241 const int scaleRange = cvCeil((maxScale - minScale) * iScaleStep);
1243 hist.setTo(Scalar::all(0));
1244 GHT_Guil_Full_calcSHist_gpu(templFeatures.sizes.ptr<int>(), imageFeatures.sizes.ptr<int>(0),
1245 hist.ptr<int>(), angle, angleEpsilon, minScale, maxScale, iScaleStep, scaleRange, levels, templFeatures.maxSize);
1246 cudaSafeCall( cudaMemcpy(&h_buf[0], hist.data, h_buf.size() * sizeof(int), cudaMemcpyDeviceToHost) );
1250 for (int s = 0; s < scaleRange; ++s)
1252 if (h_buf[s] >= scaleThresh)
1254 const double scale = minScale + s * scaleStep;
1255 scales.push_back(make_pair(scale, h_buf[s]));
1260 void GHT_Guil_Full::calcPosition(double angle, int angleVotes, double scale, int scaleVotes)
1262 using namespace cv::gpu::device::hough;
1264 hist.setTo(Scalar::all(0));
1265 GHT_Guil_Full_calcPHist_gpu(templFeatures.sizes.ptr<int>(), imageFeatures.sizes.ptr<int>(0),
1266 hist, angle, angleEpsilon, scale, dp, levels, templFeatures.maxSize);
1268 posCount = GHT_Guil_Full_findPosInHist_gpu(hist, outBuf.ptr<float4>(0), outBuf.ptr<int3>(1),
1269 posCount, maxSize, angle, angleVotes, scale, scaleVotes, dp, posThresh);
1273 Ptr<GeneralizedHough_GPU> cv::gpu::GeneralizedHough_GPU::create(int method)
1278 CV_Assert( !GHT_Ballard_Pos_info_auto.name().empty() );
1279 return new GHT_Ballard_Pos();
1281 case (GHT_POSITION | GHT_SCALE):
1282 CV_Assert( !GHT_Ballard_PosScale_info_auto.name().empty() );
1283 return new GHT_Ballard_PosScale();
1285 case (GHT_POSITION | GHT_ROTATION):
1286 CV_Assert( !GHT_Ballard_PosRotation_info_auto.name().empty() );
1287 return new GHT_Ballard_PosRotation();
1289 case (GHT_POSITION | GHT_SCALE | GHT_ROTATION):
1290 CV_Assert( !GHT_Guil_Full_info_auto.name().empty() );
1291 return new GHT_Guil_Full();
1294 CV_Error(CV_StsBadArg, "Unsupported method");
1295 return Ptr<GeneralizedHough_GPU>();
1298 cv::gpu::GeneralizedHough_GPU::~GeneralizedHough_GPU()
1302 void cv::gpu::GeneralizedHough_GPU::setTemplate(const GpuMat& templ, int cannyThreshold, Point templCenter)
1304 CV_Assert(templ.type() == CV_8UC1);
1305 CV_Assert(cannyThreshold > 0);
1307 ensureSizeIsEnough(templ.size(), CV_8UC1, edges_);
1308 Canny(templ, cannyBuf_, edges_, cannyThreshold / 2, cannyThreshold);
1310 if (templCenter == Point(-1, -1))
1311 templCenter = Point(templ.cols / 2, templ.rows / 2);
1313 setTemplateImpl(edges_, cannyBuf_.dx, cannyBuf_.dy, templCenter);
1316 void cv::gpu::GeneralizedHough_GPU::setTemplate(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, Point templCenter)
1318 if (templCenter == Point(-1, -1))
1319 templCenter = Point(edges.cols / 2, edges.rows / 2);
1321 setTemplateImpl(edges, dx, dy, templCenter);
1324 void cv::gpu::GeneralizedHough_GPU::detect(const GpuMat& image, GpuMat& positions, int cannyThreshold)
1326 CV_Assert(image.type() == CV_8UC1);
1327 CV_Assert(cannyThreshold > 0);
1329 ensureSizeIsEnough(image.size(), CV_8UC1, edges_);
1330 Canny(image, cannyBuf_, edges_, cannyThreshold / 2, cannyThreshold);
1332 detectImpl(edges_, cannyBuf_.dx, cannyBuf_.dy, positions);
1335 void cv::gpu::GeneralizedHough_GPU::detect(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, GpuMat& positions)
1337 detectImpl(edges, dx, dy, positions);
1340 void cv::gpu::GeneralizedHough_GPU::download(const GpuMat& d_positions, OutputArray h_positions_, OutputArray h_votes_)
1342 if (d_positions.empty())
1344 h_positions_.release();
1345 if (h_votes_.needed())
1350 CV_Assert(d_positions.rows == 2 && d_positions.type() == CV_32FC4);
1352 h_positions_.create(1, d_positions.cols, CV_32FC4);
1353 Mat h_positions = h_positions_.getMat();
1354 d_positions.row(0).download(h_positions);
1356 if (h_votes_.needed())
1358 h_votes_.create(1, d_positions.cols, CV_32SC3);
1359 Mat h_votes = h_votes_.getMat();
1360 GpuMat d_votes(1, d_positions.cols, CV_32SC3, const_cast<int3*>(d_positions.ptr<int3>(1)));
1361 d_votes.download(h_votes);
1365 void cv::gpu::GeneralizedHough_GPU::release()
1368 cannyBuf_.release();
1372 #endif /* !defined (HAVE_CUDA) */