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