• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
hough_cmp_gtcv::hough_cmp_gt60     hough_cmp_gt(const int* _aux) : aux(_aux) {}
operator ()cv::hough_cmp_gt61     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
HoughLinesStandard(const Mat & img,float rho,float theta,int threshold,std::vector<Vec2f> & lines,int linesMax,double min_theta,double max_theta)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 {
hough_indexcv::hough_index188     hough_index() : value(0), rho(0.f), theta(0.f) {}
hough_indexcv::hough_index189     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
HoughLinesSDiv(const Mat & img,float rho,float theta,int threshold,int srn,int stn,std::vector<Vec2f> & lines,int linesMax,double min_theta,double max_theta)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
HoughLinesProbabilistic(Mat & image,float rho,float theta,int threshold,int lineLength,int lineGap,std::vector<Vec4i> & lines,int linesMax)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 
ocl_makePointsList(InputArray _src,OutputArray _pointsList,InputOutputArray _counters)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 
ocl_fillAccum(InputArray _pointsList,OutputArray _accum,int total_points,double rho,double theta,int numrho,int numangle)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 
ocl_HoughLines(InputArray _src,OutputArray _lines,double rho,double theta,int threshold,double min_theta,double max_theta)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 
ocl_HoughLinesP(InputArray _src,OutputArray _lines,double rho,double theta,int threshold,double minLineLength,double maxGap)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 
HoughLines(InputArray _image,OutputArray _lines,double rho,double theta,int threshold,double srn,double stn,double min_theta,double max_theta)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 
HoughLinesP(InputArray _image,OutputArray _lines,double rho,double theta,int threshold,double minLineLength,double maxGap)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*
cvHoughLines2(CvArr * src_image,void * lineStorage,int method,double rho,double theta,int threshold,double param1,double param2,double min_theta,double max_theta)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
icvHoughCirclesGradient(CvMat * img,float dp,float min_dist,int min_radius,int max_radius,int canny_threshold,int acc_threshold,CvSeq * circles,int circles_max)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*
cvHoughCircles(CvArr * src_image,void * circle_storage,int method,double dp,double min_dist,double param1,double param2,int min_radius,int max_radius)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 
seqToMat(const CvSeq * seq,OutputArray _arr)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 
HoughCircles(InputArray _image,OutputArray _circles,int method,double dp,double min_dist,double param1,double param2,int minRadius,int maxRadius)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