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, Intel Corporation, all rights reserved.
14 // Copyright (C) 2013, OpenCV Foundation, all rights reserved.
15 // Copyright (C) 2014, Itseez, Inc, all rights reserved.
16 // Third party copyrights are property of their respective owners.
18 // Redistribution and use in source and binary forms, with or without modification,
19 // are permitted provided that the following conditions are met:
21 // * Redistribution's of source code must retain the above copyright notice,
22 // this list of conditions and the following disclaimer.
24 // * Redistribution's in binary form must reproduce the above copyright notice,
25 // this list of conditions and the following disclaimer in the documentation
26 // and/or other materials provided with the distribution.
28 // * The name of the copyright holders may not be used to endorse or promote products
29 // derived from this software without specific prior written permission.
31 // This software is provided by the copyright holders and contributors "as is" and
32 // any express or implied warranties, including, but not limited to, the implied
33 // warranties of merchantability and fitness for a particular purpose are disclaimed.
34 // In no event shall the Intel Corporation or contributors be liable for any direct,
35 // indirect, incidental, special, exemplary, or consequential damages
36 // (including, but not limited to, procurement of substitute goods or services;
37 // loss of use, data, or profits; or business interruption) however caused
38 // and on any theory of liability, whether in contract, strict liability,
39 // or tort (including negligence or otherwise) arising in any way out of
40 // the use of this software, even if advised of the possibility of such damage.
44 #include "precomp.hpp"
45 #include "opencl_kernels_imgproc.hpp"
50 // Classical Hough Transform
60 hough_cmp_gt(const int* _aux) : aux(_aux) {}
61 bool operator()(int l1, int l2) const
63 return aux[l1] > aux[l2] || (aux[l1] == aux[l2] && l1 < l2);
70 Here image is an input raster;
71 step is it's step; size characterizes it's ROI;
72 rho and theta are discretization steps (in pixels and radians correspondingly).
73 threshold is the minimum number of pixels in the feature for it
74 to be a candidate for line. lines is the output
75 array of (rho, theta) pairs. linesMax is the buffer size (number of pairs).
76 Functions return the actual number of found lines.
79 HoughLinesStandard( const Mat& img, float rho, float theta,
80 int threshold, std::vector<Vec2f>& lines, int linesMax,
81 double min_theta, double max_theta )
86 CV_Assert( img.type() == CV_8UC1 );
88 const uchar* image = img.ptr();
89 int step = (int)img.step;
91 int height = img.rows;
93 if (max_theta < 0 || max_theta > CV_PI ) {
94 CV_Error( CV_StsBadArg, "max_theta must fall between 0 and pi" );
96 if (min_theta < 0 || min_theta > max_theta ) {
97 CV_Error( CV_StsBadArg, "min_theta must fall between 0 and max_theta" );
99 int numangle = cvRound((max_theta - min_theta) / theta);
100 int numrho = cvRound(((width + height) * 2 + 1) / rho);
102 #if (0 && defined(HAVE_IPP) && !defined(HAVE_IPP_ICV_ONLY) && IPP_VERSION_X100 >= 801)
103 IppiSize srcSize = { width, height };
104 IppPointPolar delta = { rho, theta };
105 IppPointPolar dstRoi[2] = {{(Ipp32f) -(width + height), (Ipp32f) min_theta},{(Ipp32f) (width + height), (Ipp32f) max_theta}};
107 int nz = countNonZero(img);
108 int ipp_linesMax = std::min(linesMax, nz*numangle/threshold);
110 lines.resize(ipp_linesMax);
111 IppStatus ok = ippiHoughLineGetSize_8u_C1R(srcSize, delta, ipp_linesMax, &bufferSize);
112 Ipp8u* buffer = ippsMalloc_8u(bufferSize);
113 if (ok >= 0) ok = ippiHoughLine_Region_8u32f_C1R(image, step, srcSize, (IppPointPolar*) &lines[0], dstRoi, ipp_linesMax, &linesCount, delta, threshold, buffer);
117 lines.resize(linesCount);
124 AutoBuffer<int> _accum((numangle+2) * (numrho+2));
125 std::vector<int> _sort_buf;
126 AutoBuffer<float> _tabSin(numangle);
127 AutoBuffer<float> _tabCos(numangle);
129 float *tabSin = _tabSin, *tabCos = _tabCos;
131 memset( accum, 0, sizeof(accum[0]) * (numangle+2) * (numrho+2) );
133 float ang = static_cast<float>(min_theta);
134 for(int n = 0; n < numangle; ang += theta, n++ )
136 tabSin[n] = (float)(sin((double)ang) * irho);
137 tabCos[n] = (float)(cos((double)ang) * irho);
140 // stage 1. fill accumulator
141 for( i = 0; i < height; i++ )
142 for( j = 0; j < width; j++ )
144 if( image[i * step + j] != 0 )
145 for(int n = 0; n < numangle; n++ )
147 int r = cvRound( j * tabCos[n] + i * tabSin[n] );
148 r += (numrho - 1) / 2;
149 accum[(n+1) * (numrho+2) + r+1]++;
153 // stage 2. find local maximums
154 for(int r = 0; r < numrho; r++ )
155 for(int n = 0; n < numangle; n++ )
157 int base = (n+1) * (numrho+2) + r+1;
158 if( accum[base] > threshold &&
159 accum[base] > accum[base - 1] && accum[base] >= accum[base + 1] &&
160 accum[base] > accum[base - numrho - 2] && accum[base] >= accum[base + numrho + 2] )
161 _sort_buf.push_back(base);
164 // stage 3. sort the detected lines by accumulator value
165 std::sort(_sort_buf.begin(), _sort_buf.end(), hough_cmp_gt(accum));
167 // stage 4. store the first min(total,linesMax) lines to the output buffer
168 linesMax = std::min(linesMax, (int)_sort_buf.size());
169 double scale = 1./(numrho+2);
170 for( i = 0; i < linesMax; i++ )
173 int idx = _sort_buf[i];
174 int n = cvFloor(idx*scale) - 1;
175 int r = idx - (n+1)*(numrho+2) - 1;
176 line.rho = (r - (numrho - 1)*0.5f) * rho;
177 line.angle = n * theta;
178 lines.push_back(Vec2f(line.rho, line.angle));
183 // Multi-Scale variant of Classical Hough Transform
187 hough_index() : value(0), rho(0.f), theta(0.f) {}
188 hough_index(int _val, float _rho, float _theta)
189 : value(_val), rho(_rho), theta(_theta) {}
197 HoughLinesSDiv( const Mat& img,
198 float rho, float theta, int threshold,
200 std::vector<Vec2f>& lines, int linesMax,
201 double min_theta, double max_theta )
203 #define _POINT(row, column)\
204 (image_src[(row)*step+(column)])
207 int ri, ti, ti1, ti0;
209 float r, t; /* Current rho and theta */
210 float rv; /* Some temporary rho value */
215 const float d2r = (float)(CV_PI / 180);
221 std::vector<hough_index> lst;
223 CV_Assert( img.type() == CV_8UC1 );
224 CV_Assert( linesMax > 0 && rho > 0 && theta > 0 );
226 threshold = MIN( threshold, 255 );
228 const uchar* image_src = img.ptr();
229 int step = (int)img.step;
233 float irho = 1 / rho;
234 float itheta = 1 / theta;
235 float srho = rho / srn;
236 float stheta = theta / stn;
237 float isrho = 1 / srho;
238 float istheta = 1 / stheta;
240 int rn = cvFloor( std::sqrt( (double)w * w + (double)h * h ) * irho );
241 int tn = cvFloor( 2 * CV_PI * itheta );
243 lst.push_back(hough_index(threshold, -1.f, 0.f));
245 // Precalculate sin table
246 std::vector<float> _sinTable( 5 * tn * stn );
247 float* sinTable = &_sinTable[0];
249 for( index = 0; index < 5 * tn * stn; index++ )
250 sinTable[index] = (float)cos( stheta * index * 0.2f );
252 std::vector<uchar> _caccum(rn * tn, (uchar)0);
253 uchar* caccum = &_caccum[0];
255 // Counting all feature pixels
256 for( row = 0; row < h; row++ )
257 for( col = 0; col < w; col++ )
258 fn += _POINT( row, col ) != 0;
260 std::vector<int> _x(fn), _y(fn);
261 int* x = &_x[0], *y = &_y[0];
263 // Full Hough Transform (it's accumulator update part)
265 for( row = 0; row < h; row++ )
267 for( col = 0; col < w; col++ )
269 if( _POINT( row, col ))
276 float theta_it; // Value of theta for iterating
278 // Remember the feature point
283 yc = (float) row + 0.5f;
284 xc = (float) col + 0.5f;
286 /* Update the accumulator */
287 t = (float) fabs( cvFastArctan( yc, xc ) * d2r );
288 r = (float) std::sqrt( (double)xc * xc + (double)yc * yc );
290 ti0 = cvFloor( (t + CV_PI*0.5) * itheta );
295 theta_it = theta_it < theta ? theta_it : theta;
296 scale_factor = theta_it * itheta;
297 halftn = cvFloor( CV_PI / theta_it );
298 for( ti1 = 1, phi = theta_it - (float)(CV_PI*0.5), phi1 = (theta_it + t) * itheta;
299 ti1 < halftn; ti1++, phi += theta_it, phi1 += scale_factor )
301 rv = r0 * std::cos( phi );
302 i = cvFloor( rv ) * tn;
303 i += cvFloor( phi1 );
305 assert( i < rn * tn );
306 caccum[i] = (uchar) (caccum[i] + ((i ^ iprev) != 0));
308 if( cmax < caccum[i] )
315 // Starting additional analysis
317 for( ri = 0; ri < rn; ri++ )
319 for( ti = 0; ti < tn; ti++ )
321 if( caccum[ri * tn + ti] > threshold )
326 if( count * 100 > rn * tn )
328 HoughLinesStandard( img, rho, theta, threshold, lines, linesMax, min_theta, max_theta );
332 std::vector<uchar> _buffer(srn * stn + 2);
333 uchar* buffer = &_buffer[0];
334 uchar* mcaccum = buffer + 1;
337 for( ri = 0; ri < rn; ri++ )
339 for( ti = 0; ti < tn; ti++ )
341 if( caccum[ri * tn + ti] > threshold )
344 memset( mcaccum, 0, sfn * sizeof( uchar ));
346 for( index = 0; index < fn; index++ )
351 yc = (float) y[index] + 0.5f;
352 xc = (float) x[index] + 0.5f;
354 // Update the accumulator
355 t = (float) fabs( cvFastArctan( yc, xc ) * d2r );
356 r = (float) std::sqrt( (double)xc * xc + (double)yc * yc ) * isrho;
357 ti0 = cvFloor( (t + CV_PI * 0.5) * istheta );
358 ti2 = (ti * stn - ti0) * 5;
359 r0 = (float) ri *srn;
361 for( ti1 = 0; ti1 < stn; ti1++, ti2 += 5 )
363 rv = r * sinTable[(int) (std::abs( ti2 ))] - r0;
364 i = cvFloor( rv ) * stn + ti1;
366 i = CV_IMAX( i, -1 );
367 i = CV_IMIN( i, sfn );
374 // Find peaks in maccum...
375 for( index = 0; index < sfn; index++ )
378 int pos = (int)(lst.size() - 1);
379 if( pos < 0 || lst[pos].value < mcaccum[index] )
381 hough_index vi(mcaccum[index],
382 index / stn * srho + ri * rho,
383 index % stn * stheta + ti * theta - (float)(CV_PI*0.5));
385 for( ; pos >= 0; pos-- )
387 if( lst[pos].value > vi.value )
389 lst[pos+1] = lst[pos];
392 if( (int)lst.size() > linesMax )
400 for( size_t idx = 0; idx < lst.size(); idx++ )
402 if( lst[idx].rho < 0 )
404 lines.push_back(Vec2f(lst[idx].rho, lst[idx].theta));
409 /****************************************************************************************\
410 * Probabilistic Hough Transform *
411 \****************************************************************************************/
414 HoughLinesProbabilistic( Mat& image,
415 float rho, float theta, int threshold,
416 int lineLength, int lineGap,
417 std::vector<Vec4i>& lines, int linesMax )
420 float irho = 1 / rho;
423 CV_Assert( image.type() == CV_8UC1 );
425 int width = image.cols;
426 int height = image.rows;
428 int numangle = cvRound(CV_PI / theta);
429 int numrho = cvRound(((width + height) * 2 + 1) / rho);
431 #if (0 && defined(HAVE_IPP) && !defined(HAVE_IPP_ICV_ONLY) && IPP_VERSION_X100 >= 801)
432 IppiSize srcSize = { width, height };
433 IppPointPolar delta = { rho, theta };
434 IppiHoughProbSpec* pSpec;
435 int bufferSize, specSize;
436 int ipp_linesMax = std::min(linesMax, numangle*numrho);
438 lines.resize(ipp_linesMax);
439 IppStatus ok = ippiHoughProbLineGetSize_8u_C1R(srcSize, delta, &specSize, &bufferSize);
440 Ipp8u* buffer = ippsMalloc_8u(bufferSize);
441 pSpec = (IppiHoughProbSpec*) malloc(specSize);
442 if (ok >= 0) ok = ippiHoughProbLineInit_8u32f_C1R(srcSize, delta, ippAlgHintNone, pSpec);
443 if (ok >= 0) ok = ippiHoughProbLine_8u32f_C1R(image.data, image.step, srcSize, threshold, lineLength, lineGap, (IppiPoint*) &lines[0], ipp_linesMax, &linesCount, buffer, pSpec);
449 lines.resize(linesCount);
456 Mat accum = Mat::zeros( numangle, numrho, CV_32SC1 );
457 Mat mask( height, width, CV_8UC1 );
458 std::vector<float> trigtab(numangle*2);
460 for( int n = 0; n < numangle; n++ )
462 trigtab[n*2] = (float)(cos((double)n*theta) * irho);
463 trigtab[n*2+1] = (float)(sin((double)n*theta) * irho);
465 const float* ttab = &trigtab[0];
466 uchar* mdata0 = mask.ptr();
467 std::vector<Point> nzloc;
469 // stage 1. collect non-zero image points
470 for( pt.y = 0; pt.y < height; pt.y++ )
472 const uchar* data = image.ptr(pt.y);
473 uchar* mdata = mask.ptr(pt.y);
474 for( pt.x = 0; pt.x < width; pt.x++ )
478 mdata[pt.x] = (uchar)1;
486 int count = (int)nzloc.size();
488 // stage 2. process all the points in random order
489 for( ; count > 0; count-- )
491 // choose random point out of the remaining ones
492 int idx = rng.uniform(0, count);
493 int max_val = threshold-1, max_n = 0;
494 Point point = nzloc[idx];
497 int* adata = accum.ptr<int>();
498 int i = point.y, j = point.x, k, x0, y0, dx0, dy0, xflag;
500 const int shift = 16;
502 // "remove" it by overriding it with the last element
503 nzloc[idx] = nzloc[count-1];
505 // check if it has been excluded already (i.e. belongs to some other line)
506 if( !mdata0[i*width + j] )
509 // update accumulator, find the most probable line
510 for( int n = 0; n < numangle; n++, adata += numrho )
512 int r = cvRound( j * ttab[n*2] + i * ttab[n*2+1] );
513 r += (numrho - 1) / 2;
514 int val = ++adata[r];
522 // if it is too "weak" candidate, continue with another point
523 if( max_val < threshold )
526 // from the current point walk in each direction
527 // along the found line and extract the line segment
528 a = -ttab[max_n*2+1];
532 if( fabs(a) > fabs(b) )
535 dx0 = a > 0 ? 1 : -1;
536 dy0 = cvRound( b*(1 << shift)/fabs(a) );
537 y0 = (y0 << shift) + (1 << (shift-1));
542 dy0 = b > 0 ? 1 : -1;
543 dx0 = cvRound( a*(1 << shift)/fabs(b) );
544 x0 = (x0 << shift) + (1 << (shift-1));
547 for( k = 0; k < 2; k++ )
549 int gap = 0, x = x0, y = y0, dx = dx0, dy = dy0;
554 // walk along the line using fixed-point arithmetics,
555 // stop at the image border or in case of too big gap
556 for( ;; x += dx, y += dy )
572 if( j1 < 0 || j1 >= width || i1 < 0 || i1 >= height )
575 mdata = mdata0 + i1*width + j1;
577 // for each non-zero point:
579 // clear the mask element
587 else if( ++gap > lineGap )
592 good_line = std::abs(line_end[1].x - line_end[0].x) >= lineLength ||
593 std::abs(line_end[1].y - line_end[0].y) >= lineLength;
595 for( k = 0; k < 2; k++ )
597 int x = x0, y = y0, dx = dx0, dy = dy0;
602 // walk along the line using fixed-point arithmetics,
603 // stop at the image border or in case of too big gap
604 for( ;; x += dx, y += dy )
620 mdata = mdata0 + i1*width + j1;
622 // for each non-zero point:
624 // clear the mask element
630 adata = accum.ptr<int>();
631 for( int n = 0; n < numangle; n++, adata += numrho )
633 int r = cvRound( j1 * ttab[n*2] + i1 * ttab[n*2+1] );
634 r += (numrho - 1) / 2;
641 if( i1 == line_end[k].y && j1 == line_end[k].x )
648 Vec4i lr(line_end[0].x, line_end[0].y, line_end[1].x, line_end[1].y);
650 if( (int)lines.size() >= linesMax )
657 static bool ocl_HoughLines(InputArray _src, OutputArray _lines, double rho, double theta, int threshold,
658 double min_theta, double max_theta)
660 CV_Assert(_src.type() == CV_8UC1);
662 if (max_theta < 0 || max_theta > CV_PI ) {
663 CV_Error( CV_StsBadArg, "max_theta must fall between 0 and pi" );
665 if (min_theta < 0 || min_theta > max_theta ) {
666 CV_Error( CV_StsBadArg, "min_theta must fall between 0 and max_theta" );
669 UMat src = _src.getUMat();
671 float irho = 1 / rho;
672 int numangle = cvRound((max_theta - min_theta) / theta);
673 int numrho = cvRound(((src.cols + src.rows) * 2 + 1) / rho);
675 // make list of nonzero points
676 const int pixelsPerWI = 4;
677 int group_size = (src.cols + pixelsPerWI - 1)/pixelsPerWI;
678 ocl::Kernel pointListKernel("make_point_list", ocl::imgproc::hough_lines_oclsrc,
679 format("-D MAKE_POINT_LIST -D GROUP_SIZE=%d -D LOCAL_SIZE", group_size, src.cols));
680 if (pointListKernel.empty())
683 UMat pointsList(1, src.total(), CV_32SC1);
684 UMat total(1, 1, CV_32SC1, Scalar::all(0));
685 pointListKernel.args(ocl::KernelArg::ReadOnly(src), ocl::KernelArg::WriteOnlyNoSize(pointsList),
686 ocl::KernelArg::PtrWriteOnly(total));
687 size_t localThreads[2] = { group_size, 1 };
688 size_t globalThreads[2] = { group_size, src.rows };
690 if (!pointListKernel.run(2, globalThreads, localThreads, false))
693 int total_points = total.getMat(ACCESS_READ).at<int>(0, 0);
694 if (total_points <= 0)
697 // convert src to hough space
698 group_size = (total_points + pixelsPerWI - 1)/pixelsPerWI;
699 ocl::Kernel fillAccumKernel("fill_accum", ocl::imgproc::hough_lines_oclsrc,
700 format("-D FILL_ACCUM -D GROUP_SIZE=%d", group_size));
701 if (fillAccumKernel.empty())
704 UMat accum(numangle + 2, numrho + 2, CV_32SC1, Scalar::all(0));
705 fillAccumKernel.args(ocl::KernelArg::ReadOnlyNoSize(pointsList), ocl::KernelArg::WriteOnly(accum),
706 ocl::KernelArg::Constant(&total_points, sizeof(int)), ocl::KernelArg::Constant(&irho, sizeof(float)),
707 ocl::KernelArg::Constant(&theta, sizeof(float)), ocl::KernelArg::Constant(&numrho, sizeof(int)));
708 globalThreads[0] = numangle; globalThreads[1] = group_size;
710 if (!fillAccumKernel.run(2, globalThreads, NULL, false))
719 void cv::HoughLines( InputArray _image, OutputArray _lines,
720 double rho, double theta, int threshold,
721 double srn, double stn, double min_theta, double max_theta )
723 CV_OCL_RUN(srn == 0 && stn == 0 && _lines.isUMat(),
724 ocl_HoughLines(_image, _lines, rho, theta, threshold, min_theta, max_theta));
726 Mat image = _image.getMat();
727 std::vector<Vec2f> lines;
729 if( srn == 0 && stn == 0 )
730 HoughLinesStandard(image, (float)rho, (float)theta, threshold, lines, INT_MAX, min_theta, max_theta );
732 HoughLinesSDiv(image, (float)rho, (float)theta, threshold, cvRound(srn), cvRound(stn), lines, INT_MAX, min_theta, max_theta);
734 Mat(lines).copyTo(_lines);
738 void cv::HoughLinesP(InputArray _image, OutputArray _lines,
739 double rho, double theta, int threshold,
740 double minLineLength, double maxGap )
742 Mat image = _image.getMat();
743 std::vector<Vec4i> lines;
744 HoughLinesProbabilistic(image, (float)rho, (float)theta, threshold, cvRound(minLineLength), cvRound(maxGap), lines, INT_MAX);
745 Mat(lines).copyTo(_lines);
750 /* Wrapper function for standard hough transform */
752 cvHoughLines2( CvArr* src_image, void* lineStorage, int method,
753 double rho, double theta, int threshold,
754 double param1, double param2,
755 double min_theta, double max_theta )
757 cv::Mat image = cv::cvarrToMat(src_image);
758 std::vector<cv::Vec2f> l2;
759 std::vector<cv::Vec4i> l4;
765 CvSeqBlock lines_block;
766 int lineType, elemSize;
767 int linesMax = INT_MAX;
768 int iparam1, iparam2;
771 CV_Error( CV_StsNullPtr, "NULL destination" );
773 if( rho <= 0 || theta <= 0 || threshold <= 0 )
774 CV_Error( CV_StsOutOfRange, "rho, theta and threshold must be positive" );
776 if( method != CV_HOUGH_PROBABILISTIC )
779 elemSize = sizeof(float)*2;
784 elemSize = sizeof(int)*4;
787 if( CV_IS_STORAGE( lineStorage ))
789 lines = cvCreateSeq( lineType, sizeof(CvSeq), elemSize, (CvMemStorage*)lineStorage );
791 else if( CV_IS_MAT( lineStorage ))
793 mat = (CvMat*)lineStorage;
795 if( !CV_IS_MAT_CONT( mat->type ) || (mat->rows != 1 && mat->cols != 1) )
796 CV_Error( CV_StsBadArg,
797 "The destination matrix should be continuous and have a single row or a single column" );
799 if( CV_MAT_TYPE( mat->type ) != lineType )
800 CV_Error( CV_StsBadArg,
801 "The destination matrix data type is inappropriate, see the manual" );
803 lines = cvMakeSeqHeaderForArray( lineType, sizeof(CvSeq), elemSize, mat->data.ptr,
804 mat->rows + mat->cols - 1, &lines_header, &lines_block );
805 linesMax = lines->total;
809 CV_Error( CV_StsBadArg, "Destination is not CvMemStorage* nor CvMat*" );
811 iparam1 = cvRound(param1);
812 iparam2 = cvRound(param2);
816 case CV_HOUGH_STANDARD:
817 HoughLinesStandard( image, (float)rho,
818 (float)theta, threshold, l2, linesMax, min_theta, max_theta );
820 case CV_HOUGH_MULTI_SCALE:
821 HoughLinesSDiv( image, (float)rho, (float)theta,
822 threshold, iparam1, iparam2, l2, linesMax, min_theta, max_theta );
824 case CV_HOUGH_PROBABILISTIC:
825 HoughLinesProbabilistic( image, (float)rho, (float)theta,
826 threshold, iparam1, iparam2, l4, linesMax );
829 CV_Error( CV_StsBadArg, "Unrecognized method id" );
832 int nlines = (int)(l2.size() + l4.size());
836 if( mat->cols > mat->rows )
844 cv::Mat lx = method == CV_HOUGH_STANDARD || method == CV_HOUGH_MULTI_SCALE ?
845 cv::Mat(nlines, 1, CV_32FC2, &l2[0]) : cv::Mat(nlines, 1, CV_32SC4, &l4[0]);
849 cv::Mat dst(nlines, 1, lx.type(), mat->data.ptr);
854 cvSeqPushMulti(lines, lx.ptr(), nlines);
864 /****************************************************************************************\
866 \****************************************************************************************/
869 icvHoughCirclesGradient( CvMat* img, float dp, float min_dist,
870 int min_radius, int max_radius,
871 int canny_threshold, int acc_threshold,
872 CvSeq* circles, int circles_max )
874 const int SHIFT = 10, ONE = 1 << SHIFT;
875 cv::Ptr<CvMat> dx, dy;
876 cv::Ptr<CvMat> edges, accum, dist_buf;
877 std::vector<int> sort_buf;
878 cv::Ptr<CvMemStorage> storage;
880 int x, y, i, j, k, center_count, nz_count;
881 float min_radius2 = (float)min_radius*min_radius;
882 float max_radius2 = (float)max_radius*max_radius;
883 int rows, cols, arows, acols;
890 edges.reset(cvCreateMat( img->rows, img->cols, CV_8UC1 ));
891 cvCanny( img, edges, MAX(canny_threshold/2,1), canny_threshold, 3 );
893 dx.reset(cvCreateMat( img->rows, img->cols, CV_16SC1 ));
894 dy.reset(cvCreateMat( img->rows, img->cols, CV_16SC1 ));
895 cvSobel( img, dx, 1, 0, 3 );
896 cvSobel( img, dy, 0, 1, 3 );
901 accum.reset(cvCreateMat( cvCeil(img->rows*idp)+2, cvCeil(img->cols*idp)+2, CV_32SC1 ));
904 storage.reset(cvCreateMemStorage());
905 nz = cvCreateSeq( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint), storage );
906 centers = cvCreateSeq( CV_32SC1, sizeof(CvSeq), sizeof(int), storage );
910 arows = accum->rows - 2;
911 acols = accum->cols - 2;
912 adata = accum->data.i;
913 astep = accum->step/sizeof(adata[0]);
914 // Accumulate circle evidence for each edge pixel
915 for( y = 0; y < rows; y++ )
917 const uchar* edges_row = edges->data.ptr + y*edges->step;
918 const short* dx_row = (const short*)(dx->data.ptr + y*dx->step);
919 const short* dy_row = (const short*)(dy->data.ptr + y*dy->step);
921 for( x = 0; x < cols; x++ )
924 int sx, sy, x0, y0, x1, y1, r;
930 if( !edges_row[x] || (vx == 0 && vy == 0) )
933 float mag = std::sqrt(vx*vx+vy*vy);
935 sx = cvRound((vx*idp)*ONE/mag);
936 sy = cvRound((vy*idp)*ONE/mag);
938 x0 = cvRound((x*idp)*ONE);
939 y0 = cvRound((y*idp)*ONE);
940 // Step from min_radius to max_radius in both directions of the gradient
941 for(int k1 = 0; k1 < 2; k1++ )
943 x1 = x0 + min_radius * sx;
944 y1 = y0 + min_radius * sy;
946 for( r = min_radius; r <= max_radius; x1 += sx, y1 += sy, r++ )
948 int x2 = x1 >> SHIFT, y2 = y1 >> SHIFT;
949 if( (unsigned)x2 >= (unsigned)acols ||
950 (unsigned)y2 >= (unsigned)arows )
952 adata[y2*astep + x2]++;
959 cvSeqPush( nz, &pt );
963 nz_count = nz->total;
966 //Find possible circle centers
967 for( y = 1; y < arows - 1; y++ )
969 for( x = 1; x < acols - 1; x++ )
971 int base = y*(acols+2) + x;
972 if( adata[base] > acc_threshold &&
973 adata[base] > adata[base-1] && adata[base] > adata[base+1] &&
974 adata[base] > adata[base-acols-2] && adata[base] > adata[base+acols+2] )
975 cvSeqPush(centers, &base);
979 center_count = centers->total;
983 sort_buf.resize( MAX(center_count,nz_count) );
984 cvCvtSeqToArray( centers, &sort_buf[0] );
986 std::sort(sort_buf.begin(), sort_buf.begin() + center_count, cv::hough_cmp_gt(adata));
987 cvClearSeq( centers );
988 cvSeqPushMulti( centers, &sort_buf[0], center_count );
990 dist_buf.reset(cvCreateMat( 1, nz_count, CV_32FC1 ));
991 ddata = dist_buf->data.fl;
994 min_dist = MAX( min_dist, dp );
995 min_dist *= min_dist;
996 // For each found possible center
997 // Estimate radius and check support
998 for( i = 0; i < centers->total; i++ )
1000 int ofs = *(int*)cvGetSeqElem( centers, i );
1002 x = ofs - (y)*(acols+2);
1003 //Calculate circle's center in pixels
1004 float cx = (float)((x + 0.5f)*dp), cy = (float)(( y + 0.5f )*dp);
1005 float start_dist, dist_sum;
1008 // Check distance with previously detected circles
1009 for( j = 0; j < circles->total; j++ )
1011 float* c = (float*)cvGetSeqElem( circles, j );
1012 if( (c[0] - cx)*(c[0] - cx) + (c[1] - cy)*(c[1] - cy) < min_dist )
1016 if( j < circles->total )
1018 // Estimate best radius
1019 cvStartReadSeq( nz, &reader );
1020 for( j = k = 0; j < nz_count; j++ )
1023 float _dx, _dy, _r2;
1024 CV_READ_SEQ_ELEM( pt, reader );
1025 _dx = cx - pt.x; _dy = cy - pt.y;
1026 _r2 = _dx*_dx + _dy*_dy;
1027 if(min_radius2 <= _r2 && _r2 <= max_radius2 )
1035 int nz_count1 = k, start_idx = nz_count1 - 1;
1036 if( nz_count1 == 0 )
1038 dist_buf->cols = nz_count1;
1039 cvPow( dist_buf, dist_buf, 0.5 );
1040 std::sort(sort_buf.begin(), sort_buf.begin() + nz_count1, cv::hough_cmp_gt((int*)ddata));
1042 dist_sum = start_dist = ddata[sort_buf[nz_count1-1]];
1043 for( j = nz_count1 - 2; j >= 0; j-- )
1045 float d = ddata[sort_buf[j]];
1047 if( d > max_radius )
1050 if( d - start_dist > dr )
1052 float r_cur = ddata[sort_buf[(j + start_idx)/2]];
1053 if( (start_idx - j)*r_best >= max_count*r_cur ||
1054 (r_best < FLT_EPSILON && start_idx - j >= max_count) )
1057 max_count = start_idx - j;
1065 // Check if the circle has enough support
1066 if( max_count > acc_threshold )
1071 c[2] = (float)r_best;
1072 cvSeqPush( circles, c );
1073 if( circles->total > circles_max )
1080 cvHoughCircles( CvArr* src_image, void* circle_storage,
1081 int method, double dp, double min_dist,
1082 double param1, double param2,
1083 int min_radius, int max_radius )
1087 CvMat stub, *img = (CvMat*)src_image;
1090 CvSeq circles_header;
1091 CvSeqBlock circles_block;
1092 int circles_max = INT_MAX;
1093 int canny_threshold = cvRound(param1);
1094 int acc_threshold = cvRound(param2);
1096 img = cvGetMat( img, &stub );
1098 if( !CV_IS_MASK_ARR(img))
1099 CV_Error( CV_StsBadArg, "The source image must be 8-bit, single-channel" );
1101 if( !circle_storage )
1102 CV_Error( CV_StsNullPtr, "NULL destination" );
1104 if( dp <= 0 || min_dist <= 0 || canny_threshold <= 0 || acc_threshold <= 0 )
1105 CV_Error( CV_StsOutOfRange, "dp, min_dist, canny_threshold and acc_threshold must be all positive numbers" );
1107 min_radius = MAX( min_radius, 0 );
1108 if( max_radius <= 0 )
1109 max_radius = MAX( img->rows, img->cols );
1110 else if( max_radius <= min_radius )
1111 max_radius = min_radius + 2;
1113 if( CV_IS_STORAGE( circle_storage ))
1115 circles = cvCreateSeq( CV_32FC3, sizeof(CvSeq),
1116 sizeof(float)*3, (CvMemStorage*)circle_storage );
1118 else if( CV_IS_MAT( circle_storage ))
1120 mat = (CvMat*)circle_storage;
1122 if( !CV_IS_MAT_CONT( mat->type ) || (mat->rows != 1 && mat->cols != 1) ||
1123 CV_MAT_TYPE(mat->type) != CV_32FC3 )
1124 CV_Error( CV_StsBadArg,
1125 "The destination matrix should be continuous and have a single row or a single column" );
1127 circles = cvMakeSeqHeaderForArray( CV_32FC3, sizeof(CvSeq), sizeof(float)*3,
1128 mat->data.ptr, mat->rows + mat->cols - 1, &circles_header, &circles_block );
1129 circles_max = circles->total;
1130 cvClearSeq( circles );
1133 CV_Error( CV_StsBadArg, "Destination is not CvMemStorage* nor CvMat*" );
1137 case CV_HOUGH_GRADIENT:
1138 icvHoughCirclesGradient( img, (float)dp, (float)min_dist,
1139 min_radius, max_radius, canny_threshold,
1140 acc_threshold, circles, circles_max );
1143 CV_Error( CV_StsBadArg, "Unrecognized method id" );
1148 if( mat->cols > mat->rows )
1149 mat->cols = circles->total;
1151 mat->rows = circles->total;
1163 const int STORAGE_SIZE = 1 << 12;
1165 static void seqToMat(const CvSeq* seq, OutputArray _arr)
1167 if( seq && seq->total > 0 )
1169 _arr.create(1, seq->total, seq->flags, -1, true);
1170 Mat arr = _arr.getMat();
1171 cvCvtSeqToArray(seq, arr.ptr());
1179 void cv::HoughCircles( InputArray _image, OutputArray _circles,
1180 int method, double dp, double min_dist,
1181 double param1, double param2,
1182 int minRadius, int maxRadius )
1184 Ptr<CvMemStorage> storage(cvCreateMemStorage(STORAGE_SIZE));
1185 Mat image = _image.getMat();
1186 CvMat c_image = image;
1187 CvSeq* seq = cvHoughCircles( &c_image, storage, method,
1188 dp, min_dist, param1, param2, minRadius, maxRadius );
1189 seqToMat(seq, _circles);