PageRenderTime 54ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/imgproc/src/hough.cpp

https://gitlab.com/gaurav1981/opencv
C++ | 1080 lines | 818 code | 160 blank | 102 comment | 169 complexity | 0d4c22fab3e10d092931bde58bbca1b8 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-3.0
  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. // Third party copyrights are property of their respective owners.
  16. //
  17. // Redistribution and use in source and binary forms, with or without modification,
  18. // are permitted provided that the following conditions are met:
  19. //
  20. // * Redistribution's of source code must retain the above copyright notice,
  21. // this list of conditions and the following disclaimer.
  22. //
  23. // * Redistribution's in binary form must reproduce the above copyright notice,
  24. // this list of conditions and the following disclaimer in the documentation
  25. // and/or other materials provided with the distribution.
  26. //
  27. // * The name of the copyright holders may not be used to endorse or promote products
  28. // derived from this software without specific prior written permission.
  29. //
  30. // This software is provided by the copyright holders and contributors "as is" and
  31. // any express or implied warranties, including, but not limited to, the implied
  32. // warranties of merchantability and fitness for a particular purpose are disclaimed.
  33. // In no event shall the Intel Corporation or contributors be liable for any direct,
  34. // indirect, incidental, special, exemplary, or consequential damages
  35. // (including, but not limited to, procurement of substitute goods or services;
  36. // loss of use, data, or profits; or business interruption) however caused
  37. // and on any theory of liability, whether in contract, strict liability,
  38. // or tort (including negligence or otherwise) arising in any way out of
  39. // the use of this software, even if advised of the possibility of such damage.
  40. //
  41. //M*/
  42. #include "precomp.hpp"
  43. namespace cv
  44. {
  45. // Classical Hough Transform
  46. struct LinePolar
  47. {
  48. float rho;
  49. float angle;
  50. };
  51. struct hough_cmp_gt
  52. {
  53. hough_cmp_gt(const int* _aux) : aux(_aux) {}
  54. bool operator()(int l1, int l2) const
  55. {
  56. return aux[l1] > aux[l2] || (aux[l1] == aux[l2] && l1 < l2);
  57. }
  58. const int* aux;
  59. };
  60. /*
  61. Here image is an input raster;
  62. step is it's step; size characterizes it's ROI;
  63. rho and theta are discretization steps (in pixels and radians correspondingly).
  64. threshold is the minimum number of pixels in the feature for it
  65. to be a candidate for line. lines is the output
  66. array of (rho, theta) pairs. linesMax is the buffer size (number of pairs).
  67. Functions return the actual number of found lines.
  68. */
  69. static void
  70. HoughLinesStandard( const Mat& img, float rho, float theta,
  71. int threshold, std::vector<Vec2f>& lines, int linesMax,
  72. double min_theta, double max_theta )
  73. {
  74. int i, j;
  75. float irho = 1 / rho;
  76. CV_Assert( img.type() == CV_8UC1 );
  77. const uchar* image = img.data;
  78. int step = (int)img.step;
  79. int width = img.cols;
  80. int height = img.rows;
  81. if (max_theta < 0 || max_theta > CV_PI ) {
  82. CV_Error( CV_StsBadArg, "max_theta must fall between 0 and pi" );
  83. }
  84. if (min_theta < 0 || min_theta > max_theta ) {
  85. CV_Error( CV_StsBadArg, "min_theta must fall between 0 and max_theta" );
  86. }
  87. int numangle = cvRound((max_theta - min_theta) / theta);
  88. int numrho = cvRound(((width + height) * 2 + 1) / rho);
  89. AutoBuffer<int> _accum((numangle+2) * (numrho+2));
  90. std::vector<int> _sort_buf;
  91. AutoBuffer<float> _tabSin(numangle);
  92. AutoBuffer<float> _tabCos(numangle);
  93. int *accum = _accum;
  94. float *tabSin = _tabSin, *tabCos = _tabCos;
  95. memset( accum, 0, sizeof(accum[0]) * (numangle+2) * (numrho+2) );
  96. float ang = static_cast<float>(min_theta);
  97. for(int n = 0; n < numangle; ang += theta, n++ )
  98. {
  99. tabSin[n] = (float)(sin((double)ang) * irho);
  100. tabCos[n] = (float)(cos((double)ang) * irho);
  101. }
  102. // stage 1. fill accumulator
  103. for( i = 0; i < height; i++ )
  104. for( j = 0; j < width; j++ )
  105. {
  106. if( image[i * step + j] != 0 )
  107. for(int n = 0; n < numangle; n++ )
  108. {
  109. int r = cvRound( j * tabCos[n] + i * tabSin[n] );
  110. r += (numrho - 1) / 2;
  111. accum[(n+1) * (numrho+2) + r+1]++;
  112. }
  113. }
  114. // stage 2. find local maximums
  115. for(int r = 0; r < numrho; r++ )
  116. for(int n = 0; n < numangle; n++ )
  117. {
  118. int base = (n+1) * (numrho+2) + r+1;
  119. if( accum[base] > threshold &&
  120. accum[base] > accum[base - 1] && accum[base] >= accum[base + 1] &&
  121. accum[base] > accum[base - numrho - 2] && accum[base] >= accum[base + numrho + 2] )
  122. _sort_buf.push_back(base);
  123. }
  124. // stage 3. sort the detected lines by accumulator value
  125. std::sort(_sort_buf.begin(), _sort_buf.end(), hough_cmp_gt(accum));
  126. // stage 4. store the first min(total,linesMax) lines to the output buffer
  127. linesMax = std::min(linesMax, (int)_sort_buf.size());
  128. double scale = 1./(numrho+2);
  129. for( i = 0; i < linesMax; i++ )
  130. {
  131. LinePolar line;
  132. int idx = _sort_buf[i];
  133. int n = cvFloor(idx*scale) - 1;
  134. int r = idx - (n+1)*(numrho+2) - 1;
  135. line.rho = (r - (numrho - 1)*0.5f) * rho;
  136. line.angle = n * theta;
  137. lines.push_back(Vec2f(line.rho, line.angle));
  138. }
  139. }
  140. // Multi-Scale variant of Classical Hough Transform
  141. struct hough_index
  142. {
  143. hough_index() : value(0), rho(0.f), theta(0.f) {}
  144. hough_index(int _val, float _rho, float _theta)
  145. : value(_val), rho(_rho), theta(_theta) {}
  146. int value;
  147. float rho, theta;
  148. };
  149. static void
  150. HoughLinesSDiv( const Mat& img,
  151. float rho, float theta, int threshold,
  152. int srn, int stn,
  153. std::vector<Vec2f>& lines, int linesMax,
  154. double min_theta, double max_theta )
  155. {
  156. #define _POINT(row, column)\
  157. (image_src[(row)*step+(column)])
  158. int index, i;
  159. int ri, ti, ti1, ti0;
  160. int row, col;
  161. float r, t; /* Current rho and theta */
  162. float rv; /* Some temporary rho value */
  163. int fn = 0;
  164. float xc, yc;
  165. const float d2r = (float)(CV_PI / 180);
  166. int sfn = srn * stn;
  167. int fi;
  168. int count;
  169. int cmax = 0;
  170. std::vector<hough_index> lst;
  171. CV_Assert( img.type() == CV_8UC1 );
  172. CV_Assert( linesMax > 0 && rho > 0 && theta > 0 );
  173. threshold = MIN( threshold, 255 );
  174. const uchar* image_src = img.data;
  175. int step = (int)img.step;
  176. int w = img.cols;
  177. int h = img.rows;
  178. float irho = 1 / rho;
  179. float itheta = 1 / theta;
  180. float srho = rho / srn;
  181. float stheta = theta / stn;
  182. float isrho = 1 / srho;
  183. float istheta = 1 / stheta;
  184. int rn = cvFloor( std::sqrt( (double)w * w + (double)h * h ) * irho );
  185. int tn = cvFloor( 2 * CV_PI * itheta );
  186. lst.push_back(hough_index(threshold, -1.f, 0.f));
  187. // Precalculate sin table
  188. std::vector<float> _sinTable( 5 * tn * stn );
  189. float* sinTable = &_sinTable[0];
  190. for( index = 0; index < 5 * tn * stn; index++ )
  191. sinTable[index] = (float)cos( stheta * index * 0.2f );
  192. std::vector<uchar> _caccum(rn * tn, (uchar)0);
  193. uchar* caccum = &_caccum[0];
  194. // Counting all feature pixels
  195. for( row = 0; row < h; row++ )
  196. for( col = 0; col < w; col++ )
  197. fn += _POINT( row, col ) != 0;
  198. std::vector<int> _x(fn), _y(fn);
  199. int* x = &_x[0], *y = &_y[0];
  200. // Full Hough Transform (it's accumulator update part)
  201. fi = 0;
  202. for( row = 0; row < h; row++ )
  203. {
  204. for( col = 0; col < w; col++ )
  205. {
  206. if( _POINT( row, col ))
  207. {
  208. int halftn;
  209. float r0;
  210. float scale_factor;
  211. int iprev = -1;
  212. float phi, phi1;
  213. float theta_it; // Value of theta for iterating
  214. // Remember the feature point
  215. x[fi] = col;
  216. y[fi] = row;
  217. fi++;
  218. yc = (float) row + 0.5f;
  219. xc = (float) col + 0.5f;
  220. /* Update the accumulator */
  221. t = (float) fabs( cvFastArctan( yc, xc ) * d2r );
  222. r = (float) std::sqrt( (double)xc * xc + (double)yc * yc );
  223. r0 = r * irho;
  224. ti0 = cvFloor( (t + CV_PI*0.5) * itheta );
  225. caccum[ti0]++;
  226. theta_it = rho / r;
  227. theta_it = theta_it < theta ? theta_it : theta;
  228. scale_factor = theta_it * itheta;
  229. halftn = cvFloor( CV_PI / theta_it );
  230. for( ti1 = 1, phi = theta_it - (float)(CV_PI*0.5), phi1 = (theta_it + t) * itheta;
  231. ti1 < halftn; ti1++, phi += theta_it, phi1 += scale_factor )
  232. {
  233. rv = r0 * std::cos( phi );
  234. i = cvFloor( rv ) * tn;
  235. i += cvFloor( phi1 );
  236. assert( i >= 0 );
  237. assert( i < rn * tn );
  238. caccum[i] = (uchar) (caccum[i] + ((i ^ iprev) != 0));
  239. iprev = i;
  240. if( cmax < caccum[i] )
  241. cmax = caccum[i];
  242. }
  243. }
  244. }
  245. }
  246. // Starting additional analysis
  247. count = 0;
  248. for( ri = 0; ri < rn; ri++ )
  249. {
  250. for( ti = 0; ti < tn; ti++ )
  251. {
  252. if( caccum[ri * tn + ti] > threshold )
  253. count++;
  254. }
  255. }
  256. if( count * 100 > rn * tn )
  257. {
  258. HoughLinesStandard( img, rho, theta, threshold, lines, linesMax, min_theta, max_theta );
  259. return;
  260. }
  261. std::vector<uchar> _buffer(srn * stn + 2);
  262. uchar* buffer = &_buffer[0];
  263. uchar* mcaccum = buffer + 1;
  264. count = 0;
  265. for( ri = 0; ri < rn; ri++ )
  266. {
  267. for( ti = 0; ti < tn; ti++ )
  268. {
  269. if( caccum[ri * tn + ti] > threshold )
  270. {
  271. count++;
  272. memset( mcaccum, 0, sfn * sizeof( uchar ));
  273. for( index = 0; index < fn; index++ )
  274. {
  275. int ti2;
  276. float r0;
  277. yc = (float) y[index] + 0.5f;
  278. xc = (float) x[index] + 0.5f;
  279. // Update the accumulator
  280. t = (float) fabs( cvFastArctan( yc, xc ) * d2r );
  281. r = (float) std::sqrt( (double)xc * xc + (double)yc * yc ) * isrho;
  282. ti0 = cvFloor( (t + CV_PI * 0.5) * istheta );
  283. ti2 = (ti * stn - ti0) * 5;
  284. r0 = (float) ri *srn;
  285. for( ti1 = 0; ti1 < stn; ti1++, ti2 += 5 )
  286. {
  287. rv = r * sinTable[(int) (std::abs( ti2 ))] - r0;
  288. i = cvFloor( rv ) * stn + ti1;
  289. i = CV_IMAX( i, -1 );
  290. i = CV_IMIN( i, sfn );
  291. mcaccum[i]++;
  292. assert( i >= -1 );
  293. assert( i <= sfn );
  294. }
  295. }
  296. // Find peaks in maccum...
  297. for( index = 0; index < sfn; index++ )
  298. {
  299. i = 0;
  300. int pos = (int)(lst.size() - 1);
  301. if( pos < 0 || lst[pos].value < mcaccum[index] )
  302. {
  303. hough_index vi(mcaccum[index],
  304. index / stn * srho + ri * rho,
  305. index % stn * stheta + ti * theta - (float)(CV_PI*0.5));
  306. lst.push_back(vi);
  307. for( ; pos >= 0; pos-- )
  308. {
  309. if( lst[pos].value > vi.value )
  310. break;
  311. lst[pos+1] = lst[pos];
  312. }
  313. lst[pos+1] = vi;
  314. if( (int)lst.size() > linesMax )
  315. lst.pop_back();
  316. }
  317. }
  318. }
  319. }
  320. }
  321. for( size_t idx = 0; idx < lst.size(); idx++ )
  322. {
  323. if( lst[idx].rho < 0 )
  324. continue;
  325. lines.push_back(Vec2f(lst[idx].rho, lst[idx].theta));
  326. }
  327. }
  328. /****************************************************************************************\
  329. * Probabilistic Hough Transform *
  330. \****************************************************************************************/
  331. static void
  332. HoughLinesProbabilistic( Mat& image,
  333. float rho, float theta, int threshold,
  334. int lineLength, int lineGap,
  335. std::vector<Vec4i>& lines, int linesMax )
  336. {
  337. Point pt;
  338. float irho = 1 / rho;
  339. RNG rng((uint64)-1);
  340. CV_Assert( image.type() == CV_8UC1 );
  341. int width = image.cols;
  342. int height = image.rows;
  343. int numangle = cvRound(CV_PI / theta);
  344. int numrho = cvRound(((width + height) * 2 + 1) / rho);
  345. Mat accum = Mat::zeros( numangle, numrho, CV_32SC1 );
  346. Mat mask( height, width, CV_8UC1 );
  347. std::vector<float> trigtab(numangle*2);
  348. for( int n = 0; n < numangle; n++ )
  349. {
  350. trigtab[n*2] = (float)(cos((double)n*theta) * irho);
  351. trigtab[n*2+1] = (float)(sin((double)n*theta) * irho);
  352. }
  353. const float* ttab = &trigtab[0];
  354. uchar* mdata0 = mask.data;
  355. std::vector<Point> nzloc;
  356. // stage 1. collect non-zero image points
  357. for( pt.y = 0; pt.y < height; pt.y++ )
  358. {
  359. const uchar* data = image.ptr(pt.y);
  360. uchar* mdata = mask.ptr(pt.y);
  361. for( pt.x = 0; pt.x < width; pt.x++ )
  362. {
  363. if( data[pt.x] )
  364. {
  365. mdata[pt.x] = (uchar)1;
  366. nzloc.push_back(pt);
  367. }
  368. else
  369. mdata[pt.x] = 0;
  370. }
  371. }
  372. int count = (int)nzloc.size();
  373. // stage 2. process all the points in random order
  374. for( ; count > 0; count-- )
  375. {
  376. // choose random point out of the remaining ones
  377. int idx = rng.uniform(0, count);
  378. int max_val = threshold-1, max_n = 0;
  379. Point point = nzloc[idx];
  380. Point line_end[2];
  381. float a, b;
  382. int* adata = (int*)accum.data;
  383. int i = point.y, j = point.x, k, x0, y0, dx0, dy0, xflag;
  384. int good_line;
  385. const int shift = 16;
  386. // "remove" it by overriding it with the last element
  387. nzloc[idx] = nzloc[count-1];
  388. // check if it has been excluded already (i.e. belongs to some other line)
  389. if( !mdata0[i*width + j] )
  390. continue;
  391. // update accumulator, find the most probable line
  392. for( int n = 0; n < numangle; n++, adata += numrho )
  393. {
  394. int r = cvRound( j * ttab[n*2] + i * ttab[n*2+1] );
  395. r += (numrho - 1) / 2;
  396. int val = ++adata[r];
  397. if( max_val < val )
  398. {
  399. max_val = val;
  400. max_n = n;
  401. }
  402. }
  403. // if it is too "weak" candidate, continue with another point
  404. if( max_val < threshold )
  405. continue;
  406. // from the current point walk in each direction
  407. // along the found line and extract the line segment
  408. a = -ttab[max_n*2+1];
  409. b = ttab[max_n*2];
  410. x0 = j;
  411. y0 = i;
  412. if( fabs(a) > fabs(b) )
  413. {
  414. xflag = 1;
  415. dx0 = a > 0 ? 1 : -1;
  416. dy0 = cvRound( b*(1 << shift)/fabs(a) );
  417. y0 = (y0 << shift) + (1 << (shift-1));
  418. }
  419. else
  420. {
  421. xflag = 0;
  422. dy0 = b > 0 ? 1 : -1;
  423. dx0 = cvRound( a*(1 << shift)/fabs(b) );
  424. x0 = (x0 << shift) + (1 << (shift-1));
  425. }
  426. for( k = 0; k < 2; k++ )
  427. {
  428. int gap = 0, x = x0, y = y0, dx = dx0, dy = dy0;
  429. if( k > 0 )
  430. dx = -dx, dy = -dy;
  431. // walk along the line using fixed-point arithmetics,
  432. // stop at the image border or in case of too big gap
  433. for( ;; x += dx, y += dy )
  434. {
  435. uchar* mdata;
  436. int i1, j1;
  437. if( xflag )
  438. {
  439. j1 = x;
  440. i1 = y >> shift;
  441. }
  442. else
  443. {
  444. j1 = x >> shift;
  445. i1 = y;
  446. }
  447. if( j1 < 0 || j1 >= width || i1 < 0 || i1 >= height )
  448. break;
  449. mdata = mdata0 + i1*width + j1;
  450. // for each non-zero point:
  451. // update line end,
  452. // clear the mask element
  453. // reset the gap
  454. if( *mdata )
  455. {
  456. gap = 0;
  457. line_end[k].y = i1;
  458. line_end[k].x = j1;
  459. }
  460. else if( ++gap > lineGap )
  461. break;
  462. }
  463. }
  464. good_line = std::abs(line_end[1].x - line_end[0].x) >= lineLength ||
  465. std::abs(line_end[1].y - line_end[0].y) >= lineLength;
  466. for( k = 0; k < 2; k++ )
  467. {
  468. int x = x0, y = y0, dx = dx0, dy = dy0;
  469. if( k > 0 )
  470. dx = -dx, dy = -dy;
  471. // walk along the line using fixed-point arithmetics,
  472. // stop at the image border or in case of too big gap
  473. for( ;; x += dx, y += dy )
  474. {
  475. uchar* mdata;
  476. int i1, j1;
  477. if( xflag )
  478. {
  479. j1 = x;
  480. i1 = y >> shift;
  481. }
  482. else
  483. {
  484. j1 = x >> shift;
  485. i1 = y;
  486. }
  487. mdata = mdata0 + i1*width + j1;
  488. // for each non-zero point:
  489. // update line end,
  490. // clear the mask element
  491. // reset the gap
  492. if( *mdata )
  493. {
  494. if( good_line )
  495. {
  496. adata = (int*)accum.data;
  497. for( int n = 0; n < numangle; n++, adata += numrho )
  498. {
  499. int r = cvRound( j1 * ttab[n*2] + i1 * ttab[n*2+1] );
  500. r += (numrho - 1) / 2;
  501. adata[r]--;
  502. }
  503. }
  504. *mdata = 0;
  505. }
  506. if( i1 == line_end[k].y && j1 == line_end[k].x )
  507. break;
  508. }
  509. }
  510. if( good_line )
  511. {
  512. Vec4i lr(line_end[0].x, line_end[0].y, line_end[1].x, line_end[1].y);
  513. lines.push_back(lr);
  514. if( (int)lines.size() >= linesMax )
  515. return;
  516. }
  517. }
  518. }
  519. }
  520. void cv::HoughLines( InputArray _image, OutputArray _lines,
  521. double rho, double theta, int threshold,
  522. double srn, double stn, double min_theta, double max_theta )
  523. {
  524. Mat image = _image.getMat();
  525. std::vector<Vec2f> lines;
  526. if( srn == 0 && stn == 0 )
  527. HoughLinesStandard(image, (float)rho, (float)theta, threshold, lines, INT_MAX, min_theta, max_theta );
  528. else
  529. HoughLinesSDiv(image, (float)rho, (float)theta, threshold, cvRound(srn), cvRound(stn), lines, INT_MAX, min_theta, max_theta);
  530. Mat(lines).copyTo(_lines);
  531. }
  532. void cv::HoughLinesP(InputArray _image, OutputArray _lines,
  533. double rho, double theta, int threshold,
  534. double minLineLength, double maxGap )
  535. {
  536. Mat image = _image.getMat();
  537. std::vector<Vec4i> lines;
  538. HoughLinesProbabilistic(image, (float)rho, (float)theta, threshold, cvRound(minLineLength), cvRound(maxGap), lines, INT_MAX);
  539. Mat(lines).copyTo(_lines);
  540. }
  541. /* Wrapper function for standard hough transform */
  542. CV_IMPL CvSeq*
  543. cvHoughLines2( CvArr* src_image, void* lineStorage, int method,
  544. double rho, double theta, int threshold,
  545. double param1, double param2,
  546. double min_theta, double max_theta )
  547. {
  548. cv::Mat image = cv::cvarrToMat(src_image);
  549. std::vector<cv::Vec2f> l2;
  550. std::vector<cv::Vec4i> l4;
  551. CvSeq* result = 0;
  552. CvMat* mat = 0;
  553. CvSeq* lines = 0;
  554. CvSeq lines_header;
  555. CvSeqBlock lines_block;
  556. int lineType, elemSize;
  557. int linesMax = INT_MAX;
  558. int iparam1, iparam2;
  559. if( !lineStorage )
  560. CV_Error( CV_StsNullPtr, "NULL destination" );
  561. if( rho <= 0 || theta <= 0 || threshold <= 0 )
  562. CV_Error( CV_StsOutOfRange, "rho, theta and threshold must be positive" );
  563. if( method != CV_HOUGH_PROBABILISTIC )
  564. {
  565. lineType = CV_32FC2;
  566. elemSize = sizeof(float)*2;
  567. }
  568. else
  569. {
  570. lineType = CV_32SC4;
  571. elemSize = sizeof(int)*4;
  572. }
  573. if( CV_IS_STORAGE( lineStorage ))
  574. {
  575. lines = cvCreateSeq( lineType, sizeof(CvSeq), elemSize, (CvMemStorage*)lineStorage );
  576. }
  577. else if( CV_IS_MAT( lineStorage ))
  578. {
  579. mat = (CvMat*)lineStorage;
  580. if( !CV_IS_MAT_CONT( mat->type ) || (mat->rows != 1 && mat->cols != 1) )
  581. CV_Error( CV_StsBadArg,
  582. "The destination matrix should be continuous and have a single row or a single column" );
  583. if( CV_MAT_TYPE( mat->type ) != lineType )
  584. CV_Error( CV_StsBadArg,
  585. "The destination matrix data type is inappropriate, see the manual" );
  586. lines = cvMakeSeqHeaderForArray( lineType, sizeof(CvSeq), elemSize, mat->data.ptr,
  587. mat->rows + mat->cols - 1, &lines_header, &lines_block );
  588. linesMax = lines->total;
  589. cvClearSeq( lines );
  590. }
  591. else
  592. CV_Error( CV_StsBadArg, "Destination is not CvMemStorage* nor CvMat*" );
  593. iparam1 = cvRound(param1);
  594. iparam2 = cvRound(param2);
  595. switch( method )
  596. {
  597. case CV_HOUGH_STANDARD:
  598. HoughLinesStandard( image, (float)rho,
  599. (float)theta, threshold, l2, linesMax, min_theta, max_theta );
  600. break;
  601. case CV_HOUGH_MULTI_SCALE:
  602. HoughLinesSDiv( image, (float)rho, (float)theta,
  603. threshold, iparam1, iparam2, l2, linesMax, min_theta, max_theta );
  604. break;
  605. case CV_HOUGH_PROBABILISTIC:
  606. HoughLinesProbabilistic( image, (float)rho, (float)theta,
  607. threshold, iparam1, iparam2, l4, linesMax );
  608. break;
  609. default:
  610. CV_Error( CV_StsBadArg, "Unrecognized method id" );
  611. }
  612. int nlines = (int)(l2.size() + l4.size());
  613. if( mat )
  614. {
  615. if( mat->cols > mat->rows )
  616. mat->cols = nlines;
  617. else
  618. mat->rows = nlines;
  619. }
  620. if( nlines )
  621. {
  622. cv::Mat lx = method == CV_HOUGH_STANDARD || method == CV_HOUGH_MULTI_SCALE ?
  623. cv::Mat(nlines, 1, CV_32FC2, &l2[0]) : cv::Mat(nlines, 1, CV_32SC4, &l4[0]);
  624. if( mat )
  625. {
  626. cv::Mat dst(nlines, 1, lx.type(), mat->data.ptr);
  627. lx.copyTo(dst);
  628. }
  629. else
  630. {
  631. cvSeqPushMulti(lines, lx.data, nlines);
  632. }
  633. }
  634. if( !mat )
  635. result = lines;
  636. return result;
  637. }
  638. /****************************************************************************************\
  639. * Circle Detection *
  640. \****************************************************************************************/
  641. static void
  642. icvHoughCirclesGradient( CvMat* img, float dp, float min_dist,
  643. int min_radius, int max_radius,
  644. int canny_threshold, int acc_threshold,
  645. CvSeq* circles, int circles_max )
  646. {
  647. const int SHIFT = 10, ONE = 1 << SHIFT;
  648. cv::Ptr<CvMat> dx, dy;
  649. cv::Ptr<CvMat> edges, accum, dist_buf;
  650. std::vector<int> sort_buf;
  651. cv::Ptr<CvMemStorage> storage;
  652. int x, y, i, j, k, center_count, nz_count;
  653. float min_radius2 = (float)min_radius*min_radius;
  654. float max_radius2 = (float)max_radius*max_radius;
  655. int rows, cols, arows, acols;
  656. int astep, *adata;
  657. float* ddata;
  658. CvSeq *nz, *centers;
  659. float idp, dr;
  660. CvSeqReader reader;
  661. edges.reset(cvCreateMat( img->rows, img->cols, CV_8UC1 ));
  662. cvCanny( img, edges, MAX(canny_threshold/2,1), canny_threshold, 3 );
  663. dx.reset(cvCreateMat( img->rows, img->cols, CV_16SC1 ));
  664. dy.reset(cvCreateMat( img->rows, img->cols, CV_16SC1 ));
  665. cvSobel( img, dx, 1, 0, 3 );
  666. cvSobel( img, dy, 0, 1, 3 );
  667. if( dp < 1.f )
  668. dp = 1.f;
  669. idp = 1.f/dp;
  670. accum.reset(cvCreateMat( cvCeil(img->rows*idp)+2, cvCeil(img->cols*idp)+2, CV_32SC1 ));
  671. cvZero(accum);
  672. storage.reset(cvCreateMemStorage());
  673. nz = cvCreateSeq( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint), storage );
  674. centers = cvCreateSeq( CV_32SC1, sizeof(CvSeq), sizeof(int), storage );
  675. rows = img->rows;
  676. cols = img->cols;
  677. arows = accum->rows - 2;
  678. acols = accum->cols - 2;
  679. adata = accum->data.i;
  680. astep = accum->step/sizeof(adata[0]);
  681. // Accumulate circle evidence for each edge pixel
  682. for( y = 0; y < rows; y++ )
  683. {
  684. const uchar* edges_row = edges->data.ptr + y*edges->step;
  685. const short* dx_row = (const short*)(dx->data.ptr + y*dx->step);
  686. const short* dy_row = (const short*)(dy->data.ptr + y*dy->step);
  687. for( x = 0; x < cols; x++ )
  688. {
  689. float vx, vy;
  690. int sx, sy, x0, y0, x1, y1, r;
  691. CvPoint pt;
  692. vx = dx_row[x];
  693. vy = dy_row[x];
  694. if( !edges_row[x] || (vx == 0 && vy == 0) )
  695. continue;
  696. float mag = std::sqrt(vx*vx+vy*vy);
  697. assert( mag >= 1 );
  698. sx = cvRound((vx*idp)*ONE/mag);
  699. sy = cvRound((vy*idp)*ONE/mag);
  700. x0 = cvRound((x*idp)*ONE);
  701. y0 = cvRound((y*idp)*ONE);
  702. // Step from min_radius to max_radius in both directions of the gradient
  703. for(int k1 = 0; k1 < 2; k1++ )
  704. {
  705. x1 = x0 + min_radius * sx;
  706. y1 = y0 + min_radius * sy;
  707. for( r = min_radius; r <= max_radius; x1 += sx, y1 += sy, r++ )
  708. {
  709. int x2 = x1 >> SHIFT, y2 = y1 >> SHIFT;
  710. if( (unsigned)x2 >= (unsigned)acols ||
  711. (unsigned)y2 >= (unsigned)arows )
  712. break;
  713. adata[y2*astep + x2]++;
  714. }
  715. sx = -sx; sy = -sy;
  716. }
  717. pt.x = x; pt.y = y;
  718. cvSeqPush( nz, &pt );
  719. }
  720. }
  721. nz_count = nz->total;
  722. if( !nz_count )
  723. return;
  724. //Find possible circle centers
  725. for( y = 1; y < arows - 1; y++ )
  726. {
  727. for( x = 1; x < acols - 1; x++ )
  728. {
  729. int base = y*(acols+2) + x;
  730. if( adata[base] > acc_threshold &&
  731. adata[base] > adata[base-1] && adata[base] > adata[base+1] &&
  732. adata[base] > adata[base-acols-2] && adata[base] > adata[base+acols+2] )
  733. cvSeqPush(centers, &base);
  734. }
  735. }
  736. center_count = centers->total;
  737. if( !center_count )
  738. return;
  739. sort_buf.resize( MAX(center_count,nz_count) );
  740. cvCvtSeqToArray( centers, &sort_buf[0] );
  741. std::sort(sort_buf.begin(), sort_buf.begin() + center_count, cv::hough_cmp_gt(adata));
  742. cvClearSeq( centers );
  743. cvSeqPushMulti( centers, &sort_buf[0], center_count );
  744. dist_buf.reset(cvCreateMat( 1, nz_count, CV_32FC1 ));
  745. ddata = dist_buf->data.fl;
  746. dr = dp;
  747. min_dist = MAX( min_dist, dp );
  748. min_dist *= min_dist;
  749. // For each found possible center
  750. // Estimate radius and check support
  751. for( i = 0; i < centers->total; i++ )
  752. {
  753. int ofs = *(int*)cvGetSeqElem( centers, i );
  754. y = ofs/(acols+2);
  755. x = ofs - (y)*(acols+2);
  756. //Calculate circle's center in pixels
  757. float cx = (float)((x + 0.5f)*dp), cy = (float)(( y + 0.5f )*dp);
  758. float start_dist, dist_sum;
  759. float r_best = 0;
  760. int max_count = 0;
  761. // Check distance with previously detected circles
  762. for( j = 0; j < circles->total; j++ )
  763. {
  764. float* c = (float*)cvGetSeqElem( circles, j );
  765. if( (c[0] - cx)*(c[0] - cx) + (c[1] - cy)*(c[1] - cy) < min_dist )
  766. break;
  767. }
  768. if( j < circles->total )
  769. continue;
  770. // Estimate best radius
  771. cvStartReadSeq( nz, &reader );
  772. for( j = k = 0; j < nz_count; j++ )
  773. {
  774. CvPoint pt;
  775. float _dx, _dy, _r2;
  776. CV_READ_SEQ_ELEM( pt, reader );
  777. _dx = cx - pt.x; _dy = cy - pt.y;
  778. _r2 = _dx*_dx + _dy*_dy;
  779. if(min_radius2 <= _r2 && _r2 <= max_radius2 )
  780. {
  781. ddata[k] = _r2;
  782. sort_buf[k] = k;
  783. k++;
  784. }
  785. }
  786. int nz_count1 = k, start_idx = nz_count1 - 1;
  787. if( nz_count1 == 0 )
  788. continue;
  789. dist_buf->cols = nz_count1;
  790. cvPow( dist_buf, dist_buf, 0.5 );
  791. std::sort(sort_buf.begin(), sort_buf.begin() + nz_count1, cv::hough_cmp_gt((int*)ddata));
  792. dist_sum = start_dist = ddata[sort_buf[nz_count1-1]];
  793. for( j = nz_count1 - 2; j >= 0; j-- )
  794. {
  795. float d = ddata[sort_buf[j]];
  796. if( d > max_radius )
  797. break;
  798. if( d - start_dist > dr )
  799. {
  800. float r_cur = ddata[sort_buf[(j + start_idx)/2]];
  801. if( (start_idx - j)*r_best >= max_count*r_cur ||
  802. (r_best < FLT_EPSILON && start_idx - j >= max_count) )
  803. {
  804. r_best = r_cur;
  805. max_count = start_idx - j;
  806. }
  807. start_dist = d;
  808. start_idx = j;
  809. dist_sum = 0;
  810. }
  811. dist_sum += d;
  812. }
  813. // Check if the circle has enough support
  814. if( max_count > acc_threshold )
  815. {
  816. float c[3];
  817. c[0] = cx;
  818. c[1] = cy;
  819. c[2] = (float)r_best;
  820. cvSeqPush( circles, c );
  821. if( circles->total > circles_max )
  822. return;
  823. }
  824. }
  825. }
  826. CV_IMPL CvSeq*
  827. cvHoughCircles( CvArr* src_image, void* circle_storage,
  828. int method, double dp, double min_dist,
  829. double param1, double param2,
  830. int min_radius, int max_radius )
  831. {
  832. CvSeq* result = 0;
  833. CvMat stub, *img = (CvMat*)src_image;
  834. CvMat* mat = 0;
  835. CvSeq* circles = 0;
  836. CvSeq circles_header;
  837. CvSeqBlock circles_block;
  838. int circles_max = INT_MAX;
  839. int canny_threshold = cvRound(param1);
  840. int acc_threshold = cvRound(param2);
  841. img = cvGetMat( img, &stub );
  842. if( !CV_IS_MASK_ARR(img))
  843. CV_Error( CV_StsBadArg, "The source image must be 8-bit, single-channel" );
  844. if( !circle_storage )
  845. CV_Error( CV_StsNullPtr, "NULL destination" );
  846. if( dp <= 0 || min_dist <= 0 || canny_threshold <= 0 || acc_threshold <= 0 )
  847. CV_Error( CV_StsOutOfRange, "dp, min_dist, canny_threshold and acc_threshold must be all positive numbers" );
  848. min_radius = MAX( min_radius, 0 );
  849. if( max_radius <= 0 )
  850. max_radius = MAX( img->rows, img->cols );
  851. else if( max_radius <= min_radius )
  852. max_radius = min_radius + 2;
  853. if( CV_IS_STORAGE( circle_storage ))
  854. {
  855. circles = cvCreateSeq( CV_32FC3, sizeof(CvSeq),
  856. sizeof(float)*3, (CvMemStorage*)circle_storage );
  857. }
  858. else if( CV_IS_MAT( circle_storage ))
  859. {
  860. mat = (CvMat*)circle_storage;
  861. if( !CV_IS_MAT_CONT( mat->type ) || (mat->rows != 1 && mat->cols != 1) ||
  862. CV_MAT_TYPE(mat->type) != CV_32FC3 )
  863. CV_Error( CV_StsBadArg,
  864. "The destination matrix should be continuous and have a single row or a single column" );
  865. circles = cvMakeSeqHeaderForArray( CV_32FC3, sizeof(CvSeq), sizeof(float)*3,
  866. mat->data.ptr, mat->rows + mat->cols - 1, &circles_header, &circles_block );
  867. circles_max = circles->total;
  868. cvClearSeq( circles );
  869. }
  870. else
  871. CV_Error( CV_StsBadArg, "Destination is not CvMemStorage* nor CvMat*" );
  872. switch( method )
  873. {
  874. case CV_HOUGH_GRADIENT:
  875. icvHoughCirclesGradient( img, (float)dp, (float)min_dist,
  876. min_radius, max_radius, canny_threshold,
  877. acc_threshold, circles, circles_max );
  878. break;
  879. default:
  880. CV_Error( CV_StsBadArg, "Unrecognized method id" );
  881. }
  882. if( mat )
  883. {
  884. if( mat->cols > mat->rows )
  885. mat->cols = circles->total;
  886. else
  887. mat->rows = circles->total;
  888. }
  889. else
  890. result = circles;
  891. return result;
  892. }
  893. namespace cv
  894. {
  895. const int STORAGE_SIZE = 1 << 12;
  896. static void seqToMat(const CvSeq* seq, OutputArray _arr)
  897. {
  898. if( seq && seq->total > 0 )
  899. {
  900. _arr.create(1, seq->total, seq->flags, -1, true);
  901. Mat arr = _arr.getMat();
  902. cvCvtSeqToArray(seq, arr.data);
  903. }
  904. else
  905. _arr.release();
  906. }
  907. }
  908. void cv::HoughCircles( InputArray _image, OutputArray _circles,
  909. int method, double dp, double min_dist,
  910. double param1, double param2,
  911. int minRadius, int maxRadius )
  912. {
  913. Ptr<CvMemStorage> storage(cvCreateMemStorage(STORAGE_SIZE));
  914. Mat image = _image.getMat();
  915. CvMat c_image = image;
  916. CvSeq* seq = cvHoughCircles( &c_image, storage, method,
  917. dp, min_dist, param1, param2, minRadius, maxRadius );
  918. seqToMat(seq, _circles);
  919. }
  920. /* End of file. */