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 //                           License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
     14 // Copyright (C) 2013, OpenCV Foundation, all rights reserved.
     15 // Copyright (C) 2014, Itseez, Inc, all rights reserved.
     16 // Third party copyrights are property of their respective owners.
     17 //
     18 // Redistribution and use in source and binary forms, with or without modification,
     19 // are permitted provided that the following conditions are met:
     20 //
     21 //   * Redistribution's of source code must retain the above copyright notice,
     22 //     this list of conditions and the following disclaimer.
     23 //
     24 //   * Redistribution's in binary form must reproduce the above copyright notice,
     25 //     this list of conditions and the following disclaimer in the documentation
     26 //     and/or other materials provided with the distribution.
     27 //
     28 //   * The name of the copyright holders may not be used to endorse or promote products
     29 //     derived from this software without specific prior written permission.
     30 //
     31 // This software is provided by the copyright holders and contributors "as is" and
     32 // any express or implied warranties, including, but not limited to, the implied
     33 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     34 // In no event shall the Intel Corporation or contributors be liable for any direct,
     35 // indirect, incidental, special, exemplary, or consequential damages
     36 // (including, but not limited to, procurement of substitute goods or services;
     37 // loss of use, data, or profits; or business interruption) however caused
     38 // and on any theory of liability, whether in contract, strict liability,
     39 // or tort (including negligence or otherwise) arising in any way out of
     40 // the use of this software, even if advised of the possibility of such damage.
     41 //
     42 //M*/
     43 
     44 #include "precomp.hpp"
     45 #include "opencl_kernels_imgproc.hpp"
     46 
     47 namespace cv
     48 {
     49 
     50 // Classical Hough Transform
     51 struct LinePolar
     52 {
     53     float rho;
     54     float angle;
     55 };
     56 
     57 
     58 struct hough_cmp_gt
     59 {
     60     hough_cmp_gt(const int* _aux) : aux(_aux) {}
     61     bool operator()(int l1, int l2) const
     62     {
     63         return aux[l1] > aux[l2] || (aux[l1] == aux[l2] && l1 < l2);
     64     }
     65     const int* aux;
     66 };
     67 
     68 
     69 /*
     70 Here image is an input raster;
     71 step is it's step; size characterizes it's ROI;
     72 rho and theta are discretization steps (in pixels and radians correspondingly).
     73 threshold is the minimum number of pixels in the feature for it
     74 to be a candidate for line. lines is the output
     75 array of (rho, theta) pairs. linesMax is the buffer size (number of pairs).
     76 Functions return the actual number of found lines.
     77 */
     78 static void
     79 HoughLinesStandard( const Mat& img, float rho, float theta,
     80                     int threshold, std::vector<Vec2f>& lines, int linesMax,
     81                     double min_theta, double max_theta )
     82 {
     83     int i, j;
     84     float irho = 1 / rho;
     85 
     86     CV_Assert( img.type() == CV_8UC1 );
     87 
     88     const uchar* image = img.ptr();
     89     int step = (int)img.step;
     90     int width = img.cols;
     91     int height = img.rows;
     92 
     93     if (max_theta < min_theta ) {
     94         CV_Error( CV_StsBadArg, "max_theta must be greater than min_theta" );
     95     }
     96     int numangle = cvRound((max_theta - min_theta) / theta);
     97     int numrho = cvRound(((width + height) * 2 + 1) / rho);
     98 
     99 #if (0 && defined(HAVE_IPP) && !defined(HAVE_IPP_ICV_ONLY) && IPP_VERSION_X100 >= 801)
    100     CV_IPP_CHECK()
    101     {
    102         IppiSize srcSize = { width, height };
    103         IppPointPolar delta = { rho, theta };
    104         IppPointPolar dstRoi[2] = {{(Ipp32f) -(width + height), (Ipp32f) min_theta},{(Ipp32f) (width + height), (Ipp32f) max_theta}};
    105         int bufferSize;
    106         int nz = countNonZero(img);
    107         int ipp_linesMax = std::min(linesMax, nz*numangle/threshold);
    108         int linesCount = 0;
    109         lines.resize(ipp_linesMax);
    110         IppStatus ok = ippiHoughLineGetSize_8u_C1R(srcSize, delta, ipp_linesMax, &bufferSize);
    111         Ipp8u* buffer = ippsMalloc_8u(bufferSize);
    112         if (ok >= 0) ok = ippiHoughLine_Region_8u32f_C1R(image, step, srcSize, (IppPointPolar*) &lines[0], dstRoi, ipp_linesMax, &linesCount, delta, threshold, buffer);
    113         ippsFree(buffer);
    114         if (ok >= 0)
    115         {
    116             lines.resize(linesCount);
    117             CV_IMPL_ADD(CV_IMPL_IPP);
    118             return;
    119         }
    120         lines.clear();
    121         setIppErrorStatus();
    122     }
    123 #endif
    124 
    125     AutoBuffer<int> _accum((numangle+2) * (numrho+2));
    126     std::vector<int> _sort_buf;
    127     AutoBuffer<float> _tabSin(numangle);
    128     AutoBuffer<float> _tabCos(numangle);
    129     int *accum = _accum;
    130     float *tabSin = _tabSin, *tabCos = _tabCos;
    131 
    132     memset( accum, 0, sizeof(accum[0]) * (numangle+2) * (numrho+2) );
    133 
    134     float ang = static_cast<float>(min_theta);
    135     for(int n = 0; n < numangle; ang += theta, n++ )
    136     {
    137         tabSin[n] = (float)(sin((double)ang) * irho);
    138         tabCos[n] = (float)(cos((double)ang) * irho);
    139     }
    140 
    141     // stage 1. fill accumulator
    142     for( i = 0; i < height; i++ )
    143         for( j = 0; j < width; j++ )
    144         {
    145             if( image[i * step + j] != 0 )
    146                 for(int n = 0; n < numangle; n++ )
    147                 {
    148                     int r = cvRound( j * tabCos[n] + i * tabSin[n] );
    149                     r += (numrho - 1) / 2;
    150                     accum[(n+1) * (numrho+2) + r+1]++;
    151                 }
    152         }
    153 
    154     // stage 2. find local maximums
    155     for(int r = 0; r < numrho; r++ )
    156         for(int n = 0; n < numangle; n++ )
    157         {
    158             int base = (n+1) * (numrho+2) + r+1;
    159             if( accum[base] > threshold &&
    160                 accum[base] > accum[base - 1] && accum[base] >= accum[base + 1] &&
    161                 accum[base] > accum[base - numrho - 2] && accum[base] >= accum[base + numrho + 2] )
    162                 _sort_buf.push_back(base);
    163         }
    164 
    165     // stage 3. sort the detected lines by accumulator value
    166     std::sort(_sort_buf.begin(), _sort_buf.end(), hough_cmp_gt(accum));
    167 
    168     // stage 4. store the first min(total,linesMax) lines to the output buffer
    169     linesMax = std::min(linesMax, (int)_sort_buf.size());
    170     double scale = 1./(numrho+2);
    171     for( i = 0; i < linesMax; i++ )
    172     {
    173         LinePolar line;
    174         int idx = _sort_buf[i];
    175         int n = cvFloor(idx*scale) - 1;
    176         int r = idx - (n+1)*(numrho+2) - 1;
    177         line.rho = (r - (numrho - 1)*0.5f) * rho;
    178         line.angle = static_cast<float>(min_theta) + n * theta;
    179         lines.push_back(Vec2f(line.rho, line.angle));
    180     }
    181 }
    182 
    183 
    184 // Multi-Scale variant of Classical Hough Transform
    185 
    186 struct hough_index
    187 {
    188     hough_index() : value(0), rho(0.f), theta(0.f) {}
    189     hough_index(int _val, float _rho, float _theta)
    190     : value(_val), rho(_rho), theta(_theta) {}
    191 
    192     int value;
    193     float rho, theta;
    194 };
    195 
    196 
    197 static void
    198 HoughLinesSDiv( const Mat& img,
    199                 float rho, float theta, int threshold,
    200                 int srn, int stn,
    201                 std::vector<Vec2f>& lines, int linesMax,
    202                 double min_theta, double max_theta )
    203 {
    204     #define _POINT(row, column)\
    205         (image_src[(row)*step+(column)])
    206 
    207     int index, i;
    208     int ri, ti, ti1, ti0;
    209     int row, col;
    210     float r, t;                 /* Current rho and theta */
    211     float rv;                   /* Some temporary rho value */
    212 
    213     int fn = 0;
    214     float xc, yc;
    215 
    216     const float d2r = (float)(CV_PI / 180);
    217     int sfn = srn * stn;
    218     int fi;
    219     int count;
    220     int cmax = 0;
    221 
    222     std::vector<hough_index> lst;
    223 
    224     CV_Assert( img.type() == CV_8UC1 );
    225     CV_Assert( linesMax > 0 );
    226 
    227     threshold = MIN( threshold, 255 );
    228 
    229     const uchar* image_src = img.ptr();
    230     int step = (int)img.step;
    231     int w = img.cols;
    232     int h = img.rows;
    233 
    234     float irho = 1 / rho;
    235     float itheta = 1 / theta;
    236     float srho = rho / srn;
    237     float stheta = theta / stn;
    238     float isrho = 1 / srho;
    239     float istheta = 1 / stheta;
    240 
    241     int rn = cvFloor( std::sqrt( (double)w * w + (double)h * h ) * irho );
    242     int tn = cvFloor( 2 * CV_PI * itheta );
    243 
    244     lst.push_back(hough_index(threshold, -1.f, 0.f));
    245 
    246     // Precalculate sin table
    247     std::vector<float> _sinTable( 5 * tn * stn );
    248     float* sinTable = &_sinTable[0];
    249 
    250     for( index = 0; index < 5 * tn * stn; index++ )
    251         sinTable[index] = (float)cos( stheta * index * 0.2f );
    252 
    253     std::vector<uchar> _caccum(rn * tn, (uchar)0);
    254     uchar* caccum = &_caccum[0];
    255 
    256     // Counting all feature pixels
    257     for( row = 0; row < h; row++ )
    258         for( col = 0; col < w; col++ )
    259             fn += _POINT( row, col ) != 0;
    260 
    261     std::vector<int> _x(fn), _y(fn);
    262     int* x = &_x[0], *y = &_y[0];
    263 
    264     // Full Hough Transform (it's accumulator update part)
    265     fi = 0;
    266     for( row = 0; row < h; row++ )
    267     {
    268         for( col = 0; col < w; col++ )
    269         {
    270             if( _POINT( row, col ))
    271             {
    272                 int halftn;
    273                 float r0;
    274                 float scale_factor;
    275                 int iprev = -1;
    276                 float phi, phi1;
    277                 float theta_it;     // Value of theta for iterating
    278 
    279                 // Remember the feature point
    280                 x[fi] = col;
    281                 y[fi] = row;
    282                 fi++;
    283 
    284                 yc = (float) row + 0.5f;
    285                 xc = (float) col + 0.5f;
    286 
    287                 /* Update the accumulator */
    288                 t = (float) fabs( cvFastArctan( yc, xc ) * d2r );
    289                 r = (float) std::sqrt( (double)xc * xc + (double)yc * yc );
    290                 r0 = r * irho;
    291                 ti0 = cvFloor( (t + CV_PI*0.5) * itheta );
    292 
    293                 caccum[ti0]++;
    294 
    295                 theta_it = rho / r;
    296                 theta_it = theta_it < theta ? theta_it : theta;
    297                 scale_factor = theta_it * itheta;
    298                 halftn = cvFloor( CV_PI / theta_it );
    299                 for( ti1 = 1, phi = theta_it - (float)(CV_PI*0.5), phi1 = (theta_it + t) * itheta;
    300                      ti1 < halftn; ti1++, phi += theta_it, phi1 += scale_factor )
    301                 {
    302                     rv = r0 * std::cos( phi );
    303                     i = (int)rv * tn;
    304                     i += cvFloor( phi1 );
    305                     assert( i >= 0 );
    306                     assert( i < rn * tn );
    307                     caccum[i] = (uchar) (caccum[i] + ((i ^ iprev) != 0));
    308                     iprev = i;
    309                     if( cmax < caccum[i] )
    310                         cmax = caccum[i];
    311                 }
    312             }
    313         }
    314     }
    315 
    316     // Starting additional analysis
    317     count = 0;
    318     for( ri = 0; ri < rn; ri++ )
    319     {
    320         for( ti = 0; ti < tn; ti++ )
    321         {
    322             if( caccum[ri * tn + ti] > threshold )
    323                 count++;
    324         }
    325     }
    326 
    327     if( count * 100 > rn * tn )
    328     {
    329         HoughLinesStandard( img, rho, theta, threshold, lines, linesMax, min_theta, max_theta );
    330         return;
    331     }
    332 
    333     std::vector<uchar> _buffer(srn * stn + 2);
    334     uchar* buffer = &_buffer[0];
    335     uchar* mcaccum = buffer + 1;
    336 
    337     count = 0;
    338     for( ri = 0; ri < rn; ri++ )
    339     {
    340         for( ti = 0; ti < tn; ti++ )
    341         {
    342             if( caccum[ri * tn + ti] > threshold )
    343             {
    344                 count++;
    345                 memset( mcaccum, 0, sfn * sizeof( uchar ));
    346 
    347                 for( index = 0; index < fn; index++ )
    348                 {
    349                     int ti2;
    350                     float r0;
    351 
    352                     yc = (float) y[index] + 0.5f;
    353                     xc = (float) x[index] + 0.5f;
    354 
    355                     // Update the accumulator
    356                     t = (float) fabs( cvFastArctan( yc, xc ) * d2r );
    357                     r = (float) std::sqrt( (double)xc * xc + (double)yc * yc ) * isrho;
    358                     ti0 = cvFloor( (t + CV_PI * 0.5) * istheta );
    359                     ti2 = (ti * stn - ti0) * 5;
    360                     r0 = (float) ri *srn;
    361 
    362                     for( ti1 = 0; ti1 < stn; ti1++, ti2 += 5 )
    363                     {
    364                         rv = r * sinTable[(int) (std::abs( ti2 ))] - r0;
    365                         i = cvFloor( rv ) * stn + ti1;
    366 
    367                         i = CV_IMAX( i, -1 );
    368                         i = CV_IMIN( i, sfn );
    369                         mcaccum[i]++;
    370                         assert( i >= -1 );
    371                         assert( i <= sfn );
    372                     }
    373                 }
    374 
    375                 // Find peaks in maccum...
    376                 for( index = 0; index < sfn; index++ )
    377                 {
    378                     i = 0;
    379                     int pos = (int)(lst.size() - 1);
    380                     if( pos < 0 || lst[pos].value < mcaccum[index] )
    381                     {
    382                         hough_index vi(mcaccum[index],
    383                                        index / stn * srho + ri * rho,
    384                                        index % stn * stheta + ti * theta - (float)(CV_PI*0.5));
    385                         lst.push_back(vi);
    386                         for( ; pos >= 0; pos-- )
    387                         {
    388                             if( lst[pos].value > vi.value )
    389                                 break;
    390                             lst[pos+1] = lst[pos];
    391                         }
    392                         lst[pos+1] = vi;
    393                         if( (int)lst.size() > linesMax )
    394                             lst.pop_back();
    395                     }
    396                 }
    397             }
    398         }
    399     }
    400 
    401     for( size_t idx = 0; idx < lst.size(); idx++ )
    402     {
    403         if( lst[idx].rho < 0 )
    404             continue;
    405         lines.push_back(Vec2f(lst[idx].rho, lst[idx].theta));
    406     }
    407 }
    408 
    409 
    410 /****************************************************************************************\
    411 *                              Probabilistic Hough Transform                             *
    412 \****************************************************************************************/
    413 
    414 static void
    415 HoughLinesProbabilistic( Mat& image,
    416                          float rho, float theta, int threshold,
    417                          int lineLength, int lineGap,
    418                          std::vector<Vec4i>& lines, int linesMax )
    419 {
    420     Point pt;
    421     float irho = 1 / rho;
    422     RNG rng((uint64)-1);
    423 
    424     CV_Assert( image.type() == CV_8UC1 );
    425 
    426     int width = image.cols;
    427     int height = image.rows;
    428 
    429     int numangle = cvRound(CV_PI / theta);
    430     int numrho = cvRound(((width + height) * 2 + 1) / rho);
    431 
    432 #if (0 && defined(HAVE_IPP) && !defined(HAVE_IPP_ICV_ONLY) && IPP_VERSION_X100 >= 801)
    433     CV_IPP_CHECK()
    434     {
    435         IppiSize srcSize = { width, height };
    436         IppPointPolar delta = { rho, theta };
    437         IppiHoughProbSpec* pSpec;
    438         int bufferSize, specSize;
    439         int ipp_linesMax = std::min(linesMax, numangle*numrho);
    440         int linesCount = 0;
    441         lines.resize(ipp_linesMax);
    442         IppStatus ok = ippiHoughProbLineGetSize_8u_C1R(srcSize, delta, &specSize, &bufferSize);
    443         Ipp8u* buffer = ippsMalloc_8u(bufferSize);
    444         pSpec = (IppiHoughProbSpec*) malloc(specSize);
    445         if (ok >= 0) ok = ippiHoughProbLineInit_8u32f_C1R(srcSize, delta, ippAlgHintNone, pSpec);
    446         if (ok >= 0) ok = ippiHoughProbLine_8u32f_C1R(image.data, image.step, srcSize, threshold, lineLength, lineGap, (IppiPoint*) &lines[0], ipp_linesMax, &linesCount, buffer, pSpec);
    447 
    448         free(pSpec);
    449         ippsFree(buffer);
    450         if (ok >= 0)
    451         {
    452             lines.resize(linesCount);
    453             CV_IMPL_ADD(CV_IMPL_IPP);
    454             return;
    455         }
    456         lines.clear();
    457         setIppErrorStatus();
    458     }
    459 #endif
    460 
    461     Mat accum = Mat::zeros( numangle, numrho, CV_32SC1 );
    462     Mat mask( height, width, CV_8UC1 );
    463     std::vector<float> trigtab(numangle*2);
    464 
    465     for( int n = 0; n < numangle; n++ )
    466     {
    467         trigtab[n*2] = (float)(cos((double)n*theta) * irho);
    468         trigtab[n*2+1] = (float)(sin((double)n*theta) * irho);
    469     }
    470     const float* ttab = &trigtab[0];
    471     uchar* mdata0 = mask.ptr();
    472     std::vector<Point> nzloc;
    473 
    474     // stage 1. collect non-zero image points
    475     for( pt.y = 0; pt.y < height; pt.y++ )
    476     {
    477         const uchar* data = image.ptr(pt.y);
    478         uchar* mdata = mask.ptr(pt.y);
    479         for( pt.x = 0; pt.x < width; pt.x++ )
    480         {
    481             if( data[pt.x] )
    482             {
    483                 mdata[pt.x] = (uchar)1;
    484                 nzloc.push_back(pt);
    485             }
    486             else
    487                 mdata[pt.x] = 0;
    488         }
    489     }
    490 
    491     int count = (int)nzloc.size();
    492 
    493     // stage 2. process all the points in random order
    494     for( ; count > 0; count-- )
    495     {
    496         // choose random point out of the remaining ones
    497         int idx = rng.uniform(0, count);
    498         int max_val = threshold-1, max_n = 0;
    499         Point point = nzloc[idx];
    500         Point line_end[2];
    501         float a, b;
    502         int* adata = accum.ptr<int>();
    503         int i = point.y, j = point.x, k, x0, y0, dx0, dy0, xflag;
    504         int good_line;
    505         const int shift = 16;
    506 
    507         // "remove" it by overriding it with the last element
    508         nzloc[idx] = nzloc[count-1];
    509 
    510         // check if it has been excluded already (i.e. belongs to some other line)
    511         if( !mdata0[i*width + j] )
    512             continue;
    513 
    514         // update accumulator, find the most probable line
    515         for( int n = 0; n < numangle; n++, adata += numrho )
    516         {
    517             int r = cvRound( j * ttab[n*2] + i * ttab[n*2+1] );
    518             r += (numrho - 1) / 2;
    519             int val = ++adata[r];
    520             if( max_val < val )
    521             {
    522                 max_val = val;
    523                 max_n = n;
    524             }
    525         }
    526 
    527         // if it is too "weak" candidate, continue with another point
    528         if( max_val < threshold )
    529             continue;
    530 
    531         // from the current point walk in each direction
    532         // along the found line and extract the line segment
    533         a = -ttab[max_n*2+1];
    534         b = ttab[max_n*2];
    535         x0 = j;
    536         y0 = i;
    537         if( fabs(a) > fabs(b) )
    538         {
    539             xflag = 1;
    540             dx0 = a > 0 ? 1 : -1;
    541             dy0 = cvRound( b*(1 << shift)/fabs(a) );
    542             y0 = (y0 << shift) + (1 << (shift-1));
    543         }
    544         else
    545         {
    546             xflag = 0;
    547             dy0 = b > 0 ? 1 : -1;
    548             dx0 = cvRound( a*(1 << shift)/fabs(b) );
    549             x0 = (x0 << shift) + (1 << (shift-1));
    550         }
    551 
    552         for( k = 0; k < 2; k++ )
    553         {
    554             int gap = 0, x = x0, y = y0, dx = dx0, dy = dy0;
    555 
    556             if( k > 0 )
    557                 dx = -dx, dy = -dy;
    558 
    559             // walk along the line using fixed-point arithmetics,
    560             // stop at the image border or in case of too big gap
    561             for( ;; x += dx, y += dy )
    562             {
    563                 uchar* mdata;
    564                 int i1, j1;
    565 
    566                 if( xflag )
    567                 {
    568                     j1 = x;
    569                     i1 = y >> shift;
    570                 }
    571                 else
    572                 {
    573                     j1 = x >> shift;
    574                     i1 = y;
    575                 }
    576 
    577                 if( j1 < 0 || j1 >= width || i1 < 0 || i1 >= height )
    578                     break;
    579 
    580                 mdata = mdata0 + i1*width + j1;
    581 
    582                 // for each non-zero point:
    583                 //    update line end,
    584                 //    clear the mask element
    585                 //    reset the gap
    586                 if( *mdata )
    587                 {
    588                     gap = 0;
    589                     line_end[k].y = i1;
    590                     line_end[k].x = j1;
    591                 }
    592                 else if( ++gap > lineGap )
    593                     break;
    594             }
    595         }
    596 
    597         good_line = std::abs(line_end[1].x - line_end[0].x) >= lineLength ||
    598                     std::abs(line_end[1].y - line_end[0].y) >= lineLength;
    599 
    600         for( k = 0; k < 2; k++ )
    601         {
    602             int x = x0, y = y0, dx = dx0, dy = dy0;
    603 
    604             if( k > 0 )
    605                 dx = -dx, dy = -dy;
    606 
    607             // walk along the line using fixed-point arithmetics,
    608             // stop at the image border or in case of too big gap
    609             for( ;; x += dx, y += dy )
    610             {
    611                 uchar* mdata;
    612                 int i1, j1;
    613 
    614                 if( xflag )
    615                 {
    616                     j1 = x;
    617                     i1 = y >> shift;
    618                 }
    619                 else
    620                 {
    621                     j1 = x >> shift;
    622                     i1 = y;
    623                 }
    624 
    625                 mdata = mdata0 + i1*width + j1;
    626 
    627                 // for each non-zero point:
    628                 //    update line end,
    629                 //    clear the mask element
    630                 //    reset the gap
    631                 if( *mdata )
    632                 {
    633                     if( good_line )
    634                     {
    635                         adata = accum.ptr<int>();
    636                         for( int n = 0; n < numangle; n++, adata += numrho )
    637                         {
    638                             int r = cvRound( j1 * ttab[n*2] + i1 * ttab[n*2+1] );
    639                             r += (numrho - 1) / 2;
    640                             adata[r]--;
    641                         }
    642                     }
    643                     *mdata = 0;
    644                 }
    645 
    646                 if( i1 == line_end[k].y && j1 == line_end[k].x )
    647                     break;
    648             }
    649         }
    650 
    651         if( good_line )
    652         {
    653             Vec4i lr(line_end[0].x, line_end[0].y, line_end[1].x, line_end[1].y);
    654             lines.push_back(lr);
    655             if( (int)lines.size() >= linesMax )
    656                 return;
    657         }
    658     }
    659 }
    660 
    661 #ifdef HAVE_OPENCL
    662 
    663 #define OCL_MAX_LINES 4096
    664 
    665 static bool ocl_makePointsList(InputArray _src, OutputArray _pointsList, InputOutputArray _counters)
    666 {
    667     UMat src = _src.getUMat();
    668     _pointsList.create(1, (int) src.total(), CV_32SC1);
    669     UMat pointsList = _pointsList.getUMat();
    670     UMat counters = _counters.getUMat();
    671     ocl::Device dev = ocl::Device::getDefault();
    672 
    673     const int pixPerWI = 16;
    674     int workgroup_size = min((int) dev.maxWorkGroupSize(), (src.cols + pixPerWI - 1)/pixPerWI);
    675     ocl::Kernel pointListKernel("make_point_list", ocl::imgproc::hough_lines_oclsrc,
    676                                 format("-D MAKE_POINTS_LIST -D GROUP_SIZE=%d -D LOCAL_SIZE=%d", workgroup_size, src.cols));
    677     if (pointListKernel.empty())
    678         return false;
    679 
    680     pointListKernel.args(ocl::KernelArg::ReadOnly(src), ocl::KernelArg::WriteOnlyNoSize(pointsList),
    681                          ocl::KernelArg::PtrWriteOnly(counters));
    682 
    683     size_t localThreads[2]  = { workgroup_size, 1 };
    684     size_t globalThreads[2] = { workgroup_size, src.rows };
    685 
    686     return pointListKernel.run(2, globalThreads, localThreads, false);
    687 }
    688 
    689 static bool ocl_fillAccum(InputArray _pointsList, OutputArray _accum, int total_points, double rho, double theta, int numrho, int numangle)
    690 {
    691     UMat pointsList = _pointsList.getUMat();
    692     _accum.create(numangle + 2, numrho + 2, CV_32SC1);
    693     UMat accum = _accum.getUMat();
    694     ocl::Device dev = ocl::Device::getDefault();
    695 
    696     float irho = (float) (1 / rho);
    697     int workgroup_size = min((int) dev.maxWorkGroupSize(), total_points);
    698 
    699     ocl::Kernel fillAccumKernel;
    700     size_t localThreads[2];
    701     size_t globalThreads[2];
    702 
    703     size_t local_memory_needed = (numrho + 2)*sizeof(int);
    704     if (local_memory_needed > dev.localMemSize())
    705     {
    706         accum.setTo(Scalar::all(0));
    707         fillAccumKernel.create("fill_accum_global", ocl::imgproc::hough_lines_oclsrc,
    708                                 format("-D FILL_ACCUM_GLOBAL"));
    709         if (fillAccumKernel.empty())
    710             return false;
    711         globalThreads[0] = workgroup_size; globalThreads[1] = numangle;
    712         fillAccumKernel.args(ocl::KernelArg::ReadOnlyNoSize(pointsList), ocl::KernelArg::WriteOnlyNoSize(accum),
    713                         total_points, irho, (float) theta, numrho, numangle);
    714         return fillAccumKernel.run(2, globalThreads, NULL, false);
    715     }
    716     else
    717     {
    718         fillAccumKernel.create("fill_accum_local", ocl::imgproc::hough_lines_oclsrc,
    719                                 format("-D FILL_ACCUM_LOCAL -D LOCAL_SIZE=%d -D BUFFER_SIZE=%d", workgroup_size, numrho + 2));
    720         if (fillAccumKernel.empty())
    721             return false;
    722         localThreads[0] = workgroup_size; localThreads[1] = 1;
    723         globalThreads[0] = workgroup_size; globalThreads[1] = numangle+2;
    724         fillAccumKernel.args(ocl::KernelArg::ReadOnlyNoSize(pointsList), ocl::KernelArg::WriteOnlyNoSize(accum),
    725                         total_points, irho, (float) theta, numrho, numangle);
    726         return fillAccumKernel.run(2, globalThreads, localThreads, false);
    727     }
    728 }
    729 
    730 static bool ocl_HoughLines(InputArray _src, OutputArray _lines, double rho, double theta, int threshold,
    731                            double min_theta, double max_theta)
    732 {
    733     CV_Assert(_src.type() == CV_8UC1);
    734 
    735     if (max_theta < 0 || max_theta > CV_PI ) {
    736         CV_Error( CV_StsBadArg, "max_theta must fall between 0 and pi" );
    737     }
    738     if (min_theta < 0 || min_theta > max_theta ) {
    739         CV_Error( CV_StsBadArg, "min_theta must fall between 0 and max_theta" );
    740     }
    741     if (!(rho > 0 && theta > 0)) {
    742         CV_Error( CV_StsBadArg, "rho and theta must be greater 0" );
    743     }
    744 
    745     UMat src = _src.getUMat();
    746     int numangle = cvRound((max_theta - min_theta) / theta);
    747     int numrho = cvRound(((src.cols + src.rows) * 2 + 1) / rho);
    748 
    749     UMat pointsList;
    750     UMat counters(1, 2, CV_32SC1, Scalar::all(0));
    751 
    752     if (!ocl_makePointsList(src, pointsList, counters))
    753         return false;
    754 
    755     int total_points = counters.getMat(ACCESS_READ).at<int>(0, 0);
    756     if (total_points <= 0)
    757     {
    758         _lines.assign(UMat(0,0,CV_32FC2));
    759         return true;
    760     }
    761 
    762     UMat accum;
    763     if (!ocl_fillAccum(pointsList, accum, total_points, rho, theta, numrho, numangle))
    764         return false;
    765 
    766     const int pixPerWI = 8;
    767     ocl::Kernel getLinesKernel("get_lines", ocl::imgproc::hough_lines_oclsrc,
    768                                format("-D GET_LINES"));
    769     if (getLinesKernel.empty())
    770         return false;
    771 
    772     int linesMax = threshold > 0 ? min(total_points*numangle/threshold, OCL_MAX_LINES) : OCL_MAX_LINES;
    773     UMat lines(linesMax, 1, CV_32FC2);
    774 
    775     getLinesKernel.args(ocl::KernelArg::ReadOnly(accum), ocl::KernelArg::WriteOnlyNoSize(lines),
    776                         ocl::KernelArg::PtrWriteOnly(counters), linesMax, threshold, (float) rho, (float) theta);
    777 
    778     size_t globalThreads[2] = { (numrho + pixPerWI - 1)/pixPerWI, numangle };
    779     if (!getLinesKernel.run(2, globalThreads, NULL, false))
    780         return false;
    781 
    782     int total_lines = min(counters.getMat(ACCESS_READ).at<int>(0, 1), linesMax);
    783     if (total_lines > 0)
    784         _lines.assign(lines.rowRange(Range(0, total_lines)));
    785     else
    786         _lines.assign(UMat(0,0,CV_32FC2));
    787     return true;
    788 }
    789 
    790 static bool ocl_HoughLinesP(InputArray _src, OutputArray _lines, double rho, double theta, int threshold,
    791                            double minLineLength, double maxGap)
    792 {
    793     CV_Assert(_src.type() == CV_8UC1);
    794 
    795     if (!(rho > 0 && theta > 0)) {
    796         CV_Error( CV_StsBadArg, "rho and theta must be greater 0" );
    797     }
    798 
    799     UMat src = _src.getUMat();
    800     int numangle = cvRound(CV_PI / theta);
    801     int numrho = cvRound(((src.cols + src.rows) * 2 + 1) / rho);
    802 
    803     UMat pointsList;
    804     UMat counters(1, 2, CV_32SC1, Scalar::all(0));
    805 
    806     if (!ocl_makePointsList(src, pointsList, counters))
    807         return false;
    808 
    809     int total_points = counters.getMat(ACCESS_READ).at<int>(0, 0);
    810     if (total_points <= 0)
    811     {
    812         _lines.assign(UMat(0,0,CV_32SC4));
    813         return true;
    814     }
    815 
    816     UMat accum;
    817     if (!ocl_fillAccum(pointsList, accum, total_points, rho, theta, numrho, numangle))
    818         return false;
    819 
    820     ocl::Kernel getLinesKernel("get_lines", ocl::imgproc::hough_lines_oclsrc,
    821                                format("-D GET_LINES_PROBABOLISTIC"));
    822     if (getLinesKernel.empty())
    823         return false;
    824 
    825     int linesMax = threshold > 0 ? min(total_points*numangle/threshold, OCL_MAX_LINES) : OCL_MAX_LINES;
    826     UMat lines(linesMax, 1, CV_32SC4);
    827 
    828     getLinesKernel.args(ocl::KernelArg::ReadOnly(accum), ocl::KernelArg::ReadOnly(src),
    829                         ocl::KernelArg::WriteOnlyNoSize(lines), ocl::KernelArg::PtrWriteOnly(counters),
    830                         linesMax, threshold, (int) minLineLength, (int) maxGap, (float) rho, (float) theta);
    831 
    832     size_t globalThreads[2] = { numrho, numangle };
    833     if (!getLinesKernel.run(2, globalThreads, NULL, false))
    834         return false;
    835 
    836     int total_lines = min(counters.getMat(ACCESS_READ).at<int>(0, 1), linesMax);
    837     if (total_lines > 0)
    838         _lines.assign(lines.rowRange(Range(0, total_lines)));
    839     else
    840         _lines.assign(UMat(0,0,CV_32SC4));
    841 
    842     return true;
    843 }
    844 
    845 #endif /* HAVE_OPENCL */
    846 
    847 }
    848 
    849 void cv::HoughLines( InputArray _image, OutputArray _lines,
    850                     double rho, double theta, int threshold,
    851                     double srn, double stn, double min_theta, double max_theta )
    852 {
    853     CV_OCL_RUN(srn == 0 && stn == 0 && _image.isUMat() && _lines.isUMat(),
    854                ocl_HoughLines(_image, _lines, rho, theta, threshold, min_theta, max_theta));
    855 
    856     Mat image = _image.getMat();
    857     std::vector<Vec2f> lines;
    858 
    859     if( srn == 0 && stn == 0 )
    860         HoughLinesStandard(image, (float)rho, (float)theta, threshold, lines, INT_MAX, min_theta, max_theta );
    861     else
    862         HoughLinesSDiv(image, (float)rho, (float)theta, threshold, cvRound(srn), cvRound(stn), lines, INT_MAX, min_theta, max_theta);
    863 
    864     Mat(lines).copyTo(_lines);
    865 }
    866 
    867 
    868 void cv::HoughLinesP(InputArray _image, OutputArray _lines,
    869                      double rho, double theta, int threshold,
    870                      double minLineLength, double maxGap )
    871 {
    872     CV_OCL_RUN(_image.isUMat() && _lines.isUMat(),
    873                ocl_HoughLinesP(_image, _lines, rho, theta, threshold, minLineLength, maxGap));
    874 
    875     Mat image = _image.getMat();
    876     std::vector<Vec4i> lines;
    877     HoughLinesProbabilistic(image, (float)rho, (float)theta, threshold, cvRound(minLineLength), cvRound(maxGap), lines, INT_MAX);
    878     Mat(lines).copyTo(_lines);
    879 }
    880 
    881 
    882 
    883 /* Wrapper function for standard hough transform */
    884 CV_IMPL CvSeq*
    885 cvHoughLines2( CvArr* src_image, void* lineStorage, int method,
    886                double rho, double theta, int threshold,
    887                double param1, double param2,
    888                double min_theta, double max_theta )
    889 {
    890     cv::Mat image = cv::cvarrToMat(src_image);
    891     std::vector<cv::Vec2f> l2;
    892     std::vector<cv::Vec4i> l4;
    893     CvSeq* result = 0;
    894 
    895     CvMat* mat = 0;
    896     CvSeq* lines = 0;
    897     CvSeq lines_header;
    898     CvSeqBlock lines_block;
    899     int lineType, elemSize;
    900     int linesMax = INT_MAX;
    901     int iparam1, iparam2;
    902 
    903     if( !lineStorage )
    904         CV_Error( CV_StsNullPtr, "NULL destination" );
    905 
    906     if( rho <= 0 || theta <= 0 || threshold <= 0 )
    907         CV_Error( CV_StsOutOfRange, "rho, theta and threshold must be positive" );
    908 
    909     if( method != CV_HOUGH_PROBABILISTIC )
    910     {
    911         lineType = CV_32FC2;
    912         elemSize = sizeof(float)*2;
    913     }
    914     else
    915     {
    916         lineType = CV_32SC4;
    917         elemSize = sizeof(int)*4;
    918     }
    919 
    920     if( CV_IS_STORAGE( lineStorage ))
    921     {
    922         lines = cvCreateSeq( lineType, sizeof(CvSeq), elemSize, (CvMemStorage*)lineStorage );
    923     }
    924     else if( CV_IS_MAT( lineStorage ))
    925     {
    926         mat = (CvMat*)lineStorage;
    927 
    928         if( !CV_IS_MAT_CONT( mat->type ) || (mat->rows != 1 && mat->cols != 1) )
    929             CV_Error( CV_StsBadArg,
    930             "The destination matrix should be continuous and have a single row or a single column" );
    931 
    932         if( CV_MAT_TYPE( mat->type ) != lineType )
    933             CV_Error( CV_StsBadArg,
    934             "The destination matrix data type is inappropriate, see the manual" );
    935 
    936         lines = cvMakeSeqHeaderForArray( lineType, sizeof(CvSeq), elemSize, mat->data.ptr,
    937                                          mat->rows + mat->cols - 1, &lines_header, &lines_block );
    938         linesMax = lines->total;
    939         cvClearSeq( lines );
    940     }
    941     else
    942         CV_Error( CV_StsBadArg, "Destination is not CvMemStorage* nor CvMat*" );
    943 
    944     iparam1 = cvRound(param1);
    945     iparam2 = cvRound(param2);
    946 
    947     switch( method )
    948     {
    949     case CV_HOUGH_STANDARD:
    950         HoughLinesStandard( image, (float)rho,
    951                 (float)theta, threshold, l2, linesMax, min_theta, max_theta );
    952         break;
    953     case CV_HOUGH_MULTI_SCALE:
    954         HoughLinesSDiv( image, (float)rho, (float)theta,
    955                 threshold, iparam1, iparam2, l2, linesMax, min_theta, max_theta );
    956         break;
    957     case CV_HOUGH_PROBABILISTIC:
    958         HoughLinesProbabilistic( image, (float)rho, (float)theta,
    959                 threshold, iparam1, iparam2, l4, linesMax );
    960         break;
    961     default:
    962         CV_Error( CV_StsBadArg, "Unrecognized method id" );
    963     }
    964 
    965     int nlines = (int)(l2.size() + l4.size());
    966 
    967     if( mat )
    968     {
    969         if( mat->cols > mat->rows )
    970             mat->cols = nlines;
    971         else
    972             mat->rows = nlines;
    973     }
    974 
    975     if( nlines )
    976     {
    977         cv::Mat lx = method == CV_HOUGH_STANDARD || method == CV_HOUGH_MULTI_SCALE ?
    978             cv::Mat(nlines, 1, CV_32FC2, &l2[0]) : cv::Mat(nlines, 1, CV_32SC4, &l4[0]);
    979 
    980         if( mat )
    981         {
    982             cv::Mat dst(nlines, 1, lx.type(), mat->data.ptr);
    983             lx.copyTo(dst);
    984         }
    985         else
    986         {
    987             cvSeqPushMulti(lines, lx.ptr(), nlines);
    988         }
    989     }
    990 
    991     if( !mat )
    992         result = lines;
    993     return result;
    994 }
    995 
    996 
    997 /****************************************************************************************\
    998 *                                     Circle Detection                                   *
    999 \****************************************************************************************/
   1000 
   1001 static void
   1002 icvHoughCirclesGradient( CvMat* img, float dp, float min_dist,
   1003                          int min_radius, int max_radius,
   1004                          int canny_threshold, int acc_threshold,
   1005                          CvSeq* circles, int circles_max )
   1006 {
   1007     const int SHIFT = 10, ONE = 1 << SHIFT;
   1008     cv::Ptr<CvMat> dx, dy;
   1009     cv::Ptr<CvMat> edges, accum, dist_buf;
   1010     std::vector<int> sort_buf;
   1011     cv::Ptr<CvMemStorage> storage;
   1012 
   1013     int x, y, i, j, k, center_count, nz_count;
   1014     float min_radius2 = (float)min_radius*min_radius;
   1015     float max_radius2 = (float)max_radius*max_radius;
   1016     int rows, cols, arows, acols;
   1017     int astep, *adata;
   1018     float* ddata;
   1019     CvSeq *nz, *centers;
   1020     float idp, dr;
   1021     CvSeqReader reader;
   1022 
   1023     edges.reset(cvCreateMat( img->rows, img->cols, CV_8UC1 ));
   1024 
   1025     // Use the Canny Edge Detector to detect all the edges in the image.
   1026     cvCanny( img, edges, MAX(canny_threshold/2,1), canny_threshold, 3 );
   1027 
   1028     dx.reset(cvCreateMat( img->rows, img->cols, CV_16SC1 ));
   1029     dy.reset(cvCreateMat( img->rows, img->cols, CV_16SC1 ));
   1030 
   1031     /*Use the Sobel Derivative to compute the local gradient of all the non-zero pixels in the edge image.*/
   1032     cvSobel( img, dx, 1, 0, 3 );
   1033     cvSobel( img, dy, 0, 1, 3 );
   1034 
   1035     if( dp < 1.f )
   1036         dp = 1.f;
   1037     idp = 1.f/dp;
   1038     accum.reset(cvCreateMat( cvCeil(img->rows*idp)+2, cvCeil(img->cols*idp)+2, CV_32SC1 ));
   1039     cvZero(accum);
   1040 
   1041     storage.reset(cvCreateMemStorage());
   1042     /* Create sequences for the nonzero pixels in the edge image and the centers of circles
   1043     which could be detected.*/
   1044     nz = cvCreateSeq( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint), storage );
   1045     centers = cvCreateSeq( CV_32SC1, sizeof(CvSeq), sizeof(int), storage );
   1046 
   1047     rows = img->rows;
   1048     cols = img->cols;
   1049     arows = accum->rows - 2;
   1050     acols = accum->cols - 2;
   1051     adata = accum->data.i;
   1052     astep = accum->step/sizeof(adata[0]);
   1053     // Accumulate circle evidence for each edge pixel
   1054     for( y = 0; y < rows; y++ )
   1055     {
   1056         const uchar* edges_row = edges->data.ptr + y*edges->step;
   1057         const short* dx_row = (const short*)(dx->data.ptr + y*dx->step);
   1058         const short* dy_row = (const short*)(dy->data.ptr + y*dy->step);
   1059 
   1060         for( x = 0; x < cols; x++ )
   1061         {
   1062             float vx, vy;
   1063             int sx, sy, x0, y0, x1, y1, r;
   1064             CvPoint pt;
   1065 
   1066             vx = dx_row[x];
   1067             vy = dy_row[x];
   1068 
   1069             if( !edges_row[x] || (vx == 0 && vy == 0) )
   1070                 continue;
   1071 
   1072             float mag = std::sqrt(vx*vx+vy*vy);
   1073             assert( mag >= 1 );
   1074             sx = cvRound((vx*idp)*ONE/mag);
   1075             sy = cvRound((vy*idp)*ONE/mag);
   1076 
   1077             x0 = cvRound((x*idp)*ONE);
   1078             y0 = cvRound((y*idp)*ONE);
   1079             // Step from min_radius to max_radius in both directions of the gradient
   1080             for(int k1 = 0; k1 < 2; k1++ )
   1081             {
   1082                 x1 = x0 + min_radius * sx;
   1083                 y1 = y0 + min_radius * sy;
   1084 
   1085                 for( r = min_radius; r <= max_radius; x1 += sx, y1 += sy, r++ )
   1086                 {
   1087                     int x2 = x1 >> SHIFT, y2 = y1 >> SHIFT;
   1088                     if( (unsigned)x2 >= (unsigned)acols ||
   1089                         (unsigned)y2 >= (unsigned)arows )
   1090                         break;
   1091                     adata[y2*astep + x2]++;
   1092                 }
   1093 
   1094                 sx = -sx; sy = -sy;
   1095             }
   1096 
   1097             pt.x = x; pt.y = y;
   1098             cvSeqPush( nz, &pt );
   1099         }
   1100     }
   1101 
   1102     nz_count = nz->total;
   1103     if( !nz_count )
   1104         return;
   1105     //Find possible circle centers
   1106     for( y = 1; y < arows - 1; y++ )
   1107     {
   1108         for( x = 1; x < acols - 1; x++ )
   1109         {
   1110             int base = y*(acols+2) + x;
   1111             if( adata[base] > acc_threshold &&
   1112                 adata[base] > adata[base-1] && adata[base] > adata[base+1] &&
   1113                 adata[base] > adata[base-acols-2] && adata[base] > adata[base+acols+2] )
   1114                 cvSeqPush(centers, &base);
   1115         }
   1116     }
   1117 
   1118     center_count = centers->total;
   1119     if( !center_count )
   1120         return;
   1121 
   1122     sort_buf.resize( MAX(center_count,nz_count) );
   1123     cvCvtSeqToArray( centers, &sort_buf[0] );
   1124     /*Sort candidate centers in descending order of their accumulator values, so that the centers
   1125     with the most supporting pixels appear first.*/
   1126     std::sort(sort_buf.begin(), sort_buf.begin() + center_count, cv::hough_cmp_gt(adata));
   1127     cvClearSeq( centers );
   1128     cvSeqPushMulti( centers, &sort_buf[0], center_count );
   1129 
   1130     dist_buf.reset(cvCreateMat( 1, nz_count, CV_32FC1 ));
   1131     ddata = dist_buf->data.fl;
   1132 
   1133     dr = dp;
   1134     min_dist = MAX( min_dist, dp );
   1135     min_dist *= min_dist;
   1136     // For each found possible center
   1137     // Estimate radius and check support
   1138     for( i = 0; i < centers->total; i++ )
   1139     {
   1140         int ofs = *(int*)cvGetSeqElem( centers, i );
   1141         y = ofs/(acols+2);
   1142         x = ofs - (y)*(acols+2);
   1143         //Calculate circle's center in pixels
   1144         float cx = (float)((x + 0.5f)*dp), cy = (float)(( y + 0.5f )*dp);
   1145         float start_dist, dist_sum;
   1146         float r_best = 0;
   1147         int max_count = 0;
   1148         // Check distance with previously detected circles
   1149         for( j = 0; j < circles->total; j++ )
   1150         {
   1151             float* c = (float*)cvGetSeqElem( circles, j );
   1152             if( (c[0] - cx)*(c[0] - cx) + (c[1] - cy)*(c[1] - cy) < min_dist )
   1153                 break;
   1154         }
   1155 
   1156         if( j < circles->total )
   1157             continue;
   1158         // Estimate best radius
   1159         cvStartReadSeq( nz, &reader );
   1160         for( j = k = 0; j < nz_count; j++ )
   1161         {
   1162             CvPoint pt;
   1163             float _dx, _dy, _r2;
   1164             CV_READ_SEQ_ELEM( pt, reader );
   1165             _dx = cx - pt.x; _dy = cy - pt.y;
   1166             _r2 = _dx*_dx + _dy*_dy;
   1167             if(min_radius2 <= _r2 && _r2 <= max_radius2 )
   1168             {
   1169                 ddata[k] = _r2;
   1170                 sort_buf[k] = k;
   1171                 k++;
   1172             }
   1173         }
   1174 
   1175         int nz_count1 = k, start_idx = nz_count1 - 1;
   1176         if( nz_count1 == 0 )
   1177             continue;
   1178         dist_buf->cols = nz_count1;
   1179         cvPow( dist_buf, dist_buf, 0.5 );
   1180         // Sort non-zero pixels according to their distance from the center.
   1181         std::sort(sort_buf.begin(), sort_buf.begin() + nz_count1, cv::hough_cmp_gt((int*)ddata));
   1182 
   1183         dist_sum = start_dist = ddata[sort_buf[nz_count1-1]];
   1184         for( j = nz_count1 - 2; j >= 0; j-- )
   1185         {
   1186             float d = ddata[sort_buf[j]];
   1187 
   1188             if( d > max_radius )
   1189                 break;
   1190 
   1191             if( d - start_dist > dr )
   1192             {
   1193                 float r_cur = ddata[sort_buf[(j + start_idx)/2]];
   1194                 if( (start_idx - j)*r_best >= max_count*r_cur ||
   1195                     (r_best < FLT_EPSILON && start_idx - j >= max_count) )
   1196                 {
   1197                     r_best = r_cur;
   1198                     max_count = start_idx - j;
   1199                 }
   1200                 start_dist = d;
   1201                 start_idx = j;
   1202                 dist_sum = 0;
   1203             }
   1204             dist_sum += d;
   1205         }
   1206         // Check if the circle has enough support
   1207         if( max_count > acc_threshold )
   1208         {
   1209             float c[3];
   1210             c[0] = cx;
   1211             c[1] = cy;
   1212             c[2] = (float)r_best;
   1213             cvSeqPush( circles, c );
   1214             if( circles->total > circles_max )
   1215                 return;
   1216         }
   1217     }
   1218 }
   1219 
   1220 CV_IMPL CvSeq*
   1221 cvHoughCircles( CvArr* src_image, void* circle_storage,
   1222                 int method, double dp, double min_dist,
   1223                 double param1, double param2,
   1224                 int min_radius, int max_radius )
   1225 {
   1226     CvSeq* result = 0;
   1227 
   1228     CvMat stub, *img = (CvMat*)src_image;
   1229     CvMat* mat = 0;
   1230     CvSeq* circles = 0;
   1231     CvSeq circles_header;
   1232     CvSeqBlock circles_block;
   1233     int circles_max = INT_MAX;
   1234     int canny_threshold = cvRound(param1);
   1235     int acc_threshold = cvRound(param2);
   1236 
   1237     img = cvGetMat( img, &stub );
   1238 
   1239     if( !CV_IS_MASK_ARR(img))
   1240         CV_Error( CV_StsBadArg, "The source image must be 8-bit, single-channel" );
   1241 
   1242     if( !circle_storage )
   1243         CV_Error( CV_StsNullPtr, "NULL destination" );
   1244 
   1245     if( dp <= 0 || min_dist <= 0 || canny_threshold <= 0 || acc_threshold <= 0 )
   1246         CV_Error( CV_StsOutOfRange, "dp, min_dist, canny_threshold and acc_threshold must be all positive numbers" );
   1247 
   1248     min_radius = MAX( min_radius, 0 );
   1249     if( max_radius <= 0 )
   1250         max_radius = MAX( img->rows, img->cols );
   1251     else if( max_radius <= min_radius )
   1252         max_radius = min_radius + 2;
   1253 
   1254     if( CV_IS_STORAGE( circle_storage ))
   1255     {
   1256         circles = cvCreateSeq( CV_32FC3, sizeof(CvSeq),
   1257             sizeof(float)*3, (CvMemStorage*)circle_storage );
   1258     }
   1259     else if( CV_IS_MAT( circle_storage ))
   1260     {
   1261         mat = (CvMat*)circle_storage;
   1262 
   1263         if( !CV_IS_MAT_CONT( mat->type ) || (mat->rows != 1 && mat->cols != 1) ||
   1264             CV_MAT_TYPE(mat->type) != CV_32FC3 )
   1265             CV_Error( CV_StsBadArg,
   1266             "The destination matrix should be continuous and have a single row or a single column" );
   1267 
   1268         circles = cvMakeSeqHeaderForArray( CV_32FC3, sizeof(CvSeq), sizeof(float)*3,
   1269                 mat->data.ptr, mat->rows + mat->cols - 1, &circles_header, &circles_block );
   1270         circles_max = circles->total;
   1271         cvClearSeq( circles );
   1272     }
   1273     else
   1274         CV_Error( CV_StsBadArg, "Destination is not CvMemStorage* nor CvMat*" );
   1275 
   1276     switch( method )
   1277     {
   1278     case CV_HOUGH_GRADIENT:
   1279         icvHoughCirclesGradient( img, (float)dp, (float)min_dist,
   1280                                 min_radius, max_radius, canny_threshold,
   1281                                 acc_threshold, circles, circles_max );
   1282           break;
   1283     default:
   1284         CV_Error( CV_StsBadArg, "Unrecognized method id" );
   1285     }
   1286 
   1287     if( mat )
   1288     {
   1289         if( mat->cols > mat->rows )
   1290             mat->cols = circles->total;
   1291         else
   1292             mat->rows = circles->total;
   1293     }
   1294     else
   1295         result = circles;
   1296 
   1297     return result;
   1298 }
   1299 
   1300 
   1301 namespace cv
   1302 {
   1303 
   1304 const int STORAGE_SIZE = 1 << 12;
   1305 
   1306 static void seqToMat(const CvSeq* seq, OutputArray _arr)
   1307 {
   1308     if( seq && seq->total > 0 )
   1309     {
   1310         _arr.create(1, seq->total, seq->flags, -1, true);
   1311         Mat arr = _arr.getMat();
   1312         cvCvtSeqToArray(seq, arr.ptr());
   1313     }
   1314     else
   1315         _arr.release();
   1316 }
   1317 
   1318 }
   1319 
   1320 void cv::HoughCircles( InputArray _image, OutputArray _circles,
   1321                        int method, double dp, double min_dist,
   1322                        double param1, double param2,
   1323                        int minRadius, int maxRadius )
   1324 {
   1325     Ptr<CvMemStorage> storage(cvCreateMemStorage(STORAGE_SIZE));
   1326     Mat image = _image.getMat();
   1327     CvMat c_image = image;
   1328     CvSeq* seq = cvHoughCircles( &c_image, storage, method,
   1329                     dp, min_dist, param1, param2, minRadius, maxRadius );
   1330     seqToMat(seq, _circles);
   1331 }
   1332 
   1333 /* End of file. */
   1334