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.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
22 // * Redistribution's in binary form must reproduce the above copyright notice,
23 // this list of conditions and the following disclaimer in the documentation
24 // and/or other materials provided with the distribution.
26 // * The name of Intel Corporation may not be used to endorse or promote products
27 // derived from this software without specific prior written permission.
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
45 #define halfPi ((float)(CV_PI*0.5))
46 #define Pi ((float)CV_PI)
47 #define a0 0 /*-4.172325e-7f*/ /*(-(float)0x7)/((float)0x1000000); */
48 #define a1 1.000025f /*((float)0x1922253)/((float)0x1000000)*2/Pi; */
49 #define a2 -2.652905e-4f /*(-(float)0x2ae6)/((float)0x1000000)*4/(Pi*Pi); */
50 #define a3 -0.165624f /*(-(float)0xa45511)/((float)0x1000000)*8/(Pi*Pi*Pi); */
51 #define a4 -1.964532e-3f /*(-(float)0x30fd3)/((float)0x1000000)*16/(Pi*Pi*Pi*Pi); */
52 #define a5 1.02575e-2f /*((float)0x191cac)/((float)0x1000000)*32/(Pi*Pi*Pi*Pi*Pi); */
53 #define a6 -9.580378e-4f /*(-(float)0x3af27)/((float)0x1000000)*64/(Pi*Pi*Pi*Pi*Pi*Pi); */
55 #define _sin(x) ((((((a6*(x) + a5)*(x) + a4)*(x) + a3)*(x) + a2)*(x) + a1)*(x) + a0)
56 #define _cos(x) _sin(halfPi - (x))
58 /****************************************************************************************\
59 * Classical Hough Transform *
60 \****************************************************************************************/
62 typedef struct CvLinePolar
69 /*=====================================================================================*/
71 #define hough_cmp_gt(l1,l2) (aux[l1] > aux[l2])
73 static CV_IMPLEMENT_QSORT_EX( icvHoughSortDescent32s, int, hough_cmp_gt, const int* )
76 Here image is an input raster;
77 step is it's step; size characterizes it's ROI;
78 rho and theta are discretization steps (in pixels and radians correspondingly).
79 threshold is the minimum number of pixels in the feature for it
80 to be a candidate for line. lines is the output
81 array of (rho, theta) pairs. linesMax is the buffer size (number of pairs).
82 Functions return the actual number of found lines.
85 icvHoughLinesStandard( const CvMat* img, float rho, float theta,
86 int threshold, CvSeq *lines, int linesMax )
93 CV_FUNCNAME( "icvHoughLinesStandard" );
98 int step, width, height;
104 float irho = 1 / rho;
107 CV_ASSERT( CV_IS_MAT(img) && CV_MAT_TYPE(img->type) == CV_8UC1 );
109 image = img->data.ptr;
114 numangle = cvRound(CV_PI / theta);
115 numrho = cvRound(((width + height) * 2 + 1) / rho);
117 CV_CALL( accum = (int*)cvAlloc( sizeof(accum[0]) * (numangle+2) * (numrho+2) ));
118 CV_CALL( sort_buf = (int*)cvAlloc( sizeof(accum[0]) * numangle * numrho ));
119 CV_CALL( tabSin = (float*)cvAlloc( sizeof(tabSin[0]) * numangle ));
120 CV_CALL( tabCos = (float*)cvAlloc( sizeof(tabCos[0]) * numangle ));
121 memset( accum, 0, sizeof(accum[0]) * (numangle+2) * (numrho+2) );
123 for( ang = 0, n = 0; n < numangle; ang += theta, n++ )
125 tabSin[n] = (float)(sin(ang) * irho);
126 tabCos[n] = (float)(cos(ang) * irho);
129 // stage 1. fill accumulator
130 for( i = 0; i < height; i++ )
131 for( j = 0; j < width; j++ )
133 if( image[i * step + j] != 0 )
134 for( n = 0; n < numangle; n++ )
136 r = cvRound( j * tabCos[n] + i * tabSin[n] );
137 r += (numrho - 1) / 2;
138 accum[(n+1) * (numrho+2) + r+1]++;
142 // stage 2. find local maximums
143 for( r = 0; r < numrho; r++ )
144 for( n = 0; n < numangle; n++ )
146 int base = (n+1) * (numrho+2) + r+1;
147 if( accum[base] > threshold &&
148 accum[base] > accum[base - 1] && accum[base] >= accum[base + 1] &&
149 accum[base] > accum[base - numrho - 2] && accum[base] >= accum[base + numrho + 2] )
150 sort_buf[total++] = base;
153 // stage 3. sort the detected lines by accumulator value
154 icvHoughSortDescent32s( sort_buf, total, accum );
156 // stage 4. store the first min(total,linesMax) lines to the output buffer
157 linesMax = MIN(linesMax, total);
158 scale = 1./(numrho+2);
159 for( i = 0; i < linesMax; i++ )
162 int idx = sort_buf[i];
163 int n = cvFloor(idx*scale) - 1;
164 int r = idx - (n+1)*(numrho+2) - 1;
165 line.rho = (r - (numrho - 1)*0.5f) * rho;
166 line.angle = n * theta;
167 cvSeqPush( lines, &line );
179 /****************************************************************************************\
180 * Multi-Scale variant of Classical Hough Transform *
181 \****************************************************************************************/
183 #if defined _MSC_VER && _MSC_VER >= 1200
184 #pragma warning( disable: 4714 )
187 //DECLARE_AND_IMPLEMENT_LIST( _index, h_ );
188 IMPLEMENT_LIST( _index, h_ )
191 icvHoughLinesSDiv( const CvMat* img,
192 float rho, float theta, int threshold,
194 CvSeq* lines, int linesMax )
203 CV_FUNCNAME( "icvHoughLinesSDiv" );
207 #define _POINT(row, column)\
208 (image_src[(row)*step+(column)])
211 int rn, tn; /* number of rho and theta discrete values */
213 int ri, ti, ti1, ti0;
215 float r, t; /* Current rho and theta */
216 float rv; /* Some temporary rho value */
220 float isrho, istheta;
222 const uchar* image_src;
227 const float d2r = (float)(Pi / 180);
237 CV_ASSERT( CV_IS_MAT(img) && CV_MAT_TYPE(img->type) == CV_8UC1 );
238 CV_ASSERT( linesMax > 0 && rho > 0 && theta > 0 );
240 threshold = MIN( threshold, 255 );
242 image_src = img->data.ptr;
250 stheta = theta / stn;
252 istheta = 1 / stheta;
254 rn = cvFloor( sqrt( (double)w * w + (double)h * h ) * irho );
255 tn = cvFloor( 2 * Pi * itheta );
257 list = h_create_list__index( linesMax < 1000 ? linesMax : 1000 );
258 vi.value = threshold;
260 h_add_head__index( list, &vi );
262 /* Precalculating sin */
263 CV_CALL( sinTable = (float*)cvAlloc( 5 * tn * stn * sizeof( float )));
265 for( index = 0; index < 5 * tn * stn; index++ )
267 sinTable[index] = (float)cos( stheta * index * 0.2f );
270 CV_CALL( caccum = (uchar*)cvAlloc( rn * tn * sizeof( caccum[0] )));
271 memset( caccum, 0, rn * tn * sizeof( caccum[0] ));
273 /* Counting all feature pixels */
274 for( row = 0; row < h; row++ )
275 for( col = 0; col < w; col++ )
276 fn += _POINT( row, col ) != 0;
278 CV_CALL( x = (int*)cvAlloc( fn * sizeof(x[0])));
279 CV_CALL( y = (int*)cvAlloc( fn * sizeof(y[0])));
281 /* Full Hough Transform (it's accumulator update part) */
283 for( row = 0; row < h; row++ )
285 for( col = 0; col < w; col++ )
287 if( _POINT( row, col ))
294 float theta_it; /* Value of theta for iterating */
296 /* Remember the feature point */
301 yc = (float) row + 0.5f;
302 xc = (float) col + 0.5f;
304 /* Update the accumulator */
305 t = (float) fabs( cvFastArctan( yc, xc ) * d2r );
306 r = (float) sqrt( (double)xc * xc + (double)yc * yc );
308 ti0 = cvFloor( (t + Pi / 2) * itheta );
313 theta_it = theta_it < theta ? theta_it : theta;
314 scale_factor = theta_it * itheta;
315 halftn = cvFloor( Pi / theta_it );
316 for( ti1 = 1, phi = theta_it - halfPi, phi1 = (theta_it + t) * itheta;
317 ti1 < halftn; ti1++, phi += theta_it, phi1 += scale_factor )
319 rv = r0 * _cos( phi );
320 i = cvFloor( rv ) * tn;
321 i += cvFloor( phi1 );
323 assert( i < rn * tn );
324 caccum[i] = (uchar) (caccum[i] + ((i ^ iprev) != 0));
326 if( cmax < caccum[i] )
333 /* Starting additional analysis */
335 for( ri = 0; ri < rn; ri++ )
337 for( ti = 0; ti < tn; ti++ )
339 if( caccum[ri * tn + ti > threshold] )
346 if( count * 100 > rn * tn )
348 icvHoughLinesStandard( img, rho, theta, threshold, lines, linesMax );
352 CV_CALL( buffer = (uchar *) cvAlloc(srn * stn + 2));
353 mcaccum = buffer + 1;
356 for( ri = 0; ri < rn; ri++ )
358 for( ti = 0; ti < tn; ti++ )
360 if( caccum[ri * tn + ti] > threshold )
363 memset( mcaccum, 0, sfn * sizeof( uchar ));
365 for( index = 0; index < fn; index++ )
370 yc = (float) y[index] + 0.5f;
371 xc = (float) x[index] + 0.5f;
373 /* Update the accumulator */
374 t = (float) fabs( cvFastArctan( yc, xc ) * d2r );
375 r = (float) sqrt( (double)xc * xc + (double)yc * yc ) * isrho;
376 ti0 = cvFloor( (t + Pi * 0.5f) * istheta );
377 ti2 = (ti * stn - ti0) * 5;
378 r0 = (float) ri *srn;
380 for( ti1 = 0 /*, phi = ti*theta - Pi/2 - t */ ; ti1 < stn; ti1++, ti2 += 5
383 /*rv = r*_cos(phi) - r0; */
384 rv = r * sinTable[(int) (abs( ti2 ))] - r0;
385 i = cvFloor( rv ) * stn + ti1;
387 i = CV_IMAX( i, -1 );
388 i = CV_IMIN( i, sfn );
395 /* Find peaks in maccum... */
396 for( index = 0; index < sfn; index++ )
399 pos = h_get_tail_pos__index( list );
400 if( h_get_prev__index( &pos )->value < mcaccum[index] )
402 vi.value = mcaccum[index];
403 vi.rho = index / stn * srho + ri * rho;
404 vi.theta = index % stn * stheta + ti * theta - halfPi;
405 while( h_is_pos__index( pos ))
407 if( h_get__index( pos )->value > mcaccum[index] )
409 h_insert_after__index( list, pos, &vi );
410 if( h_get_count__index( list ) > linesMax )
412 h_remove_tail__index( list );
416 h_get_prev__index( &pos );
418 if( !h_is_pos__index( pos ))
420 h_add_head__index( list, &vi );
421 if( h_get_count__index( list ) > linesMax )
423 h_remove_tail__index( list );
432 pos = h_get_head_pos__index( list );
433 if( h_get_count__index( list ) == 1 )
435 if( h_get__index( pos )->rho < 0 )
437 h_clear_list__index( list );
442 while( h_is_pos__index( pos ))
445 pindex = h_get__index( pos );
446 if( pindex->rho < 0 )
448 /* This should be the last element... */
449 h_get_next__index( &pos );
450 assert( !h_is_pos__index( pos ));
453 line.rho = pindex->rho;
454 line.angle = pindex->theta;
455 cvSeqPush( lines, &line );
457 if( lines->total >= linesMax )
459 h_get_next__index( &pos );
465 h_destroy_list__index( list );
474 /****************************************************************************************\
475 * Probabilistic Hough Transform *
476 \****************************************************************************************/
478 #if defined WIN64 && defined EM64T && _MSC_VER == 1400 && !defined CV_ICC
479 #pragma optimize("",off)
483 icvHoughLinesProbabalistic( CvMat* image,
484 float rho, float theta, int threshold,
485 int lineLength, int lineGap,
486 CvSeq *lines, int linesMax )
491 CvMemStorage* storage = 0;
493 CV_FUNCNAME( "icvHoughLinesProbalistic" );
500 int numangle, numrho;
504 float irho = 1 / rho;
505 CvRNG rng = cvRNG(-1);
509 CV_ASSERT( CV_IS_MAT(image) && CV_MAT_TYPE(image->type) == CV_8UC1 );
512 height = image->rows;
514 numangle = cvRound(CV_PI / theta);
515 numrho = cvRound(((width + height) * 2 + 1) / rho);
517 CV_CALL( accum = cvCreateMat( numangle, numrho, CV_32SC1 ));
518 CV_CALL( mask = cvCreateMat( height, width, CV_8UC1 ));
519 CV_CALL( trigtab = cvCreateMat( 1, numangle, CV_32FC2 ));
522 CV_CALL( storage = cvCreateMemStorage(0) );
524 for( ang = 0, n = 0; n < numangle; ang += theta, n++ )
526 trigtab->data.fl[n*2] = (float)(cos(ang) * irho);
527 trigtab->data.fl[n*2+1] = (float)(sin(ang) * irho);
529 ttab = trigtab->data.fl;
530 mdata0 = mask->data.ptr;
532 CV_CALL( cvStartWriteSeq( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint), storage, &writer ));
534 // stage 1. collect non-zero image points
535 for( pt.y = 0, count = 0; pt.y < height; pt.y++ )
537 const uchar* data = image->data.ptr + pt.y*image->step;
538 uchar* mdata = mdata0 + pt.y*width;
539 for( pt.x = 0; pt.x < width; pt.x++ )
543 mdata[pt.x] = (uchar)1;
544 CV_WRITE_SEQ_ELEM( pt, writer );
551 seq = cvEndWriteSeq( &writer );
554 // stage 2. process all the points in random order
555 for( ; count > 0; count-- )
557 // choose random point out of the remaining ones
558 int idx = cvRandInt(&rng) % count;
559 int max_val = threshold-1, max_n = 0;
560 CvPoint* pt = (CvPoint*)cvGetSeqElem( seq, idx );
561 CvPoint line_end[2] = {{0,0}, {0,0}};
563 int* adata = accum->data.i;
564 int i, j, k, x0, y0, dx0, dy0, xflag;
566 const int shift = 16;
571 // "remove" it by overriding it with the last element
572 *pt = *(CvPoint*)cvGetSeqElem( seq, count-1 );
574 // check if it has been excluded already (i.e. belongs to some other line)
575 if( !mdata0[i*width + j] )
578 // update accumulator, find the most probable line
579 for( n = 0; n < numangle; n++, adata += numrho )
581 r = cvRound( j * ttab[n*2] + i * ttab[n*2+1] );
582 r += (numrho - 1) / 2;
583 int val = ++adata[r];
591 // if it is too "weak" candidate, continue with another point
592 if( max_val < threshold )
595 // from the current point walk in each direction
596 // along the found line and extract the line segment
597 a = -ttab[max_n*2+1];
601 if( fabs(a) > fabs(b) )
604 dx0 = a > 0 ? 1 : -1;
605 dy0 = cvRound( b*(1 << shift)/fabs(a) );
606 y0 = (y0 << shift) + (1 << (shift-1));
611 dy0 = b > 0 ? 1 : -1;
612 dx0 = cvRound( a*(1 << shift)/fabs(b) );
613 x0 = (x0 << shift) + (1 << (shift-1));
616 for( k = 0; k < 2; k++ )
618 int gap = 0, x = x0, y = y0, dx = dx0, dy = dy0;
623 // walk along the line using fixed-point arithmetics,
624 // stop at the image border or in case of too big gap
625 for( ;; x += dx, y += dy )
641 if( j1 < 0 || j1 >= width || i1 < 0 || i1 >= height )
644 mdata = mdata0 + i1*width + j1;
646 // for each non-zero point:
648 // clear the mask element
656 else if( ++gap > lineGap )
661 good_line = abs(line_end[1].x - line_end[0].x) >= lineLength ||
662 abs(line_end[1].y - line_end[0].y) >= lineLength;
664 for( k = 0; k < 2; k++ )
666 int x = x0, y = y0, dx = dx0, dy = dy0;
671 // walk along the line using fixed-point arithmetics,
672 // stop at the image border or in case of too big gap
673 for( ;; x += dx, y += dy )
689 mdata = mdata0 + i1*width + j1;
691 // for each non-zero point:
693 // clear the mask element
699 adata = accum->data.i;
700 for( n = 0; n < numangle; n++, adata += numrho )
702 r = cvRound( j1 * ttab[n*2] + i1 * ttab[n*2+1] );
703 r += (numrho - 1) / 2;
710 if( i1 == line_end[k].y && j1 == line_end[k].x )
717 CvRect lr = { line_end[0].x, line_end[0].y, line_end[1].x, line_end[1].y };
718 cvSeqPush( lines, &lr );
719 if( lines->total >= linesMax )
726 cvReleaseMat( &accum );
727 cvReleaseMat( &mask );
728 cvReleaseMat( &trigtab );
729 cvReleaseMemStorage( &storage );
733 #if defined WIN64 && defined EM64T && _MSC_VER == 1400 && !defined CV_ICC
734 #pragma optimize("",on)
738 /* Wrapper function for standard hough transform */
740 cvHoughLines2( CvArr* src_image, void* lineStorage, int method,
741 double rho, double theta, int threshold,
742 double param1, double param2 )
746 CV_FUNCNAME( "cvHoughLines" );
750 CvMat stub, *img = (CvMat*)src_image;
754 CvSeqBlock lines_block;
755 int lineType, elemSize;
756 int linesMax = INT_MAX;
757 int iparam1, iparam2;
759 CV_CALL( img = cvGetMat( img, &stub ));
761 if( !CV_IS_MASK_ARR(img))
762 CV_ERROR( CV_StsBadArg, "The source image must be 8-bit, single-channel" );
765 CV_ERROR( CV_StsNullPtr, "NULL destination" );
767 if( rho <= 0 || theta <= 0 || threshold <= 0 )
768 CV_ERROR( CV_StsOutOfRange, "rho, theta and threshold must be positive" );
770 if( method != CV_HOUGH_PROBABILISTIC )
773 elemSize = sizeof(float)*2;
778 elemSize = sizeof(int)*4;
781 if( CV_IS_STORAGE( lineStorage ))
783 CV_CALL( lines = cvCreateSeq( lineType, sizeof(CvSeq), elemSize, (CvMemStorage*)lineStorage ));
785 else if( CV_IS_MAT( lineStorage ))
787 mat = (CvMat*)lineStorage;
789 if( !CV_IS_MAT_CONT( mat->type ) || mat->rows != 1 && mat->cols != 1 )
790 CV_ERROR( CV_StsBadArg,
791 "The destination matrix should be continuous and have a single row or a single column" );
793 if( CV_MAT_TYPE( mat->type ) != lineType )
794 CV_ERROR( CV_StsBadArg,
795 "The destination matrix data type is inappropriate, see the manual" );
797 CV_CALL( lines = cvMakeSeqHeaderForArray( lineType, sizeof(CvSeq), elemSize, mat->data.ptr,
798 mat->rows + mat->cols - 1, &lines_header, &lines_block ));
799 linesMax = lines->total;
800 CV_CALL( cvClearSeq( lines ));
804 CV_ERROR( CV_StsBadArg, "Destination is not CvMemStorage* nor CvMat*" );
807 iparam1 = cvRound(param1);
808 iparam2 = cvRound(param2);
812 case CV_HOUGH_STANDARD:
813 CV_CALL( icvHoughLinesStandard( img, (float)rho,
814 (float)theta, threshold, lines, linesMax ));
816 case CV_HOUGH_MULTI_SCALE:
817 CV_CALL( icvHoughLinesSDiv( img, (float)rho, (float)theta,
818 threshold, iparam1, iparam2, lines, linesMax ));
820 case CV_HOUGH_PROBABILISTIC:
821 CV_CALL( icvHoughLinesProbabalistic( img, (float)rho, (float)theta,
822 threshold, iparam1, iparam2, lines, linesMax ));
825 CV_ERROR( CV_StsBadArg, "Unrecognized method id" );
830 if( mat->cols > mat->rows )
831 mat->cols = lines->total;
833 mat->rows = lines->total;
846 /****************************************************************************************\
848 \****************************************************************************************/
851 icvHoughCirclesGradient( CvMat* img, float dp, float min_dist,
852 int min_radius, int max_radius,
853 int canny_threshold, int acc_threshold,
854 CvSeq* circles, int circles_max )
856 const int SHIFT = 10, ONE = 1 << SHIFT, R_THRESH = 30;
857 CvMat *dx = 0, *dy = 0;
862 CvMemStorage* storage = 0;
864 CV_FUNCNAME( "icvHoughCirclesGradient" );
868 int x, y, i, j, center_count, nz_count;
869 int rows, cols, arows, acols;
876 CV_CALL( edges = cvCreateMat( img->rows, img->cols, CV_8UC1 ));
877 CV_CALL( cvCanny( img, edges, MAX(canny_threshold/2,1), canny_threshold, 3 ));
879 CV_CALL( dx = cvCreateMat( img->rows, img->cols, CV_16SC1 ));
880 CV_CALL( dy = cvCreateMat( img->rows, img->cols, CV_16SC1 ));
881 CV_CALL( cvSobel( img, dx, 1, 0, 3 ));
882 CV_CALL( cvSobel( img, dy, 0, 1, 3 ));
887 CV_CALL( accum = cvCreateMat( cvCeil(img->rows*idp)+2, cvCeil(img->cols*idp)+2, CV_32SC1 ));
888 CV_CALL( cvZero(accum));
890 CV_CALL( storage = cvCreateMemStorage() );
891 CV_CALL( nz = cvCreateSeq( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint), storage ));
892 CV_CALL( centers = cvCreateSeq( CV_32SC1, sizeof(CvSeq), sizeof(int), storage ));
896 arows = accum->rows - 2;
897 acols = accum->cols - 2;
898 adata = accum->data.i;
899 astep = accum->step/sizeof(adata[0]);
901 for( y = 0; y < rows; y++ )
903 const uchar* edges_row = edges->data.ptr + y*edges->step;
904 const short* dx_row = (const short*)(dx->data.ptr + y*dx->step);
905 const short* dy_row = (const short*)(dy->data.ptr + y*dy->step);
907 for( x = 0; x < cols; x++ )
910 int sx, sy, x0, y0, x1, y1, r, k;
916 if( !edges_row[x] || vx == 0 && vy == 0 )
919 if( fabs(vx) < fabs(vy) )
921 sx = cvRound(vx*ONE/fabs(vy));
922 sy = vy < 0 ? -ONE : ONE;
927 sy = cvRound(vy*ONE/fabs(vx));
928 sx = vx < 0 ? -ONE : ONE;
931 x0 = cvRound((x*idp)*ONE) + ONE + (ONE/2);
932 y0 = cvRound((y*idp)*ONE) + ONE + (ONE/2);
934 for( k = 0; k < 2; k++ )
936 x0 += min_radius * sx;
937 y0 += min_radius * sy;
939 for( x1 = x0, y1 = y0, r = min_radius; r <= max_radius; x1 += sx, y1 += sy, r++ )
941 int x2 = x1 >> SHIFT, y2 = y1 >> SHIFT;
942 if( (unsigned)x2 >= (unsigned)acols ||
943 (unsigned)y2 >= (unsigned)arows )
945 adata[y2*astep + x2]++;
948 x0 -= min_radius * sx;
949 y0 -= min_radius * sy;
954 cvSeqPush( nz, &pt );
958 nz_count = nz->total;
962 for( y = 1; y < arows - 1; y++ )
964 for( x = 1; x < acols - 1; x++ )
966 int base = y*(acols+2) + x;
967 if( adata[base] > acc_threshold &&
968 adata[base] > adata[base-1] && adata[base] > adata[base+1] &&
969 adata[base] > adata[base-acols-2] && adata[base] > adata[base+acols+2] )
970 cvSeqPush(centers, &base);
974 center_count = centers->total;
978 CV_CALL( sort_buf = (int*)cvAlloc( MAX(center_count,nz_count)*sizeof(sort_buf[0]) ));
979 cvCvtSeqToArray( centers, sort_buf );
981 icvHoughSortDescent32s( sort_buf, center_count, adata );
982 cvClearSeq( centers );
983 cvSeqPushMulti( centers, sort_buf, center_count );
985 CV_CALL( dist_buf = cvCreateMat( 1, nz_count, CV_32FC1 ));
986 ddata = dist_buf->data.fl;
989 min_dist = MAX( min_dist, dp );
990 min_dist *= min_dist;
992 for( i = 0; i < centers->total; i++ )
994 int ofs = *(int*)cvGetSeqElem( centers, i );
995 y = ofs/(acols+2) - 1;
996 x = ofs - (y+1)*(acols+2) - 1;
997 float cx = (float)(x*dp), cy = (float)(y*dp);
998 int start_idx = nz_count - 1;
999 float start_dist, dist_sum;
1000 float r_best = 0, c[3];
1001 int max_count = R_THRESH;
1003 for( j = 0; j < circles->total; j++ )
1005 float* c = (float*)cvGetSeqElem( circles, j );
1006 if( (c[0] - cx)*(c[0] - cx) + (c[1] - cy)*(c[1] - cy) < min_dist )
1010 if( j < circles->total )
1013 cvStartReadSeq( nz, &reader );
1014 for( j = 0; j < nz_count; j++ )
1018 CV_READ_SEQ_ELEM( pt, reader );
1019 _dx = cx - pt.x; _dy = cy - pt.y;
1020 ddata[j] = _dx*_dx + _dy*_dy;
1024 cvPow( dist_buf, dist_buf, 0.5 );
1025 icvHoughSortDescent32s( sort_buf, nz_count, (int*)ddata );
1027 dist_sum = start_dist = ddata[sort_buf[nz_count-1]];
1028 for( j = nz_count - 2; j >= 0; j-- )
1030 float d = ddata[sort_buf[j]];
1032 if( d > max_radius )
1035 if( d - start_dist > dr )
1037 float r_cur = ddata[sort_buf[(j + start_idx)/2]];
1038 if( (start_idx - j)*r_best >= max_count*r_cur ||
1039 r_best < FLT_EPSILON && start_idx - j >= max_count )
1042 max_count = start_idx - j;
1051 if( max_count > R_THRESH )
1055 c[2] = (float)r_best;
1056 cvSeqPush( circles, c );
1057 if( circles->total > circles_max )
1064 cvReleaseMat( &dist_buf );
1065 cvFree( &sort_buf );
1066 cvReleaseMemStorage( &storage );
1067 cvReleaseMat( &edges );
1068 cvReleaseMat( &dx );
1069 cvReleaseMat( &dy );
1070 cvReleaseMat( &accum );
1074 cvHoughCircles( CvArr* src_image, void* circle_storage,
1075 int method, double dp, double min_dist,
1076 double param1, double param2,
1077 int min_radius, int max_radius )
1081 CV_FUNCNAME( "cvHoughCircles" );
1085 CvMat stub, *img = (CvMat*)src_image;
1088 CvSeq circles_header;
1089 CvSeqBlock circles_block;
1090 int circles_max = INT_MAX;
1091 int canny_threshold = cvRound(param1);
1092 int acc_threshold = cvRound(param2);
1094 CV_CALL( img = cvGetMat( img, &stub ));
1096 if( !CV_IS_MASK_ARR(img))
1097 CV_ERROR( CV_StsBadArg, "The source image must be 8-bit, single-channel" );
1099 if( !circle_storage )
1100 CV_ERROR( CV_StsNullPtr, "NULL destination" );
1102 if( dp <= 0 || min_dist <= 0 || canny_threshold <= 0 || acc_threshold <= 0 )
1103 CV_ERROR( CV_StsOutOfRange, "dp, min_dist, canny_threshold and acc_threshold must be all positive numbers" );
1105 min_radius = MAX( min_radius, 0 );
1106 if( max_radius <= 0 )
1107 max_radius = MAX( img->rows, img->cols );
1108 else if( max_radius <= min_radius )
1109 max_radius = min_radius + 2;
1111 if( CV_IS_STORAGE( circle_storage ))
1113 CV_CALL( circles = cvCreateSeq( CV_32FC3, sizeof(CvSeq),
1114 sizeof(float)*3, (CvMemStorage*)circle_storage ));
1116 else if( CV_IS_MAT( circle_storage ))
1118 mat = (CvMat*)circle_storage;
1120 if( !CV_IS_MAT_CONT( mat->type ) || mat->rows != 1 && mat->cols != 1 ||
1121 CV_MAT_TYPE(mat->type) != CV_32FC3 )
1122 CV_ERROR( CV_StsBadArg,
1123 "The destination matrix should be continuous and have a single row or a single column" );
1125 CV_CALL( circles = cvMakeSeqHeaderForArray( CV_32FC3, sizeof(CvSeq), sizeof(float)*3,
1126 mat->data.ptr, mat->rows + mat->cols - 1, &circles_header, &circles_block ));
1127 circles_max = circles->total;
1128 CV_CALL( cvClearSeq( circles ));
1132 CV_ERROR( CV_StsBadArg, "Destination is not CvMemStorage* nor CvMat*" );
1137 case CV_HOUGH_GRADIENT:
1138 CV_CALL( 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;