1 /*M/////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 4 // 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. 8 // 9 // 10 // Intel License Agreement 11 // For Open Source Computer Vision Library 12 // 13 // Copyright (C) 2000, Intel Corporation, all rights reserved. 14 // Third party copyrights are property of their respective owners. 15 // 16 // Redistribution and use in source and binary forms, with or without modification, 17 // are permitted provided that the following conditions are met: 18 // 19 // * Redistribution's of source code must retain the above copyright notice, 20 // this list of conditions and the following disclaimer. 21 // 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. 25 // 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. 28 // 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. 39 // 40 //M*/ 41 42 #include "_cv.h" 43 #include "_cvlist.h" 44 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); */ 54 55 #define _sin(x) ((((((a6*(x) + a5)*(x) + a4)*(x) + a3)*(x) + a2)*(x) + a1)*(x) + a0) 56 #define _cos(x) _sin(halfPi - (x)) 57 58 /****************************************************************************************\ 59 * Classical Hough Transform * 60 \****************************************************************************************/ 61 62 typedef struct CvLinePolar 63 { 64 float rho; 65 float angle; 66 } 67 CvLinePolar; 68 69 /*=====================================================================================*/ 70 71 #define hough_cmp_gt(l1,l2) (aux[l1] > aux[l2]) 72 73 static CV_IMPLEMENT_QSORT_EX( icvHoughSortDescent32s, int, hough_cmp_gt, const int* ) 74 75 /* 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. 83 */ 84 static void 85 icvHoughLinesStandard( const CvMat* img, float rho, float theta, 86 int threshold, CvSeq *lines, int linesMax ) 87 { 88 int *accum = 0; 89 int *sort_buf=0; 90 float *tabSin = 0; 91 float *tabCos = 0; 92 93 CV_FUNCNAME( "icvHoughLinesStandard" ); 94 95 __BEGIN__; 96 97 const uchar* image; 98 int step, width, height; 99 int numangle, numrho; 100 int total = 0; 101 float ang; 102 int r, n; 103 int i, j; 104 float irho = 1 / rho; 105 double scale; 106 107 CV_ASSERT( CV_IS_MAT(img) && CV_MAT_TYPE(img->type) == CV_8UC1 ); 108 109 image = img->data.ptr; 110 step = img->step; 111 width = img->cols; 112 height = img->rows; 113 114 numangle = cvRound(CV_PI / theta); 115 numrho = cvRound(((width + height) * 2 + 1) / rho); 116 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) ); 122 123 for( ang = 0, n = 0; n < numangle; ang += theta, n++ ) 124 { 125 tabSin[n] = (float)(sin(ang) * irho); 126 tabCos[n] = (float)(cos(ang) * irho); 127 } 128 129 // stage 1. fill accumulator 130 for( i = 0; i < height; i++ ) 131 for( j = 0; j < width; j++ ) 132 { 133 if( image[i * step + j] != 0 ) 134 for( n = 0; n < numangle; n++ ) 135 { 136 r = cvRound( j * tabCos[n] + i * tabSin[n] ); 137 r += (numrho - 1) / 2; 138 accum[(n+1) * (numrho+2) + r+1]++; 139 } 140 } 141 142 // stage 2. find local maximums 143 for( r = 0; r < numrho; r++ ) 144 for( n = 0; n < numangle; n++ ) 145 { 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; 151 } 152 153 // stage 3. sort the detected lines by accumulator value 154 icvHoughSortDescent32s( sort_buf, total, accum ); 155 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++ ) 160 { 161 CvLinePolar line; 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 ); 168 } 169 170 __END__; 171 172 cvFree( &sort_buf ); 173 cvFree( &tabSin ); 174 cvFree( &tabCos ); 175 cvFree( &accum ); 176 } 177 178 179 /****************************************************************************************\ 180 * Multi-Scale variant of Classical Hough Transform * 181 \****************************************************************************************/ 182 183 #if defined _MSC_VER && _MSC_VER >= 1200 184 #pragma warning( disable: 4714 ) 185 #endif 186 187 //DECLARE_AND_IMPLEMENT_LIST( _index, h_ ); 188 IMPLEMENT_LIST( _index, h_ ) 189 190 static void 191 icvHoughLinesSDiv( const CvMat* img, 192 float rho, float theta, int threshold, 193 int srn, int stn, 194 CvSeq* lines, int linesMax ) 195 { 196 uchar *caccum = 0; 197 uchar *buffer = 0; 198 float *sinTable = 0; 199 int *x = 0; 200 int *y = 0; 201 _CVLIST *list = 0; 202 203 CV_FUNCNAME( "icvHoughLinesSDiv" ); 204 205 __BEGIN__; 206 207 #define _POINT(row, column)\ 208 (image_src[(row)*step+(column)]) 209 210 uchar *mcaccum = 0; 211 int rn, tn; /* number of rho and theta discrete values */ 212 int index, i; 213 int ri, ti, ti1, ti0; 214 int row, col; 215 float r, t; /* Current rho and theta */ 216 float rv; /* Some temporary rho value */ 217 float irho; 218 float itheta; 219 float srho, stheta; 220 float isrho, istheta; 221 222 const uchar* image_src; 223 int w, h, step; 224 int fn = 0; 225 float xc, yc; 226 227 const float d2r = (float)(Pi / 180); 228 int sfn = srn * stn; 229 int fi; 230 int count; 231 int cmax = 0; 232 233 CVPOS pos; 234 _index *pindex; 235 _index vi; 236 237 CV_ASSERT( CV_IS_MAT(img) && CV_MAT_TYPE(img->type) == CV_8UC1 ); 238 CV_ASSERT( linesMax > 0 && rho > 0 && theta > 0 ); 239 240 threshold = MIN( threshold, 255 ); 241 242 image_src = img->data.ptr; 243 step = img->step; 244 w = img->cols; 245 h = img->rows; 246 247 irho = 1 / rho; 248 itheta = 1 / theta; 249 srho = rho / srn; 250 stheta = theta / stn; 251 isrho = 1 / srho; 252 istheta = 1 / stheta; 253 254 rn = cvFloor( sqrt( (double)w * w + (double)h * h ) * irho ); 255 tn = cvFloor( 2 * Pi * itheta ); 256 257 list = h_create_list__index( linesMax < 1000 ? linesMax : 1000 ); 258 vi.value = threshold; 259 vi.rho = -1; 260 h_add_head__index( list, &vi ); 261 262 /* Precalculating sin */ 263 CV_CALL( sinTable = (float*)cvAlloc( 5 * tn * stn * sizeof( float ))); 264 265 for( index = 0; index < 5 * tn * stn; index++ ) 266 { 267 sinTable[index] = (float)cos( stheta * index * 0.2f ); 268 } 269 270 CV_CALL( caccum = (uchar*)cvAlloc( rn * tn * sizeof( caccum[0] ))); 271 memset( caccum, 0, rn * tn * sizeof( caccum[0] )); 272 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; 277 278 CV_CALL( x = (int*)cvAlloc( fn * sizeof(x[0]))); 279 CV_CALL( y = (int*)cvAlloc( fn * sizeof(y[0]))); 280 281 /* Full Hough Transform (it's accumulator update part) */ 282 fi = 0; 283 for( row = 0; row < h; row++ ) 284 { 285 for( col = 0; col < w; col++ ) 286 { 287 if( _POINT( row, col )) 288 { 289 int halftn; 290 float r0; 291 float scale_factor; 292 int iprev = -1; 293 float phi, phi1; 294 float theta_it; /* Value of theta for iterating */ 295 296 /* Remember the feature point */ 297 x[fi] = col; 298 y[fi] = row; 299 fi++; 300 301 yc = (float) row + 0.5f; 302 xc = (float) col + 0.5f; 303 304 /* Update the accumulator */ 305 t = (float) fabs( cvFastArctan( yc, xc ) * d2r ); 306 r = (float) sqrt( (double)xc * xc + (double)yc * yc ); 307 r0 = r * irho; 308 ti0 = cvFloor( (t + Pi / 2) * itheta ); 309 310 caccum[ti0]++; 311 312 theta_it = rho / r; 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 ) 318 { 319 rv = r0 * _cos( phi ); 320 i = cvFloor( rv ) * tn; 321 i += cvFloor( phi1 ); 322 assert( i >= 0 ); 323 assert( i < rn * tn ); 324 caccum[i] = (uchar) (caccum[i] + ((i ^ iprev) != 0)); 325 iprev = i; 326 if( cmax < caccum[i] ) 327 cmax = caccum[i]; 328 } 329 } 330 } 331 } 332 333 /* Starting additional analysis */ 334 count = 0; 335 for( ri = 0; ri < rn; ri++ ) 336 { 337 for( ti = 0; ti < tn; ti++ ) 338 { 339 if( caccum[ri * tn + ti > threshold] ) 340 { 341 count++; 342 } 343 } 344 } 345 346 if( count * 100 > rn * tn ) 347 { 348 icvHoughLinesStandard( img, rho, theta, threshold, lines, linesMax ); 349 EXIT; 350 } 351 352 CV_CALL( buffer = (uchar *) cvAlloc(srn * stn + 2)); 353 mcaccum = buffer + 1; 354 355 count = 0; 356 for( ri = 0; ri < rn; ri++ ) 357 { 358 for( ti = 0; ti < tn; ti++ ) 359 { 360 if( caccum[ri * tn + ti] > threshold ) 361 { 362 count++; 363 memset( mcaccum, 0, sfn * sizeof( uchar )); 364 365 for( index = 0; index < fn; index++ ) 366 { 367 int ti2; 368 float r0; 369 370 yc = (float) y[index] + 0.5f; 371 xc = (float) x[index] + 0.5f; 372 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; 379 380 for( ti1 = 0 /*, phi = ti*theta - Pi/2 - t */ ; ti1 < stn; ti1++, ti2 += 5 381 /*phi += stheta */ ) 382 { 383 /*rv = r*_cos(phi) - r0; */ 384 rv = r * sinTable[(int) (abs( ti2 ))] - r0; 385 i = cvFloor( rv ) * stn + ti1; 386 387 i = CV_IMAX( i, -1 ); 388 i = CV_IMIN( i, sfn ); 389 mcaccum[i]++; 390 assert( i >= -1 ); 391 assert( i <= sfn ); 392 } 393 } 394 395 /* Find peaks in maccum... */ 396 for( index = 0; index < sfn; index++ ) 397 { 398 i = 0; 399 pos = h_get_tail_pos__index( list ); 400 if( h_get_prev__index( &pos )->value < mcaccum[index] ) 401 { 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 )) 406 { 407 if( h_get__index( pos )->value > mcaccum[index] ) 408 { 409 h_insert_after__index( list, pos, &vi ); 410 if( h_get_count__index( list ) > linesMax ) 411 { 412 h_remove_tail__index( list ); 413 } 414 break; 415 } 416 h_get_prev__index( &pos ); 417 } 418 if( !h_is_pos__index( pos )) 419 { 420 h_add_head__index( list, &vi ); 421 if( h_get_count__index( list ) > linesMax ) 422 { 423 h_remove_tail__index( list ); 424 } 425 } 426 } 427 } 428 } 429 } 430 } 431 432 pos = h_get_head_pos__index( list ); 433 if( h_get_count__index( list ) == 1 ) 434 { 435 if( h_get__index( pos )->rho < 0 ) 436 { 437 h_clear_list__index( list ); 438 } 439 } 440 else 441 { 442 while( h_is_pos__index( pos )) 443 { 444 CvLinePolar line; 445 pindex = h_get__index( pos ); 446 if( pindex->rho < 0 ) 447 { 448 /* This should be the last element... */ 449 h_get_next__index( &pos ); 450 assert( !h_is_pos__index( pos )); 451 break; 452 } 453 line.rho = pindex->rho; 454 line.angle = pindex->theta; 455 cvSeqPush( lines, &line ); 456 457 if( lines->total >= linesMax ) 458 EXIT; 459 h_get_next__index( &pos ); 460 } 461 } 462 463 __END__; 464 465 h_destroy_list__index( list ); 466 cvFree( &sinTable ); 467 cvFree( &x ); 468 cvFree( &y ); 469 cvFree( &caccum ); 470 cvFree( &buffer ); 471 } 472 473 474 /****************************************************************************************\ 475 * Probabilistic Hough Transform * 476 \****************************************************************************************/ 477 478 #if defined WIN64 && defined EM64T && _MSC_VER == 1400 && !defined CV_ICC 479 #pragma optimize("",off) 480 #endif 481 482 static void 483 icvHoughLinesProbabalistic( CvMat* image, 484 float rho, float theta, int threshold, 485 int lineLength, int lineGap, 486 CvSeq *lines, int linesMax ) 487 { 488 CvMat* accum = 0; 489 CvMat* mask = 0; 490 CvMat* trigtab = 0; 491 CvMemStorage* storage = 0; 492 493 CV_FUNCNAME( "icvHoughLinesProbalistic" ); 494 495 __BEGIN__; 496 497 CvSeq* seq; 498 CvSeqWriter writer; 499 int width, height; 500 int numangle, numrho; 501 float ang; 502 int r, n, count; 503 CvPoint pt; 504 float irho = 1 / rho; 505 CvRNG rng = cvRNG(-1); 506 const float* ttab; 507 uchar* mdata0; 508 509 CV_ASSERT( CV_IS_MAT(image) && CV_MAT_TYPE(image->type) == CV_8UC1 ); 510 511 width = image->cols; 512 height = image->rows; 513 514 numangle = cvRound(CV_PI / theta); 515 numrho = cvRound(((width + height) * 2 + 1) / rho); 516 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 )); 520 cvZero( accum ); 521 522 CV_CALL( storage = cvCreateMemStorage(0) ); 523 524 for( ang = 0, n = 0; n < numangle; ang += theta, n++ ) 525 { 526 trigtab->data.fl[n*2] = (float)(cos(ang) * irho); 527 trigtab->data.fl[n*2+1] = (float)(sin(ang) * irho); 528 } 529 ttab = trigtab->data.fl; 530 mdata0 = mask->data.ptr; 531 532 CV_CALL( cvStartWriteSeq( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint), storage, &writer )); 533 534 // stage 1. collect non-zero image points 535 for( pt.y = 0, count = 0; pt.y < height; pt.y++ ) 536 { 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++ ) 540 { 541 if( data[pt.x] ) 542 { 543 mdata[pt.x] = (uchar)1; 544 CV_WRITE_SEQ_ELEM( pt, writer ); 545 } 546 else 547 mdata[pt.x] = 0; 548 } 549 } 550 551 seq = cvEndWriteSeq( &writer ); 552 count = seq->total; 553 554 // stage 2. process all the points in random order 555 for( ; count > 0; count-- ) 556 { 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}}; 562 float a, b; 563 int* adata = accum->data.i; 564 int i, j, k, x0, y0, dx0, dy0, xflag; 565 int good_line; 566 const int shift = 16; 567 568 i = pt->y; 569 j = pt->x; 570 571 // "remove" it by overriding it with the last element 572 *pt = *(CvPoint*)cvGetSeqElem( seq, count-1 ); 573 574 // check if it has been excluded already (i.e. belongs to some other line) 575 if( !mdata0[i*width + j] ) 576 continue; 577 578 // update accumulator, find the most probable line 579 for( n = 0; n < numangle; n++, adata += numrho ) 580 { 581 r = cvRound( j * ttab[n*2] + i * ttab[n*2+1] ); 582 r += (numrho - 1) / 2; 583 int val = ++adata[r]; 584 if( max_val < val ) 585 { 586 max_val = val; 587 max_n = n; 588 } 589 } 590 591 // if it is too "weak" candidate, continue with another point 592 if( max_val < threshold ) 593 continue; 594 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]; 598 b = ttab[max_n*2]; 599 x0 = j; 600 y0 = i; 601 if( fabs(a) > fabs(b) ) 602 { 603 xflag = 1; 604 dx0 = a > 0 ? 1 : -1; 605 dy0 = cvRound( b*(1 << shift)/fabs(a) ); 606 y0 = (y0 << shift) + (1 << (shift-1)); 607 } 608 else 609 { 610 xflag = 0; 611 dy0 = b > 0 ? 1 : -1; 612 dx0 = cvRound( a*(1 << shift)/fabs(b) ); 613 x0 = (x0 << shift) + (1 << (shift-1)); 614 } 615 616 for( k = 0; k < 2; k++ ) 617 { 618 int gap = 0, x = x0, y = y0, dx = dx0, dy = dy0; 619 620 if( k > 0 ) 621 dx = -dx, dy = -dy; 622 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 ) 626 { 627 uchar* mdata; 628 int i1, j1; 629 630 if( xflag ) 631 { 632 j1 = x; 633 i1 = y >> shift; 634 } 635 else 636 { 637 j1 = x >> shift; 638 i1 = y; 639 } 640 641 if( j1 < 0 || j1 >= width || i1 < 0 || i1 >= height ) 642 break; 643 644 mdata = mdata0 + i1*width + j1; 645 646 // for each non-zero point: 647 // update line end, 648 // clear the mask element 649 // reset the gap 650 if( *mdata ) 651 { 652 gap = 0; 653 line_end[k].y = i1; 654 line_end[k].x = j1; 655 } 656 else if( ++gap > lineGap ) 657 break; 658 } 659 } 660 661 good_line = abs(line_end[1].x - line_end[0].x) >= lineLength || 662 abs(line_end[1].y - line_end[0].y) >= lineLength; 663 664 for( k = 0; k < 2; k++ ) 665 { 666 int x = x0, y = y0, dx = dx0, dy = dy0; 667 668 if( k > 0 ) 669 dx = -dx, dy = -dy; 670 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 ) 674 { 675 uchar* mdata; 676 int i1, j1; 677 678 if( xflag ) 679 { 680 j1 = x; 681 i1 = y >> shift; 682 } 683 else 684 { 685 j1 = x >> shift; 686 i1 = y; 687 } 688 689 mdata = mdata0 + i1*width + j1; 690 691 // for each non-zero point: 692 // update line end, 693 // clear the mask element 694 // reset the gap 695 if( *mdata ) 696 { 697 if( good_line ) 698 { 699 adata = accum->data.i; 700 for( n = 0; n < numangle; n++, adata += numrho ) 701 { 702 r = cvRound( j1 * ttab[n*2] + i1 * ttab[n*2+1] ); 703 r += (numrho - 1) / 2; 704 adata[r]--; 705 } 706 } 707 *mdata = 0; 708 } 709 710 if( i1 == line_end[k].y && j1 == line_end[k].x ) 711 break; 712 } 713 } 714 715 if( good_line ) 716 { 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 ) 720 EXIT; 721 } 722 } 723 724 __END__; 725 726 cvReleaseMat( &accum ); 727 cvReleaseMat( &mask ); 728 cvReleaseMat( &trigtab ); 729 cvReleaseMemStorage( &storage ); 730 } 731 732 733 #if defined WIN64 && defined EM64T && _MSC_VER == 1400 && !defined CV_ICC 734 #pragma optimize("",on) 735 #endif 736 737 738 /* Wrapper function for standard hough transform */ 739 CV_IMPL CvSeq* 740 cvHoughLines2( CvArr* src_image, void* lineStorage, int method, 741 double rho, double theta, int threshold, 742 double param1, double param2 ) 743 { 744 CvSeq* result = 0; 745 746 CV_FUNCNAME( "cvHoughLines" ); 747 748 __BEGIN__; 749 750 CvMat stub, *img = (CvMat*)src_image; 751 CvMat* mat = 0; 752 CvSeq* lines = 0; 753 CvSeq lines_header; 754 CvSeqBlock lines_block; 755 int lineType, elemSize; 756 int linesMax = INT_MAX; 757 int iparam1, iparam2; 758 759 CV_CALL( img = cvGetMat( img, &stub )); 760 761 if( !CV_IS_MASK_ARR(img)) 762 CV_ERROR( CV_StsBadArg, "The source image must be 8-bit, single-channel" ); 763 764 if( !lineStorage ) 765 CV_ERROR( CV_StsNullPtr, "NULL destination" ); 766 767 if( rho <= 0 || theta <= 0 || threshold <= 0 ) 768 CV_ERROR( CV_StsOutOfRange, "rho, theta and threshold must be positive" ); 769 770 if( method != CV_HOUGH_PROBABILISTIC ) 771 { 772 lineType = CV_32FC2; 773 elemSize = sizeof(float)*2; 774 } 775 else 776 { 777 lineType = CV_32SC4; 778 elemSize = sizeof(int)*4; 779 } 780 781 if( CV_IS_STORAGE( lineStorage )) 782 { 783 CV_CALL( lines = cvCreateSeq( lineType, sizeof(CvSeq), elemSize, (CvMemStorage*)lineStorage )); 784 } 785 else if( CV_IS_MAT( lineStorage )) 786 { 787 mat = (CvMat*)lineStorage; 788 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" ); 792 793 if( CV_MAT_TYPE( mat->type ) != lineType ) 794 CV_ERROR( CV_StsBadArg, 795 "The destination matrix data type is inappropriate, see the manual" ); 796 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 )); 801 } 802 else 803 { 804 CV_ERROR( CV_StsBadArg, "Destination is not CvMemStorage* nor CvMat*" ); 805 } 806 807 iparam1 = cvRound(param1); 808 iparam2 = cvRound(param2); 809 810 switch( method ) 811 { 812 case CV_HOUGH_STANDARD: 813 CV_CALL( icvHoughLinesStandard( img, (float)rho, 814 (float)theta, threshold, lines, linesMax )); 815 break; 816 case CV_HOUGH_MULTI_SCALE: 817 CV_CALL( icvHoughLinesSDiv( img, (float)rho, (float)theta, 818 threshold, iparam1, iparam2, lines, linesMax )); 819 break; 820 case CV_HOUGH_PROBABILISTIC: 821 CV_CALL( icvHoughLinesProbabalistic( img, (float)rho, (float)theta, 822 threshold, iparam1, iparam2, lines, linesMax )); 823 break; 824 default: 825 CV_ERROR( CV_StsBadArg, "Unrecognized method id" ); 826 } 827 828 if( mat ) 829 { 830 if( mat->cols > mat->rows ) 831 mat->cols = lines->total; 832 else 833 mat->rows = lines->total; 834 } 835 else 836 { 837 result = lines; 838 } 839 840 __END__; 841 842 return result; 843 } 844 845 846 /****************************************************************************************\ 847 * Circle Detection * 848 \****************************************************************************************/ 849 850 static void 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 ) 855 { 856 const int SHIFT = 10, ONE = 1 << SHIFT, R_THRESH = 30; 857 CvMat *dx = 0, *dy = 0; 858 CvMat *edges = 0; 859 CvMat *accum = 0; 860 int* sort_buf = 0; 861 CvMat* dist_buf = 0; 862 CvMemStorage* storage = 0; 863 864 CV_FUNCNAME( "icvHoughCirclesGradient" ); 865 866 __BEGIN__; 867 868 int x, y, i, j, center_count, nz_count; 869 int rows, cols, arows, acols; 870 int astep, *adata; 871 float* ddata; 872 CvSeq *nz, *centers; 873 float idp, dr; 874 CvSeqReader reader; 875 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 )); 878 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 )); 883 884 if( dp < 1.f ) 885 dp = 1.f; 886 idp = 1.f/dp; 887 CV_CALL( accum = cvCreateMat( cvCeil(img->rows*idp)+2, cvCeil(img->cols*idp)+2, CV_32SC1 )); 888 CV_CALL( cvZero(accum)); 889 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 )); 893 894 rows = img->rows; 895 cols = img->cols; 896 arows = accum->rows - 2; 897 acols = accum->cols - 2; 898 adata = accum->data.i; 899 astep = accum->step/sizeof(adata[0]); 900 901 for( y = 0; y < rows; y++ ) 902 { 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); 906 907 for( x = 0; x < cols; x++ ) 908 { 909 float vx, vy; 910 int sx, sy, x0, y0, x1, y1, r, k; 911 CvPoint pt; 912 913 vx = dx_row[x]; 914 vy = dy_row[x]; 915 916 if( !edges_row[x] || (vx == 0 && vy == 0) ) 917 continue; 918 919 if( fabs(vx) < fabs(vy) ) 920 { 921 sx = cvRound(vx*ONE/fabs(vy)); 922 sy = vy < 0 ? -ONE : ONE; 923 } 924 else 925 { 926 assert( vx != 0 ); 927 sy = cvRound(vy*ONE/fabs(vx)); 928 sx = vx < 0 ? -ONE : ONE; 929 } 930 931 x0 = cvRound((x*idp)*ONE) + ONE + (ONE/2); 932 y0 = cvRound((y*idp)*ONE) + ONE + (ONE/2); 933 934 for( k = 0; k < 2; k++ ) 935 { 936 x0 += min_radius * sx; 937 y0 += min_radius * sy; 938 939 for( x1 = x0, y1 = y0, r = min_radius; r <= max_radius; x1 += sx, y1 += sy, r++ ) 940 { 941 int x2 = x1 >> SHIFT, y2 = y1 >> SHIFT; 942 if( (unsigned)x2 >= (unsigned)acols || 943 (unsigned)y2 >= (unsigned)arows ) 944 break; 945 adata[y2*astep + x2]++; 946 } 947 948 x0 -= min_radius * sx; 949 y0 -= min_radius * sy; 950 sx = -sx; sy = -sy; 951 } 952 953 pt.x = x; pt.y = y; 954 cvSeqPush( nz, &pt ); 955 } 956 } 957 958 nz_count = nz->total; 959 if( !nz_count ) 960 EXIT; 961 962 for( y = 1; y < arows - 1; y++ ) 963 { 964 for( x = 1; x < acols - 1; x++ ) 965 { 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); 971 } 972 } 973 974 center_count = centers->total; 975 if( !center_count ) 976 EXIT; 977 978 CV_CALL( sort_buf = (int*)cvAlloc( MAX(center_count,nz_count)*sizeof(sort_buf[0]) )); 979 cvCvtSeqToArray( centers, sort_buf ); 980 981 icvHoughSortDescent32s( sort_buf, center_count, adata ); 982 cvClearSeq( centers ); 983 cvSeqPushMulti( centers, sort_buf, center_count ); 984 985 CV_CALL( dist_buf = cvCreateMat( 1, nz_count, CV_32FC1 )); 986 ddata = dist_buf->data.fl; 987 988 dr = dp; 989 min_dist = MAX( min_dist, dp ); 990 min_dist *= min_dist; 991 992 for( i = 0; i < centers->total; i++ ) 993 { 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; 1002 1003 for( j = 0; j < circles->total; j++ ) 1004 { 1005 float* c = (float*)cvGetSeqElem( circles, j ); 1006 if( (c[0] - cx)*(c[0] - cx) + (c[1] - cy)*(c[1] - cy) < min_dist ) 1007 break; 1008 } 1009 1010 if( j < circles->total ) 1011 continue; 1012 1013 cvStartReadSeq( nz, &reader ); 1014 for( j = 0; j < nz_count; j++ ) 1015 { 1016 CvPoint pt; 1017 float _dx, _dy; 1018 CV_READ_SEQ_ELEM( pt, reader ); 1019 _dx = cx - pt.x; _dy = cy - pt.y; 1020 ddata[j] = _dx*_dx + _dy*_dy; 1021 sort_buf[j] = j; 1022 } 1023 1024 cvPow( dist_buf, dist_buf, 0.5 ); 1025 icvHoughSortDescent32s( sort_buf, nz_count, (int*)ddata ); 1026 1027 dist_sum = start_dist = ddata[sort_buf[nz_count-1]]; 1028 for( j = nz_count - 2; j >= 0; j-- ) 1029 { 1030 float d = ddata[sort_buf[j]]; 1031 1032 if( d > max_radius ) 1033 break; 1034 1035 if( d - start_dist > dr ) 1036 { 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) ) 1040 { 1041 r_best = r_cur; 1042 max_count = start_idx - j; 1043 } 1044 start_dist = d; 1045 start_idx = j; 1046 dist_sum = 0; 1047 } 1048 dist_sum += d; 1049 } 1050 1051 if( max_count > R_THRESH ) 1052 { 1053 c[0] = cx; 1054 c[1] = cy; 1055 c[2] = (float)r_best; 1056 cvSeqPush( circles, c ); 1057 if( circles->total > circles_max ) 1058 EXIT; 1059 } 1060 } 1061 1062 __END__; 1063 1064 cvReleaseMat( &dist_buf ); 1065 cvFree( &sort_buf ); 1066 cvReleaseMemStorage( &storage ); 1067 cvReleaseMat( &edges ); 1068 cvReleaseMat( &dx ); 1069 cvReleaseMat( &dy ); 1070 cvReleaseMat( &accum ); 1071 } 1072 1073 CV_IMPL CvSeq* 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 ) 1078 { 1079 CvSeq* result = 0; 1080 1081 CV_FUNCNAME( "cvHoughCircles" ); 1082 1083 __BEGIN__; 1084 1085 CvMat stub, *img = (CvMat*)src_image; 1086 CvMat* mat = 0; 1087 CvSeq* circles = 0; 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); 1093 1094 CV_CALL( img = cvGetMat( img, &stub )); 1095 1096 if( !CV_IS_MASK_ARR(img)) 1097 CV_ERROR( CV_StsBadArg, "The source image must be 8-bit, single-channel" ); 1098 1099 if( !circle_storage ) 1100 CV_ERROR( CV_StsNullPtr, "NULL destination" ); 1101 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" ); 1104 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; 1110 1111 if( CV_IS_STORAGE( circle_storage )) 1112 { 1113 CV_CALL( circles = cvCreateSeq( CV_32FC3, sizeof(CvSeq), 1114 sizeof(float)*3, (CvMemStorage*)circle_storage )); 1115 } 1116 else if( CV_IS_MAT( circle_storage )) 1117 { 1118 mat = (CvMat*)circle_storage; 1119 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" ); 1124 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 )); 1129 } 1130 else 1131 { 1132 CV_ERROR( CV_StsBadArg, "Destination is not CvMemStorage* nor CvMat*" ); 1133 } 1134 1135 switch( method ) 1136 { 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 )); 1141 break; 1142 default: 1143 CV_ERROR( CV_StsBadArg, "Unrecognized method id" ); 1144 } 1145 1146 if( mat ) 1147 { 1148 if( mat->cols > mat->rows ) 1149 mat->cols = circles->total; 1150 else 1151 mat->rows = circles->total; 1152 } 1153 else 1154 result = circles; 1155 1156 __END__; 1157 1158 return result; 1159 } 1160 1161 /* End of file. */ 1162