Home | History | Annotate | Download | only in src
      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