PageRenderTime 56ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/calib3d/src/calibinit.cpp

https://gitlab.com/gaurav1981/opencv
C++ | 2044 lines | 1525 code | 259 blank | 260 comment | 402 complexity | edf3ce0e84cbf68e921a89c3f6fc84fb 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. // Intel License Agreement
  11. // For Open Source Computer Vision Library
  12. //
  13. // Copyright (C) 2000, Intel Corporation, all rights reserved.
  14. // Third party copyrights are property of their respective owners.
  15. //
  16. // Redistribution and use in source and binary forms, with or without modification,
  17. // are permitted provided that the following conditions are met:
  18. //
  19. // * Redistribution's of source code must retain the above copyright notice,
  20. // this list of conditions and the following disclaimer.
  21. //
  22. // * Redistribution's in binary form must reproduce the above copyright notice,
  23. // this list of conditions and the following disclaimer in the documentation
  24. // and/or other materials provided with the distribution.
  25. //
  26. // * The name of Intel Corporation may not be used to endorse or promote products
  27. // derived from this software without specific prior written permission.
  28. //
  29. // This software is provided by the copyright holders and contributors "as is" and
  30. // any express or implied warranties, including, but not limited to, the implied
  31. // warranties of merchantability and fitness for a particular purpose are disclaimed.
  32. // In no event shall the Intel Corporation or contributors be liable for any direct,
  33. // indirect, incidental, special, exemplary, or consequential damages
  34. // (including, but not limited to, procurement of substitute goods or services;
  35. // loss of use, data, or profits; or business interruption) however caused
  36. // and on any theory of liability, whether in contract, strict liability,
  37. // or tort (including negligence or otherwise) arising in any way out of
  38. // the use of this software, even if advised of the possibility of such damage.
  39. //
  40. //M*/
  41. /************************************************************************************\
  42. This is improved variant of chessboard corner detection algorithm that
  43. uses a graph of connected quads. It is based on the code contributed
  44. by Vladimir Vezhnevets and Philip Gruebele.
  45. Here is the copyright notice from the original Vladimir's code:
  46. ===============================================================
  47. The algorithms developed and implemented by Vezhnevets Vldimir
  48. aka Dead Moroz (vvp@graphics.cs.msu.ru)
  49. See http://graphics.cs.msu.su/en/research/calibration/opencv.html
  50. for detailed information.
  51. Reliability additions and modifications made by Philip Gruebele.
  52. <a href="mailto:pgruebele@cox.net">pgruebele@cox.net</a>
  53. Some further improvements for detection of partially ocluded boards at non-ideal
  54. lighting conditions have been made by Alex Bovyrin and Kurt Kolonige
  55. \************************************************************************************/
  56. #include "precomp.hpp"
  57. #include "opencv2/imgproc/imgproc_c.h"
  58. #include "opencv2/calib3d/calib3d_c.h"
  59. #include "circlesgrid.hpp"
  60. #include <stdarg.h>
  61. //#define ENABLE_TRIM_COL_ROW
  62. //#define DEBUG_CHESSBOARD
  63. #ifdef DEBUG_CHESSBOARD
  64. # include "opencv2/opencv_modules.hpp"
  65. # ifdef HAVE_OPENCV_HIGHGUI
  66. # include "opencv2/highgui.hpp"
  67. # else
  68. # undef DEBUG_CHESSBOARD
  69. # endif
  70. #endif
  71. #ifdef DEBUG_CHESSBOARD
  72. static int PRINTF( const char* fmt, ... )
  73. {
  74. va_list args;
  75. va_start(args, fmt);
  76. return vprintf(fmt, args);
  77. }
  78. #else
  79. static int PRINTF( const char*, ... )
  80. {
  81. return 0;
  82. }
  83. #endif
  84. //=====================================================================================
  85. // Implementation for the enhanced calibration object detection
  86. //=====================================================================================
  87. #define MAX_CONTOUR_APPROX 7
  88. struct CvContourEx
  89. {
  90. CV_CONTOUR_FIELDS()
  91. int counter;
  92. };
  93. //=====================================================================================
  94. /// Corner info structure
  95. /** This structure stores information about the chessboard corner.*/
  96. struct CvCBCorner
  97. {
  98. CvPoint2D32f pt; // Coordinates of the corner
  99. int row; // Board row index
  100. int count; // Number of neighbor corners
  101. struct CvCBCorner* neighbors[4]; // Neighbor corners
  102. float meanDist(int *_n) const
  103. {
  104. float sum = 0;
  105. int n = 0;
  106. for( int i = 0; i < 4; i++ )
  107. {
  108. if( neighbors[i] )
  109. {
  110. float dx = neighbors[i]->pt.x - pt.x;
  111. float dy = neighbors[i]->pt.y - pt.y;
  112. sum += sqrt(dx*dx + dy*dy);
  113. n++;
  114. }
  115. }
  116. if(_n)
  117. *_n = n;
  118. return sum/MAX(n,1);
  119. }
  120. };
  121. //=====================================================================================
  122. /// Quadrangle contour info structure
  123. /** This structure stores information about the chessboard quadrange.*/
  124. struct CvCBQuad
  125. {
  126. int count; // Number of quad neighbors
  127. int group_idx; // quad group ID
  128. int row, col; // row and column of this quad
  129. bool ordered; // true if corners/neighbors are ordered counter-clockwise
  130. float edge_len; // quad edge len, in pix^2
  131. // neighbors and corners are synced, i.e., neighbor 0 shares corner 0
  132. CvCBCorner *corners[4]; // Coordinates of quad corners
  133. struct CvCBQuad *neighbors[4]; // Pointers of quad neighbors
  134. };
  135. //=====================================================================================
  136. //static CvMat* debug_img = 0;
  137. static int icvGenerateQuads( CvCBQuad **quads, CvCBCorner **corners,
  138. CvMemStorage *storage, CvMat *image, int flags );
  139. /*static int
  140. icvGenerateQuadsEx( CvCBQuad **out_quads, CvCBCorner **out_corners,
  141. CvMemStorage *storage, CvMat *image, CvMat *thresh_img, int dilation, int flags );*/
  142. static void icvFindQuadNeighbors( CvCBQuad *quads, int quad_count );
  143. static int icvFindConnectedQuads( CvCBQuad *quads, int quad_count,
  144. CvCBQuad **quad_group, int group_idx,
  145. CvMemStorage* storage );
  146. static int icvCheckQuadGroup( CvCBQuad **quad_group, int count,
  147. CvCBCorner **out_corners, CvSize pattern_size );
  148. static int icvCleanFoundConnectedQuads( int quad_count,
  149. CvCBQuad **quads, CvSize pattern_size );
  150. static int icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads,
  151. int *all_count, CvCBQuad **all_quads, CvCBCorner **corners,
  152. CvSize pattern_size, CvMemStorage* storage );
  153. static void icvOrderQuad(CvCBQuad *quad, CvCBCorner *corner, int common);
  154. #ifdef ENABLE_TRIM_COL_ROW
  155. static int icvTrimCol(CvCBQuad **quads, int count, int col, int dir);
  156. static int icvTrimRow(CvCBQuad **quads, int count, int row, int dir);
  157. #endif
  158. static int icvAddOuterQuad(CvCBQuad *quad, CvCBQuad **quads, int quad_count,
  159. CvCBQuad **all_quads, int all_count, CvCBCorner **corners);
  160. static void icvRemoveQuadFromGroup(CvCBQuad **quads, int count, CvCBQuad *q0);
  161. static int icvCheckBoardMonotony( CvPoint2D32f* corners, CvSize pattern_size );
  162. #if 0
  163. static void
  164. icvCalcAffineTranf2D32f(CvPoint2D32f* pts1, CvPoint2D32f* pts2, int count, CvMat* affine_trans)
  165. {
  166. int i, j;
  167. int real_count = 0;
  168. for( j = 0; j < count; j++ )
  169. {
  170. if( pts1[j].x >= 0 ) real_count++;
  171. }
  172. if(real_count < 3) return;
  173. cv::Ptr<CvMat> xy = cvCreateMat( 2*real_count, 6, CV_32FC1 );
  174. cv::Ptr<CvMat> uv = cvCreateMat( 2*real_count, 1, CV_32FC1 );
  175. //estimate affine transfromation
  176. for( i = 0, j = 0; j < count; j++ )
  177. {
  178. if( pts1[j].x >= 0 )
  179. {
  180. CV_MAT_ELEM( *xy, float, i*2+1, 2 ) = CV_MAT_ELEM( *xy, float, i*2, 0 ) = pts2[j].x;
  181. CV_MAT_ELEM( *xy, float, i*2+1, 3 ) = CV_MAT_ELEM( *xy, float, i*2, 1 ) = pts2[j].y;
  182. CV_MAT_ELEM( *xy, float, i*2, 2 ) = CV_MAT_ELEM( *xy, float, i*2, 3 ) = CV_MAT_ELEM( *xy, float, i*2, 5 ) = \
  183. CV_MAT_ELEM( *xy, float, i*2+1, 0 ) = CV_MAT_ELEM( *xy, float, i*2+1, 1 ) = CV_MAT_ELEM( *xy, float, i*2+1, 4 ) = 0;
  184. CV_MAT_ELEM( *xy, float, i*2, 4 ) = CV_MAT_ELEM( *xy, float, i*2+1, 5 ) = 1;
  185. CV_MAT_ELEM( *uv, float, i*2, 0 ) = pts1[j].x;
  186. CV_MAT_ELEM( *uv, float, i*2+1, 0 ) = pts1[j].y;
  187. i++;
  188. }
  189. }
  190. cvSolve( xy, uv, affine_trans, CV_SVD );
  191. }
  192. #endif
  193. CV_IMPL
  194. int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
  195. CvPoint2D32f* out_corners, int* out_corner_count,
  196. int flags )
  197. {
  198. int found = 0;
  199. CvCBQuad *quads = 0, **quad_group = 0;
  200. CvCBCorner *corners = 0, **corner_group = 0;
  201. try
  202. {
  203. int k = 0;
  204. const int min_dilations = 0;
  205. const int max_dilations = 7;
  206. cv::Ptr<CvMat> norm_img, thresh_img;
  207. #ifdef DEBUG_CHESSBOARD
  208. cv::Ptr<IplImage> dbg_img;
  209. cv::Ptr<IplImage> dbg1_img;
  210. cv::Ptr<IplImage> dbg2_img;
  211. #endif
  212. cv::Ptr<CvMemStorage> storage;
  213. CvMat stub, *img = (CvMat*)arr;
  214. int expected_corners_num = (pattern_size.width/2+1)*(pattern_size.height/2+1);
  215. int prev_sqr_size = 0;
  216. if( out_corner_count )
  217. *out_corner_count = 0;
  218. IplImage _img;
  219. int check_chessboard_result;
  220. int quad_count = 0, group_idx = 0, dilations = 0;
  221. img = cvGetMat( img, &stub );
  222. //debug_img = img;
  223. if( CV_MAT_DEPTH( img->type ) != CV_8U || CV_MAT_CN( img->type ) == 2 )
  224. CV_Error( CV_StsUnsupportedFormat, "Only 8-bit grayscale or color images are supported" );
  225. if( pattern_size.width <= 2 || pattern_size.height <= 2 )
  226. CV_Error( CV_StsOutOfRange, "Both width and height of the pattern should have bigger than 2" );
  227. if( !out_corners )
  228. CV_Error( CV_StsNullPtr, "Null pointer to corners" );
  229. storage.reset(cvCreateMemStorage(0));
  230. thresh_img.reset(cvCreateMat( img->rows, img->cols, CV_8UC1 ));
  231. #ifdef DEBUG_CHESSBOARD
  232. dbg_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3 );
  233. dbg1_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3 );
  234. dbg2_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3 );
  235. #endif
  236. if( CV_MAT_CN(img->type) != 1 || (flags & CV_CALIB_CB_NORMALIZE_IMAGE) )
  237. {
  238. // equalize the input image histogram -
  239. // that should make the contrast between "black" and "white" areas big enough
  240. norm_img.reset(cvCreateMat( img->rows, img->cols, CV_8UC1 ));
  241. if( CV_MAT_CN(img->type) != 1 )
  242. {
  243. cvCvtColor( img, norm_img, CV_BGR2GRAY );
  244. img = norm_img;
  245. }
  246. if( flags & CV_CALIB_CB_NORMALIZE_IMAGE )
  247. {
  248. cvEqualizeHist( img, norm_img );
  249. img = norm_img;
  250. }
  251. }
  252. if( flags & CV_CALIB_CB_FAST_CHECK)
  253. {
  254. cvGetImage(img, &_img);
  255. check_chessboard_result = cvCheckChessboard(&_img, pattern_size);
  256. if(check_chessboard_result <= 0)
  257. {
  258. return 0;
  259. }
  260. }
  261. // Try our standard "1" dilation, but if the pattern is not found, iterate the whole procedure with higher dilations.
  262. // This is necessary because some squares simply do not separate properly with a single dilation. However,
  263. // we want to use the minimum number of dilations possible since dilations cause the squares to become smaller,
  264. // making it difficult to detect smaller squares.
  265. for( k = 0; k < 6; k++ )
  266. {
  267. for( dilations = min_dilations; dilations <= max_dilations; dilations++ )
  268. {
  269. if (found)
  270. break; // already found it
  271. cvFree(&quads);
  272. cvFree(&corners);
  273. /*if( k == 1 )
  274. {
  275. //Pattern was not found using binarization
  276. // Run multi-level quads extraction
  277. // In case one-level binarization did not give enough number of quads
  278. CV_CALL( quad_count = icvGenerateQuadsEx( &quads, &corners, storage, img, thresh_img, dilations, flags ));
  279. PRINTF("EX quad count: %d/%d\n", quad_count, expected_corners_num);
  280. }
  281. else*/
  282. {
  283. // convert the input grayscale image to binary (black-n-white)
  284. if( flags & CV_CALIB_CB_ADAPTIVE_THRESH )
  285. {
  286. int block_size = cvRound(prev_sqr_size == 0 ?
  287. MIN(img->cols,img->rows)*(k%2 == 0 ? 0.2 : 0.1): prev_sqr_size*2)|1;
  288. // convert to binary
  289. cvAdaptiveThreshold( img, thresh_img, 255,
  290. CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, block_size, (k/2)*5 );
  291. if (dilations > 0)
  292. cvDilate( thresh_img, thresh_img, 0, dilations-1 );
  293. }
  294. else
  295. {
  296. // Make dilation before the thresholding.
  297. // It splits chessboard corners
  298. //cvDilate( img, thresh_img, 0, 1 );
  299. // empiric threshold level
  300. double mean = cvAvg( img ).val[0];
  301. int thresh_level = cvRound( mean - 10 );
  302. thresh_level = MAX( thresh_level, 10 );
  303. cvThreshold( img, thresh_img, thresh_level, 255, CV_THRESH_BINARY );
  304. cvDilate( thresh_img, thresh_img, 0, dilations );
  305. }
  306. #ifdef DEBUG_CHESSBOARD
  307. cvCvtColor(thresh_img,dbg_img,CV_GRAY2BGR);
  308. #endif
  309. // So we can find rectangles that go to the edge, we draw a white line around the image edge.
  310. // Otherwise FindContours will miss those clipped rectangle contours.
  311. // The border color will be the image mean, because otherwise we risk screwing up filters like cvSmooth()...
  312. cvRectangle( thresh_img, cvPoint(0,0), cvPoint(thresh_img->cols-1,
  313. thresh_img->rows-1), CV_RGB(255,255,255), 3, 8);
  314. quad_count = icvGenerateQuads( &quads, &corners, storage, thresh_img, flags );
  315. PRINTF("Quad count: %d/%d\n", quad_count, expected_corners_num);
  316. }
  317. #ifdef DEBUG_CHESSBOARD
  318. cvCopy(dbg_img, dbg1_img);
  319. cvNamedWindow("all_quads", 1);
  320. // copy corners to temp array
  321. for(int i = 0; i < quad_count; i++ )
  322. {
  323. for (int k=0; k<4; k++)
  324. {
  325. CvPoint2D32f pt1, pt2;
  326. CvScalar color = CV_RGB(30,255,30);
  327. pt1 = quads[i].corners[k]->pt;
  328. pt2 = quads[i].corners[(k+1)%4]->pt;
  329. pt2.x = (pt1.x + pt2.x)/2;
  330. pt2.y = (pt1.y + pt2.y)/2;
  331. if (k>0)
  332. color = CV_RGB(200,200,0);
  333. cvLine( dbg1_img, cvPointFrom32f(pt1), cvPointFrom32f(pt2), color, 3, 8);
  334. }
  335. }
  336. cvShowImage("all_quads", (IplImage*)dbg1_img);
  337. cvWaitKey();
  338. #endif
  339. if( quad_count <= 0 )
  340. continue;
  341. // Find quad's neighbors
  342. icvFindQuadNeighbors( quads, quad_count );
  343. // allocate extra for adding in icvOrderFoundQuads
  344. cvFree(&quad_group);
  345. cvFree(&corner_group);
  346. quad_group = (CvCBQuad**)cvAlloc( sizeof(quad_group[0]) * (quad_count+quad_count / 2));
  347. corner_group = (CvCBCorner**)cvAlloc( sizeof(corner_group[0]) * (quad_count+quad_count / 2)*4 );
  348. for( group_idx = 0; ; group_idx++ )
  349. {
  350. int count = 0;
  351. count = icvFindConnectedQuads( quads, quad_count, quad_group, group_idx, storage );
  352. int icount = count;
  353. if( count == 0 )
  354. break;
  355. // order the quad corners globally
  356. // maybe delete or add some
  357. PRINTF("Starting ordering of inner quads\n");
  358. count = icvOrderFoundConnectedQuads(count, quad_group, &quad_count, &quads, &corners,
  359. pattern_size, storage );
  360. PRINTF("Orig count: %d After ordering: %d\n", icount, count);
  361. #ifdef DEBUG_CHESSBOARD
  362. cvCopy(dbg_img,dbg2_img);
  363. cvNamedWindow("connected_group", 1);
  364. // copy corners to temp array
  365. for(int i = 0; i < quad_count; i++ )
  366. {
  367. if (quads[i].group_idx == group_idx)
  368. for (int k=0; k<4; k++)
  369. {
  370. CvPoint2D32f pt1, pt2;
  371. CvScalar color = CV_RGB(30,255,30);
  372. if (quads[i].ordered)
  373. color = CV_RGB(255,30,30);
  374. pt1 = quads[i].corners[k]->pt;
  375. pt2 = quads[i].corners[(k+1)%4]->pt;
  376. pt2.x = (pt1.x + pt2.x)/2;
  377. pt2.y = (pt1.y + pt2.y)/2;
  378. if (k>0)
  379. color = CV_RGB(200,200,0);
  380. cvLine( dbg2_img, cvPointFrom32f(pt1), cvPointFrom32f(pt2), color, 3, 8);
  381. }
  382. }
  383. cvShowImage("connected_group", (IplImage*)dbg2_img);
  384. cvWaitKey();
  385. #endif
  386. if (count == 0)
  387. continue; // haven't found inner quads
  388. // If count is more than it should be, this will remove those quads
  389. // which cause maximum deviation from a nice square pattern.
  390. count = icvCleanFoundConnectedQuads( count, quad_group, pattern_size );
  391. PRINTF("Connected group: %d orig count: %d cleaned: %d\n", group_idx, icount, count);
  392. count = icvCheckQuadGroup( quad_group, count, corner_group, pattern_size );
  393. PRINTF("Connected group: %d count: %d cleaned: %d\n", group_idx, icount, count);
  394. {
  395. int n = count > 0 ? pattern_size.width * pattern_size.height : -count;
  396. n = MIN( n, pattern_size.width * pattern_size.height );
  397. float sum_dist = 0;
  398. int total = 0;
  399. for(int i = 0; i < n; i++ )
  400. {
  401. int ni = 0;
  402. float avgi = corner_group[i]->meanDist(&ni);
  403. sum_dist += avgi*ni;
  404. total += ni;
  405. }
  406. prev_sqr_size = cvRound(sum_dist/MAX(total, 1));
  407. if( count > 0 || (out_corner_count && -count > *out_corner_count) )
  408. {
  409. // copy corners to output array
  410. for(int i = 0; i < n; i++ )
  411. out_corners[i] = corner_group[i]->pt;
  412. if( out_corner_count )
  413. *out_corner_count = n;
  414. if( count == pattern_size.width*pattern_size.height &&
  415. icvCheckBoardMonotony( out_corners, pattern_size ))
  416. {
  417. found = 1;
  418. break;
  419. }
  420. }
  421. }
  422. }
  423. }//dilations
  424. }//
  425. if( found )
  426. found = icvCheckBoardMonotony( out_corners, pattern_size );
  427. // check that none of the found corners is too close to the image boundary
  428. if( found )
  429. {
  430. const int BORDER = 8;
  431. for( k = 0; k < pattern_size.width*pattern_size.height; k++ )
  432. {
  433. if( out_corners[k].x <= BORDER || out_corners[k].x > img->cols - BORDER ||
  434. out_corners[k].y <= BORDER || out_corners[k].y > img->rows - BORDER )
  435. break;
  436. }
  437. found = k == pattern_size.width*pattern_size.height;
  438. }
  439. if( found && pattern_size.height % 2 == 0 && pattern_size.width % 2 == 0 )
  440. {
  441. int last_row = (pattern_size.height-1)*pattern_size.width;
  442. double dy0 = out_corners[last_row].y - out_corners[0].y;
  443. if( dy0 < 0 )
  444. {
  445. int n = pattern_size.width*pattern_size.height;
  446. for(int i = 0; i < n/2; i++ )
  447. {
  448. CvPoint2D32f temp;
  449. CV_SWAP(out_corners[i], out_corners[n-i-1], temp);
  450. }
  451. }
  452. }
  453. if( found )
  454. {
  455. cv::Ptr<CvMat> gray;
  456. if( CV_MAT_CN(img->type) != 1 )
  457. {
  458. gray.reset(cvCreateMat(img->rows, img->cols, CV_8UC1));
  459. cvCvtColor(img, gray, CV_BGR2GRAY);
  460. }
  461. else
  462. {
  463. gray.reset(cvCloneMat(img));
  464. }
  465. int wsize = 2;
  466. cvFindCornerSubPix( gray, out_corners, pattern_size.width*pattern_size.height,
  467. cvSize(wsize, wsize), cvSize(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 15, 0.1));
  468. }
  469. }
  470. catch(...)
  471. {
  472. cvFree(&quads);
  473. cvFree(&corners);
  474. cvFree(&quad_group);
  475. cvFree(&corner_group);
  476. throw;
  477. }
  478. cvFree(&quads);
  479. cvFree(&corners);
  480. cvFree(&quad_group);
  481. cvFree(&corner_group);
  482. return found;
  483. }
  484. //
  485. // Checks that each board row and column is pretty much monotonous curve:
  486. // It analyzes each row and each column of the chessboard as following:
  487. // for each corner c lying between end points in the same row/column it checks that
  488. // the point projection to the line segment (a,b) is lying between projections
  489. // of the neighbor corners in the same row/column.
  490. //
  491. // This function has been created as temporary workaround for the bug in current implementation
  492. // of cvFindChessboardCornes that produces absolutely unordered sets of corners.
  493. //
  494. static int
  495. icvCheckBoardMonotony( CvPoint2D32f* corners, CvSize pattern_size )
  496. {
  497. int i, j, k;
  498. for( k = 0; k < 2; k++ )
  499. {
  500. for( i = 0; i < (k == 0 ? pattern_size.height : pattern_size.width); i++ )
  501. {
  502. CvPoint2D32f a = k == 0 ? corners[i*pattern_size.width] : corners[i];
  503. CvPoint2D32f b = k == 0 ? corners[(i+1)*pattern_size.width-1] :
  504. corners[(pattern_size.height-1)*pattern_size.width + i];
  505. float prevt = 0, dx0 = b.x - a.x, dy0 = b.y - a.y;
  506. if( fabs(dx0) + fabs(dy0) < FLT_EPSILON )
  507. return 0;
  508. for( j = 1; j < (k == 0 ? pattern_size.width : pattern_size.height) - 1; j++ )
  509. {
  510. CvPoint2D32f c = k == 0 ? corners[i*pattern_size.width + j] :
  511. corners[j*pattern_size.width + i];
  512. float t = ((c.x - a.x)*dx0 + (c.y - a.y)*dy0)/(dx0*dx0 + dy0*dy0);
  513. if( t < prevt || t > 1 )
  514. return 0;
  515. prevt = t;
  516. }
  517. }
  518. }
  519. return 1;
  520. }
  521. //
  522. // order a group of connected quads
  523. // order of corners:
  524. // 0 is top left
  525. // clockwise from there
  526. // note: "top left" is nominal, depends on initial ordering of starting quad
  527. // but all other quads are ordered consistently
  528. //
  529. // can change the number of quads in the group
  530. // can add quads, so we need to have quad/corner arrays passed in
  531. //
  532. static int
  533. icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads,
  534. int *all_count, CvCBQuad **all_quads, CvCBCorner **corners,
  535. CvSize pattern_size, CvMemStorage* storage )
  536. {
  537. cv::Ptr<CvMemStorage> temp_storage(cvCreateChildMemStorage( storage ));
  538. CvSeq* stack = cvCreateSeq( 0, sizeof(*stack), sizeof(void*), temp_storage );
  539. // first find an interior quad
  540. CvCBQuad *start = NULL;
  541. for (int i=0; i<quad_count; i++)
  542. {
  543. if (quads[i]->count == 4)
  544. {
  545. start = quads[i];
  546. break;
  547. }
  548. }
  549. if (start == NULL)
  550. return 0; // no 4-connected quad
  551. // start with first one, assign rows/cols
  552. int row_min = 0, col_min = 0, row_max=0, col_max = 0;
  553. std::map<int, int> col_hist;
  554. std::map<int, int> row_hist;
  555. cvSeqPush(stack, &start);
  556. start->row = 0;
  557. start->col = 0;
  558. start->ordered = true;
  559. // Recursively order the quads so that all position numbers (e.g.,
  560. // 0,1,2,3) are in the at the same relative corner (e.g., lower right).
  561. while( stack->total )
  562. {
  563. CvCBQuad* q;
  564. cvSeqPop( stack, &q );
  565. int col = q->col;
  566. int row = q->row;
  567. col_hist[col]++;
  568. row_hist[row]++;
  569. // check min/max
  570. if (row > row_max) row_max = row;
  571. if (row < row_min) row_min = row;
  572. if (col > col_max) col_max = col;
  573. if (col < col_min) col_min = col;
  574. for(int i = 0; i < 4; i++ )
  575. {
  576. CvCBQuad *neighbor = q->neighbors[i];
  577. switch(i) // adjust col, row for this quad
  578. { // start at top left, go clockwise
  579. case 0:
  580. row--; col--; break;
  581. case 1:
  582. col += 2; break;
  583. case 2:
  584. row += 2; break;
  585. case 3:
  586. col -= 2; break;
  587. }
  588. // just do inside quads
  589. if (neighbor && neighbor->ordered == false && neighbor->count == 4)
  590. {
  591. PRINTF("col: %d row: %d\n", col, row);
  592. icvOrderQuad(neighbor, q->corners[i], (i+2)%4); // set in order
  593. neighbor->ordered = true;
  594. neighbor->row = row;
  595. neighbor->col = col;
  596. cvSeqPush( stack, &neighbor );
  597. }
  598. }
  599. }
  600. for (int i=col_min; i<=col_max; i++)
  601. PRINTF("HIST[%d] = %d\n", i, col_hist[i]);
  602. // analyze inner quad structure
  603. int w = pattern_size.width - 1;
  604. int h = pattern_size.height - 1;
  605. int drow = row_max - row_min + 1;
  606. int dcol = col_max - col_min + 1;
  607. // normalize pattern and found quad indices
  608. if ((w > h && dcol < drow) ||
  609. (w < h && drow < dcol))
  610. {
  611. h = pattern_size.width - 1;
  612. w = pattern_size.height - 1;
  613. }
  614. PRINTF("Size: %dx%d Pattern: %dx%d\n", dcol, drow, w, h);
  615. // check if there are enough inner quads
  616. if (dcol < w || drow < h) // found enough inner quads?
  617. {
  618. PRINTF("Too few inner quad rows/cols\n");
  619. return 0; // no, return
  620. }
  621. #ifdef ENABLE_TRIM_COL_ROW
  622. // too many columns, not very common
  623. if (dcol == w+1) // too many, trim
  624. {
  625. PRINTF("Trimming cols\n");
  626. if (col_hist[col_max] > col_hist[col_min])
  627. {
  628. PRINTF("Trimming left col\n");
  629. quad_count = icvTrimCol(quads,quad_count,col_min,-1);
  630. }
  631. else
  632. {
  633. PRINTF("Trimming right col\n");
  634. quad_count = icvTrimCol(quads,quad_count,col_max,+1);
  635. }
  636. }
  637. // too many rows, not very common
  638. if (drow == h+1) // too many, trim
  639. {
  640. PRINTF("Trimming rows\n");
  641. if (row_hist[row_max] > row_hist[row_min])
  642. {
  643. PRINTF("Trimming top row\n");
  644. quad_count = icvTrimRow(quads,quad_count,row_min,-1);
  645. }
  646. else
  647. {
  648. PRINTF("Trimming bottom row\n");
  649. quad_count = icvTrimRow(quads,quad_count,row_max,+1);
  650. }
  651. }
  652. #endif
  653. // check edges of inner quads
  654. // if there is an outer quad missing, fill it in
  655. // first order all inner quads
  656. int found = 0;
  657. for (int i=0; i<quad_count; i++)
  658. {
  659. if (quads[i]->count == 4)
  660. { // ok, look at neighbors
  661. int col = quads[i]->col;
  662. int row = quads[i]->row;
  663. for (int j=0; j<4; j++)
  664. {
  665. switch(j) // adjust col, row for this quad
  666. { // start at top left, go clockwise
  667. case 0:
  668. row--; col--; break;
  669. case 1:
  670. col += 2; break;
  671. case 2:
  672. row += 2; break;
  673. case 3:
  674. col -= 2; break;
  675. }
  676. CvCBQuad *neighbor = quads[i]->neighbors[j];
  677. if (neighbor && !neighbor->ordered && // is it an inner quad?
  678. col <= col_max && col >= col_min &&
  679. row <= row_max && row >= row_min)
  680. {
  681. // if so, set in order
  682. PRINTF("Adding inner: col: %d row: %d\n", col, row);
  683. found++;
  684. icvOrderQuad(neighbor, quads[i]->corners[j], (j+2)%4);
  685. neighbor->ordered = true;
  686. neighbor->row = row;
  687. neighbor->col = col;
  688. }
  689. }
  690. }
  691. }
  692. // if we have found inner quads, add corresponding outer quads,
  693. // which are missing
  694. if (found > 0)
  695. {
  696. PRINTF("Found %d inner quads not connected to outer quads, repairing\n", found);
  697. for (int i=0; i<quad_count; i++)
  698. {
  699. if (quads[i]->count < 4 && quads[i]->ordered)
  700. {
  701. int added = icvAddOuterQuad(quads[i],quads,quad_count,all_quads,*all_count,corners);
  702. *all_count += added;
  703. quad_count += added;
  704. }
  705. }
  706. }
  707. // final trimming of outer quads
  708. if (dcol == w && drow == h) // found correct inner quads
  709. {
  710. PRINTF("Inner bounds ok, check outer quads\n");
  711. int rcount = quad_count;
  712. for (int i=quad_count-1; i>=0; i--) // eliminate any quad not connected to
  713. // an ordered quad
  714. {
  715. if (quads[i]->ordered == false)
  716. {
  717. bool outer = false;
  718. for (int j=0; j<4; j++) // any neighbors that are ordered?
  719. {
  720. if (quads[i]->neighbors[j] && quads[i]->neighbors[j]->ordered)
  721. outer = true;
  722. }
  723. if (!outer) // not an outer quad, eliminate
  724. {
  725. PRINTF("Removing quad %d\n", i);
  726. icvRemoveQuadFromGroup(quads,rcount,quads[i]);
  727. rcount--;
  728. }
  729. }
  730. }
  731. return rcount;
  732. }
  733. return 0;
  734. }
  735. // add an outer quad
  736. // looks for the neighbor of <quad> that isn't present,
  737. // tries to add it in.
  738. // <quad> is ordered
  739. static int
  740. icvAddOuterQuad( CvCBQuad *quad, CvCBQuad **quads, int quad_count,
  741. CvCBQuad **all_quads, int all_count, CvCBCorner **corners )
  742. {
  743. int added = 0;
  744. for (int i=0; i<4; i++) // find no-neighbor corners
  745. {
  746. if (!quad->neighbors[i]) // ok, create and add neighbor
  747. {
  748. int j = (i+2)%4;
  749. PRINTF("Adding quad as neighbor 2\n");
  750. CvCBQuad *q = &(*all_quads)[all_count];
  751. memset( q, 0, sizeof(*q) );
  752. added++;
  753. quads[quad_count] = q;
  754. quad_count++;
  755. // set neighbor and group id
  756. quad->neighbors[i] = q;
  757. quad->count += 1;
  758. q->neighbors[j] = quad;
  759. q->group_idx = quad->group_idx;
  760. q->count = 1; // number of neighbors
  761. q->ordered = false;
  762. q->edge_len = quad->edge_len;
  763. // make corners of new quad
  764. // same as neighbor quad, but offset
  765. CvPoint2D32f pt = quad->corners[i]->pt;
  766. CvCBCorner* corner;
  767. float dx = pt.x - quad->corners[j]->pt.x;
  768. float dy = pt.y - quad->corners[j]->pt.y;
  769. for (int k=0; k<4; k++)
  770. {
  771. corner = &(*corners)[all_count*4+k];
  772. pt = quad->corners[k]->pt;
  773. memset( corner, 0, sizeof(*corner) );
  774. corner->pt = pt;
  775. q->corners[k] = corner;
  776. corner->pt.x += dx;
  777. corner->pt.y += dy;
  778. }
  779. // have to set exact corner
  780. q->corners[j] = quad->corners[i];
  781. // now find other neighbor and add it, if possible
  782. if (quad->neighbors[(i+3)%4] &&
  783. quad->neighbors[(i+3)%4]->ordered &&
  784. quad->neighbors[(i+3)%4]->neighbors[i] &&
  785. quad->neighbors[(i+3)%4]->neighbors[i]->ordered )
  786. {
  787. CvCBQuad *qn = quad->neighbors[(i+3)%4]->neighbors[i];
  788. q->count = 2;
  789. q->neighbors[(j+1)%4] = qn;
  790. qn->neighbors[(i+1)%4] = q;
  791. qn->count += 1;
  792. // have to set exact corner
  793. q->corners[(j+1)%4] = qn->corners[(i+1)%4];
  794. }
  795. all_count++;
  796. }
  797. }
  798. return added;
  799. }
  800. // trimming routines
  801. #ifdef ENABLE_TRIM_COL_ROW
  802. static int
  803. icvTrimCol(CvCBQuad **quads, int count, int col, int dir)
  804. {
  805. int rcount = count;
  806. // find the right quad(s)
  807. for (int i=0; i<count; i++)
  808. {
  809. #ifdef DEBUG_CHESSBOARD
  810. if (quads[i]->ordered)
  811. PRINTF("index: %d cur: %d\n", col, quads[i]->col);
  812. #endif
  813. if (quads[i]->ordered && quads[i]->col == col)
  814. {
  815. if (dir == 1)
  816. {
  817. if (quads[i]->neighbors[1])
  818. {
  819. icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[1]);
  820. rcount--;
  821. }
  822. if (quads[i]->neighbors[2])
  823. {
  824. icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[2]);
  825. rcount--;
  826. }
  827. }
  828. else
  829. {
  830. if (quads[i]->neighbors[0])
  831. {
  832. icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[0]);
  833. rcount--;
  834. }
  835. if (quads[i]->neighbors[3])
  836. {
  837. icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[3]);
  838. rcount--;
  839. }
  840. }
  841. }
  842. }
  843. return rcount;
  844. }
  845. static int
  846. icvTrimRow(CvCBQuad **quads, int count, int row, int dir)
  847. {
  848. int i, rcount = count;
  849. // find the right quad(s)
  850. for (i=0; i<count; i++)
  851. {
  852. #ifdef DEBUG_CHESSBOARD
  853. if (quads[i]->ordered)
  854. PRINTF("index: %d cur: %d\n", row, quads[i]->row);
  855. #endif
  856. if (quads[i]->ordered && quads[i]->row == row)
  857. {
  858. if (dir == 1) // remove from bottom
  859. {
  860. if (quads[i]->neighbors[2])
  861. {
  862. icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[2]);
  863. rcount--;
  864. }
  865. if (quads[i]->neighbors[3])
  866. {
  867. icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[3]);
  868. rcount--;
  869. }
  870. }
  871. else // remove from top
  872. {
  873. if (quads[i]->neighbors[0])
  874. {
  875. icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[0]);
  876. rcount--;
  877. }
  878. if (quads[i]->neighbors[1])
  879. {
  880. icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[1]);
  881. rcount--;
  882. }
  883. }
  884. }
  885. }
  886. return rcount;
  887. }
  888. #endif
  889. //
  890. // remove quad from quad group
  891. //
  892. static void
  893. icvRemoveQuadFromGroup(CvCBQuad **quads, int count, CvCBQuad *q0)
  894. {
  895. int i, j;
  896. // remove any references to this quad as a neighbor
  897. for(i = 0; i < count; i++ )
  898. {
  899. CvCBQuad *q = quads[i];
  900. for(j = 0; j < 4; j++ )
  901. {
  902. if( q->neighbors[j] == q0 )
  903. {
  904. q->neighbors[j] = 0;
  905. q->count--;
  906. for(int k = 0; k < 4; k++ )
  907. if( q0->neighbors[k] == q )
  908. {
  909. q0->neighbors[k] = 0;
  910. q0->count--;
  911. break;
  912. }
  913. break;
  914. }
  915. }
  916. }
  917. // remove the quad
  918. for(i = 0; i < count; i++ )
  919. {
  920. CvCBQuad *q = quads[i];
  921. if (q == q0)
  922. {
  923. quads[i] = quads[count-1];
  924. break;
  925. }
  926. }
  927. }
  928. //
  929. // put quad into correct order, where <corner> has value <common>
  930. //
  931. static void
  932. icvOrderQuad(CvCBQuad *quad, CvCBCorner *corner, int common)
  933. {
  934. // find the corner
  935. int tc;
  936. for (tc=0; tc<4; tc++)
  937. if (quad->corners[tc]->pt.x == corner->pt.x &&
  938. quad->corners[tc]->pt.y == corner->pt.y)
  939. break;
  940. // set corner order
  941. // shift
  942. while (tc != common)
  943. {
  944. // shift by one
  945. CvCBCorner *tempc;
  946. CvCBQuad *tempq;
  947. tempc = quad->corners[3];
  948. tempq = quad->neighbors[3];
  949. for (int i=3; i>0; i--)
  950. {
  951. quad->corners[i] = quad->corners[i-1];
  952. quad->neighbors[i] = quad->neighbors[i-1];
  953. }
  954. quad->corners[0] = tempc;
  955. quad->neighbors[0] = tempq;
  956. tc++;
  957. tc = tc%4;
  958. }
  959. }
  960. // if we found too many connect quads, remove those which probably do not belong.
  961. static int
  962. icvCleanFoundConnectedQuads( int quad_count, CvCBQuad **quad_group, CvSize pattern_size )
  963. {
  964. CvPoint2D32f center;
  965. int i, j, k;
  966. // number of quads this pattern should contain
  967. int count = ((pattern_size.width + 1)*(pattern_size.height + 1) + 1)/2;
  968. // if we have more quadrangles than we should,
  969. // try to eliminate duplicates or ones which don't belong to the pattern rectangle...
  970. if( quad_count <= count )
  971. return quad_count;
  972. // create an array of quadrangle centers
  973. cv::AutoBuffer<CvPoint2D32f> centers( quad_count );
  974. cv::Ptr<CvMemStorage> temp_storage(cvCreateMemStorage(0));
  975. for( i = 0; i < quad_count; i++ )
  976. {
  977. CvPoint2D32f ci;
  978. CvCBQuad* q = quad_group[i];
  979. for( j = 0; j < 4; j++ )
  980. {
  981. CvPoint2D32f pt = q->corners[j]->pt;
  982. ci.x += pt.x;
  983. ci.y += pt.y;
  984. }
  985. ci.x *= 0.25f;
  986. ci.y *= 0.25f;
  987. centers[i] = ci;
  988. center.x += ci.x;
  989. center.y += ci.y;
  990. }
  991. center.x /= quad_count;
  992. center.y /= quad_count;
  993. // If we still have more quadrangles than we should,
  994. // we try to eliminate bad ones based on minimizing the bounding box.
  995. // We iteratively remove the point which reduces the size of
  996. // the bounding box of the blobs the most
  997. // (since we want the rectangle to be as small as possible)
  998. // remove the quadrange that causes the biggest reduction
  999. // in pattern size until we have the correct number
  1000. for( ; quad_count > count; quad_count-- )
  1001. {
  1002. double min_box_area = DBL_MAX;
  1003. int skip, min_box_area_index = -1;
  1004. CvCBQuad *q0, *q;
  1005. // For each point, calculate box area without that point
  1006. for( skip = 0; skip < quad_count; skip++ )
  1007. {
  1008. // get bounding rectangle
  1009. CvPoint2D32f temp = centers[skip]; // temporarily make index 'skip' the same as
  1010. centers[skip] = center; // pattern center (so it is not counted for convex hull)
  1011. CvMat pointMat = cvMat(1, quad_count, CV_32FC2, centers);
  1012. CvSeq *hull = cvConvexHull2( &pointMat, temp_storage, CV_CLOCKWISE, 1 );
  1013. centers[skip] = temp;
  1014. double hull_area = fabs(cvContourArea(hull, CV_WHOLE_SEQ));
  1015. // remember smallest box area
  1016. if( hull_area < min_box_area )
  1017. {
  1018. min_box_area = hull_area;
  1019. min_box_area_index = skip;
  1020. }
  1021. cvClearMemStorage( temp_storage );
  1022. }
  1023. q0 = quad_group[min_box_area_index];
  1024. // remove any references to this quad as a neighbor
  1025. for( i = 0; i < quad_count; i++ )
  1026. {
  1027. q = quad_group[i];
  1028. for( j = 0; j < 4; j++ )
  1029. {
  1030. if( q->neighbors[j] == q0 )
  1031. {
  1032. q->neighbors[j] = 0;
  1033. q->count--;
  1034. for( k = 0; k < 4; k++ )
  1035. if( q0->neighbors[k] == q )
  1036. {
  1037. q0->neighbors[k] = 0;
  1038. q0->count--;
  1039. break;
  1040. }
  1041. break;
  1042. }
  1043. }
  1044. }
  1045. // remove the quad
  1046. quad_count--;
  1047. quad_group[min_box_area_index] = quad_group[quad_count];
  1048. centers[min_box_area_index] = centers[quad_count];
  1049. }
  1050. return quad_count;
  1051. }
  1052. //=====================================================================================
  1053. static int
  1054. icvFindConnectedQuads( CvCBQuad *quad, int quad_count, CvCBQuad **out_group,
  1055. int group_idx, CvMemStorage* storage )
  1056. {
  1057. cv::Ptr<CvMemStorage> temp_storage(cvCreateChildMemStorage( storage ));
  1058. CvSeq* stack = cvCreateSeq( 0, sizeof(*stack), sizeof(void*), temp_storage );
  1059. int i, count = 0;
  1060. // Scan the array for a first unlabeled quad
  1061. for( i = 0; i < quad_count; i++ )
  1062. {
  1063. if( quad[i].count > 0 && quad[i].group_idx < 0)
  1064. break;
  1065. }
  1066. // Recursively find a group of connected quads starting from the seed quad[i]
  1067. if( i < quad_count )
  1068. {
  1069. CvCBQuad* q = &quad[i];
  1070. cvSeqPush( stack, &q );
  1071. out_group[count++] = q;
  1072. q->group_idx = group_idx;
  1073. q->ordered = false;
  1074. while( stack->total )
  1075. {
  1076. cvSeqPop( stack, &q );
  1077. for( i = 0; i < 4; i++ )
  1078. {
  1079. CvCBQuad *neighbor = q->neighbors[i];
  1080. if( neighbor && neighbor->count > 0 && neighbor->group_idx < 0 )
  1081. {
  1082. cvSeqPush( stack, &neighbor );
  1083. out_group[count++] = neighbor;
  1084. neighbor->group_idx = group_idx;
  1085. neighbor->ordered = false;
  1086. }
  1087. }
  1088. }
  1089. }
  1090. return count;
  1091. }
  1092. //=====================================================================================
  1093. static int
  1094. icvCheckQuadGroup( CvCBQuad **quad_group, int quad_count,
  1095. CvCBCorner **out_corners, CvSize pattern_size )
  1096. {
  1097. const int ROW1 = 1000000;
  1098. const int ROW2 = 2000000;
  1099. const int ROW_ = 3000000;
  1100. int result = 0;
  1101. int i, out_corner_count = 0, corner_count = 0;
  1102. std::vector<CvCBCorner*> corners(quad_count*4);
  1103. int j, k, kk;
  1104. int width = 0, height = 0;
  1105. int hist[5] = {0,0,0,0,0};
  1106. CvCBCorner* first = 0, *first2 = 0, *right, *cur, *below, *c;
  1107. // build dual graph, which vertices are internal quad corners
  1108. // and two vertices are connected iff they lie on the same quad edge
  1109. for( i = 0; i < quad_count; i++ )
  1110. {
  1111. CvCBQuad* q = quad_group[i];
  1112. /*CvScalar color = q->count == 0 ? cvScalar(0,255,255) :
  1113. q->count == 1 ? cvScalar(0,0,255) :
  1114. q->count == 2 ? cvScalar(0,255,0) :
  1115. q->count == 3 ? cvScalar(255,255,0) :
  1116. cvScalar(255,0,0);*/
  1117. for( j = 0; j < 4; j++ )
  1118. {
  1119. //cvLine( debug_img, cvPointFrom32f(q->corners[j]->pt), cvPointFrom32f(q->corners[(j+1)&3]->pt), color, 1, CV_AA, 0 );
  1120. if( q->neighbors[j] )
  1121. {
  1122. CvCBCorner *a = q->corners[j], *b = q->corners[(j+1)&3];
  1123. // mark internal corners that belong to:
  1124. // - a quad with a single neighbor - with ROW1,
  1125. // - a quad with two neighbors - with ROW2
  1126. // make the rest of internal corners with ROW_
  1127. int row_flag = q->count == 1 ? ROW1 : q->count == 2 ? ROW2 : ROW_;
  1128. if( a->row == 0 )
  1129. {
  1130. corners[corner_count++] = a;
  1131. a->row = row_flag;
  1132. }
  1133. else if( a->row > row_flag )
  1134. a->row = row_flag;
  1135. if( q->neighbors[(j+1)&3] )
  1136. {
  1137. if( a->count >= 4 || b->count >= 4 )
  1138. goto finalize;
  1139. for( k = 0; k < 4; k++ )
  1140. {
  1141. if( a->neighbors[k] == b )
  1142. goto finalize;
  1143. if( b->neighbors[k] == a )
  1144. goto finalize;
  1145. }
  1146. a->neighbors[a->count++] = b;
  1147. b->neighbors[b->count++] = a;
  1148. }
  1149. }
  1150. }
  1151. }
  1152. if( corner_count != pattern_size.width*pattern_size.height )
  1153. goto finalize;
  1154. for( i = 0; i < corner_count; i++ )
  1155. {
  1156. int n = corners[i]->count;
  1157. assert( 0 <= n && n <= 4 );
  1158. hist[n]++;
  1159. if( !first && n == 2 )
  1160. {
  1161. if( corners[i]->row == ROW1 )
  1162. first = corners[i];
  1163. else if( !first2 && corners[i]->row == ROW2 )
  1164. first2 = corners[i];
  1165. }
  1166. }
  1167. // start with a corner that belongs to a quad with a signle neighbor.
  1168. // if we do not have such, start with a corner of a quad with two neighbors.
  1169. if( !first )
  1170. first = first2;
  1171. if( !first || hist[0] != 0 || hist[1] != 0 || hist[2] != 4 ||
  1172. hist[3] != (pattern_size.width + pattern_size.height)*2 - 8 )
  1173. goto finalize;
  1174. cur = first;
  1175. right = below = 0;
  1176. out_corners[out_corner_count++] = cur;
  1177. for( k = 0; k < 4; k++ )
  1178. {
  1179. c = cur->neighbors[k];
  1180. if( c )
  1181. {
  1182. if( !right )
  1183. right = c;
  1184. else if( !below )
  1185. below = c;
  1186. }
  1187. }
  1188. if( !right || (right->count != 2 && right->count != 3) ||
  1189. !below || (below->count != 2 && below->count != 3) )
  1190. goto finalize;
  1191. cur->row = 0;
  1192. //cvCircle( debug_img, cvPointFrom32f(cur->pt), 3, cvScalar(0,255,0), -1, 8, 0 );
  1193. first = below; // remember the first corner in the next row
  1194. // find and store the first row (or column)
  1195. for(j=1;;j++)
  1196. {
  1197. right->row = 0;
  1198. out_corners[out_corner_count++] = right;
  1199. //cvCircle( debug_img, cvPointFrom32f(right->pt), 3, cvScalar(0,255-j*10,0), -1, 8, 0 );
  1200. if( right->count == 2 )
  1201. break;
  1202. if( right->count != 3 || out_corner_count >= MAX(pattern_size.width,pattern_size.height) )
  1203. goto finalize;
  1204. cur = right;
  1205. for( k = 0; k < 4; k++ )
  1206. {
  1207. c = cur->neighbors[k];
  1208. if( c && c->row > 0 )
  1209. {
  1210. for( kk = 0; kk < 4; kk++ )
  1211. {
  1212. if( c->neighbors[kk] == below )
  1213. break;
  1214. }
  1215. if( kk < 4 )
  1216. below = c;
  1217. else
  1218. right = c;
  1219. }
  1220. }
  1221. }
  1222. width = out_corner_count;
  1223. if( width == pattern_size.width )
  1224. height = pattern_size.height;
  1225. else if( width == pattern_size.height )
  1226. height = pattern_size.width;
  1227. else
  1228. goto finalize;
  1229. // find and store all the other rows
  1230. for( i = 1; ; i++ )
  1231. {
  1232. if( !first )
  1233. break;
  1234. cur = first;
  1235. first = 0;
  1236. for( j = 0;; j++ )
  1237. {
  1238. cur->row = i;
  1239. out_corners[out_corner_count++] = cur;
  1240. //cvCircle( debug_img, cvPointFrom32f(cur->pt), 3, cvScalar(0,0,255-j*10), -1, 8, 0 );
  1241. if( cur->count == 2 + (i < height-1) && j > 0 )
  1242. break;
  1243. right = 0;
  1244. // find a neighbor that has not been processed yet
  1245. // and that has a neighbor from the previous row
  1246. for( k = 0; k < 4; k++ )
  1247. {
  1248. c = cur->neighbors[k];
  1249. if( c && c->row > i )
  1250. {
  1251. for( kk = 0; kk < 4; kk++ )
  1252. {
  1253. if( c->neighbors[kk] && c->neighbors[kk]->row == i-1 )
  1254. break;
  1255. }
  1256. if( kk < 4 )
  1257. {
  1258. right = c;
  1259. if( j > 0 )
  1260. break;
  1261. }
  1262. else if( j == 0 )
  1263. first = c;
  1264. }
  1265. }
  1266. if( !right )
  1267. goto finalize;
  1268. cur = right;
  1269. }
  1270. if( j != width - 1 )
  1271. goto finalize;
  1272. }
  1273. if( out_corner_count != corner_count )
  1274. goto finalize;
  1275. // check if we need to transpose the board
  1276. if( width != pattern_size.width )
  1277. {
  1278. CV_SWAP( width, height, k );
  1279. memcpy( &corners[0], out_corners, corner_count*sizeof(corners[0]) );
  1280. for( i = 0; i < height; i++ )
  1281. for( j = 0; j < width; j++ )
  1282. out_corners[i*width + j] = corners[j*height + i];
  1283. }
  1284. // check if we need to revert the order in each row
  1285. {
  1286. CvPoint2D32f p0 = out_corners[0]->pt, p1 = out_corners[pattern_size.width-1]->pt,
  1287. p2 = out_corners[pattern_size.width]->pt;
  1288. if( (p1.x - p0.x)*(p2.y - p1.y) - (p1.y - p0.y)*(p2.x - p1.x) < 0 )
  1289. {
  1290. if( width % 2 == 0 )
  1291. {
  1292. for( i = 0; i < height; i++ )
  1293. for( j = 0; j < width/2; j++ )
  1294. CV_SWAP( out_corners[i*width+j], out_corners[i*width+width-j-1], c );
  1295. }
  1296. else
  1297. {
  1298. for( j = 0; j < width; j++ )
  1299. for( i = 0; i < height/2; i++ )
  1300. CV_SWAP( out_corners[i*width+j], out_corners[(height - i - 1)*width+j], c );
  1301. }
  1302. }
  1303. }
  1304. result = corner_count;
  1305. finalize:
  1306. if( result <= 0 )
  1307. {
  1308. corner_count = MIN( corner_count, pattern_size.width*pattern_size.height );
  1309. for( i = 0; i < corner_count; i++ )
  1310. out_corners[i] = corners[i];
  1311. result = -corner_count;
  1312. if (result == -pattern_size.width*pattern_size.height)
  1313. result = -result;
  1314. }
  1315. return result;
  1316. }
  1317. //=====================================================================================
  1318. static void icvFindQuadNeighbors( CvCBQuad *quads, int quad_count )
  1319. {
  1320. const float thresh_scale = 1.f;
  1321. int idx, i, k, j;
  1322. float dx, dy, dist;
  1323. // find quad neighbors
  1324. for( idx = 0; idx < quad_count; idx++ )
  1325. {
  1326. CvCBQuad* cur_quad = &quads[idx];
  1327. // choose the points of the current quadrangle that are close to
  1328. // some points of the other quadrangles
  1329. // (it can happen for split corners (due to dilation) of the
  1330. // checker board). Search only in other quadrangles!
  1331. // for each corner of this quadrangle
  1332. for( i = 0; i < 4; i++ )
  1333. {
  1334. CvPoint2D32f pt;
  1335. float min_dist = FLT_MAX;
  1336. int closest_corner_idx = -1;
  1337. CvCBQuad *closest_quad = 0;
  1338. CvCBCorner *closest_corner = 0;
  1339. if( cur_quad->neighbors[i] )
  1340. continue;
  1341. pt = cur_quad->corners[i]->pt;
  1342. // find the closest corner in all other quadrangles
  1343. for( k = 0; k < quad_count; k++ )
  1344. {
  1345. if( k == idx )
  1346. continue;
  1347. for( j = 0; j < 4; j++ )
  1348. {
  1349. if( quads[k].neighbors[j] )
  1350. continue;
  1351. dx = pt.x - quads[k].corners[j]->pt.x;
  1352. dy = pt.y - quads[k].corners[j]->pt.y;
  1353. dist = dx * dx + dy * dy;
  1354. if( dist < min_dist &&
  1355. dist <= cur_quad->edge_len*thresh_scale &&
  1356. dist <= quads[k].edge_len*thresh_scale )
  1357. {
  1358. // check edge lengths, make sure they're compatible
  1359. // edges that are different by more than 1:4 are rejected
  1360. float ediff = cur_quad->edge_len - quads[k].edge_len;
  1361. if (ediff > 32*cur_quad->edge_len ||
  1362. ediff > 32*quads[k].edge_len)
  1363. {
  1364. PRINTF("Incompatible edge lengths\n");
  1365. continue;
  1366. }
  1367. closest_corner_idx = j;
  1368. closest_quad = &quads[k];
  1369. min_dist = dist;
  1370. }
  1371. }
  1372. }
  1373. // we found a matching corner point?
  1374. if( closest_corner_idx >= 0 && min_dist < FLT_MAX )
  1375. {
  1376. // If another point from our current quad is closer to the found corner
  1377. // than the current one, then we don't count this one after all.
  1378. // This is necessary to support small squares where otherwise the wrong
  1379. // corner will get matched to closest_quad;
  1380. closest_corner = closest_quad->corners[closest_corner_idx];
  1381. for( j = 0; j < 4; j++ )
  1382. {
  1383. if( cur_quad->neighbors[j] == closest_quad )
  1384. break;
  1385. dx = closest_corner->pt.x - cur_quad->corners[j]->pt.x;
  1386. dy = closest_corner->pt.y - cur_quad->corners[j]->pt.y;
  1387. if( dx * dx + dy * dy < min_dist )
  1388. break;
  1389. }
  1390. if( j < 4 || cur_quad->count >= 4 || closest_quad->count >= 4 )
  1391. continue;
  1392. // Check that each corner is a neighbor of different quads
  1393. for( j = 0; j < closest_quad->count; j++ )
  1394. {
  1395. if( closest_quad->neighbors[j] == cur_quad )
  1396. break;
  1397. }
  1398. if( j < closest_quad->count )
  1399. continue;
  1400. // check whether the closest corner to closest_corner
  1401. // is different from cur_quad->corners[i]->pt
  1402. for( k = 0; k < quad_count; k++ )
  1403. {
  1404. CvCBQuad* q = &quads[k];
  1405. if( k == idx || q == closest_quad )
  1406. continue;
  1407. for( j = 0; j < 4; j++ )
  1408. if( !q->neighbors[j] )
  1409. {
  1410. dx = closest_corner->pt.x - q->corners[j]->pt.x;
  1411. dy = closest_corner->pt.y - q->corners[j]->pt.y;
  1412. dist = dx*dx + dy*dy;
  1413. if( dist < min_dist )
  1414. break;
  1415. }
  1416. if( j < 4 )
  1417. break;
  1418. }
  1419. if( k < quad_count )
  1420. continue;
  1421. closest_corner->pt.x = (pt.x + closest_corner->pt.x) * 0.5f;
  1422. closest_corner->pt.y = (pt.y + closest_corner->pt.y) * 0.5f;
  1423. // We've found one more corner - remember it
  1424. cur_quad->count++;
  1425. cur_quad->neighbors[i] = closest_quad;
  1426. cur_quad->corners[i] = closest_corner;
  1427. closest_quad->count++;
  1428. closest_quad->neighbors[closest_corner_idx] = cur_quad;
  1429. }
  1430. }
  1431. }
  1432. }
  1433. //=====================================================================================
  1434. // returns corners in clockwise order
  1435. // corners don't necessarily start at same position on quad (e.g.,
  1436. // top left corner)
  1437. static int
  1438. icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
  1439. CvMemStorage *storage, CvMat *image, int flags )
  1440. {
  1441. int quad_count = 0;
  1442. cv::Ptr<CvMemStorage> temp_storage;
  1443. if( out_quads )
  1444. *out_quads = 0;
  1445. if( out_corners )
  1446. *out_corners = 0;
  1447. CvSeq *src_contour = 0;
  1448. CvSeq *root;
  1449. CvContourEx* board = 0;
  1450. CvContourScanner scanner;
  1451. int i, idx, min_size;
  1452. CV_Assert( out_corners && out_quads );
  1453. // empiric bound for minimal allowed perimeter for squares
  1454. min_size = 25; //cvRound( image->cols * image->rows * .03 * 0.01 * 0.92 );
  1455. // create temporary storage for contours and the sequence of pointers to found quadrangles
  1456. temp_storage.reset(cvCreateChildMemStorage( storage ));
  1457. root = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvSeq*), temp_storage );
  1458. // initialize contour retrieving routine
  1459. scanner = cvStartFindContours( image, temp_storage, sizeof(CvContourEx),
  1460. CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
  1461. // get all the contours one by one
  1462. while( (src_contour = cvFindNextContour( scanner )) != 0 )
  1463. {
  1464. CvSeq *dst_contour = 0;
  1465. CvRect rect = ((CvContour*)src_contour)->rect;
  1466. // reject contours with too small perimeter
  1467. if( CV_IS_SEQ_HOLE(src_contour) && rect.width*rect.height >= min_size )
  1468. {
  1469. const int min_approx_level = 1, max_approx_level = MAX_CONTOUR_APPROX;
  1470. int approx_level;
  1471. for( approx_level = min_approx_level; approx_level <= max_approx_level; approx_level++ )
  1472. {
  1473. dst_contour = cvApproxPoly( src_contour, sizeof(CvContour), temp_storage,
  1474. CV_POLY_APPROX_DP, (float)approx_level );
  1475. if( dst_contour->total == 4 )
  1476. break;
  1477. // we call this again on its own output, because sometimes
  1478. // cvApproxPoly() does not simplify as much as it should.
  1479. dst_contour = cvApproxPoly( dst_contour, sizeof(CvContour), temp_storage,
  1480. CV_POLY_APPROX_DP, (float)approx_level );
  1481. if( dst_contour->total == 4 )
  1482. break;
  1483. }
  1484. // reject non-quadrangles
  1485. if( dst_contour->total == 4 && cvCheckContourConvexity(dst_contour) )
  1486. {
  1487. CvPoint pt[4];
  1488. double d1, d2, p = cvContourPerimeter(dst_contour);
  1489. double area = fabs(cvContourArea(dst_contour, CV_WHOLE_SEQ));
  1490. double dx, dy;
  1491. for( i = 0; i < 4; i++ )
  1492. pt[i] = *(CvPoint*)cvGetSeqElem(dst_contour, i);
  1493. dx = pt[0].x - pt[2].x;
  1494. dy = pt[0].y - pt[2].y;
  1495. d1 = sqrt(dx*dx + dy*dy);
  1496. dx = pt[1].x - pt[3].x;
  1497. dy = pt[1].y - pt[3].y;
  1498. d2 = sqrt(dx*dx + dy*dy);
  1499. // philipg. Only accept those quadrangles which are more square
  1500. // than rectangular and which are big enough
  1501. double d3, d4;
  1502. dx = pt[0].x - pt[1].x;
  1503. dy = pt[0].y - pt[1].y;
  1504. d3 = sqrt(dx*dx + dy*dy);
  1505. dx = pt[1].x - pt[2].x;
  1506. dy = pt[1].y - pt[2].y;
  1507. d4 = sqrt(dx*dx + dy*dy);
  1508. if( !(flags & CV_CALIB_CB_FILTER_QUADS) ||
  1509. (d3*4 > d4 && d4*4 > d3 && d3*d4 < area*1.5 && area > min_size &&
  1510. d1 >= 0.15 * p && d2 >= 0.15 * p) )
  1511. {
  1512. CvContourEx* parent = (CvContourEx*)(src_contour->v_prev);
  1513. parent->counter++;
  1514. if( !board || board->counter < parent->counter )
  1515. board = parent;
  1516. dst_contour->v_prev = (CvSeq*)parent;
  1517. //for( i = 0; i < 4; i++ ) cvLine( debug_img, pt[i], pt[(i+1)&3], cvScalar(200,255,255), 1, CV_AA, 0 );
  1518. cvSeqPush( root, &dst_contour );
  1519. }
  1520. }
  1521. }
  1522. }
  1523. // finish contour retrieving
  1524. cvEndFindContours( &scanner );
  1525. // allocate quad & corner buffers
  1526. *out_quads = (CvCBQuad*)cvAlloc((root->total+root->total / 2) * sizeof((*out_quads)[0]));
  1527. *out_corners = (CvCBCorner*)cvAlloc((root->total+root->total / 2) * 4 * sizeof((*out_corners)[0]));
  1528. // Create array of quads structures
  1529. for( idx = 0; idx < root->total; idx++ )
  1530. {
  1531. CvCBQuad* q = &(*out_quads)[quad_count];
  1532. src_contour = *(CvSeq**)cvGetSeqElem( root, idx );
  1533. if( (flags & CV_CALIB_CB_FILTER_QUADS) && src_contour->v_prev != (CvSeq*)board )
  1534. continue;
  1535. // reset group ID
  1536. memset( q, 0, sizeof(*q) );
  1537. q->group_idx = -1;
  1538. assert( src_contour->total == 4 );
  1539. for( i = 0; i < 4; i++ )
  1540. {
  1541. CvPoint2D32f pt = cvPointTo32f(*(CvPoint*)cvGetSeqElem(src_contour, i));
  1542. CvCBCorner* corner = &(*out_corners)[quad_count*4 + i];
  1543. memset( corner, 0, sizeof(*corner) );
  1544. corner->pt = pt;
  1545. q->corners[i] = corner;
  1546. }
  1547. q->edge_len = FLT_MAX;
  1548. for( i = 0; i < 4; i++ )
  1549. {
  1550. float dx = q->corners[i]->pt.x - q->corners[(i+1)&3]->pt.x;
  1551. float dy = q->corners[i]->pt.y - q->corners[(i+1)&3]->pt.y;
  1552. float d = dx*dx + dy*dy;
  1553. if( q->edge_len > d )
  1554. q->edge_len = d;
  1555. }
  1556. quad_count++;
  1557. }
  1558. return quad_count;
  1559. }
  1560. CV_IMPL void
  1561. cvDrawChessboardCorners( CvArr* _image, CvSize pattern_size,
  1562. CvPoint2D32f* corners, int count, int found )
  1563. {
  1564. const int shift = 0;
  1565. const int radius = 4;
  1566. const int r = radius*(1 << shift);
  1567. int i;
  1568. CvMat stub, *image;
  1569. double scale = 1;
  1570. int type, cn, line_type;
  1571. image = cvGetMat( _image, &stub );
  1572. type = CV_MAT_TYPE(image->type);
  1573. cn = CV_MAT_CN(type);
  1574. if( cn != 1 && cn != 3 && cn != 4 )
  1575. CV_Error( CV_StsUnsupportedFormat, "Number of channels must be 1, 3 or 4" );
  1576. switch( CV_MAT_DEPTH(image->type) )
  1577. {
  1578. case CV_8U:
  1579. scale = 1;
  1580. break;
  1581. case CV_16U:
  1582. scale = 256;
  1583. break;
  1584. case CV_32F:
  1585. scale = 1./255;
  1586. break;
  1587. default:
  1588. CV_Error( CV_StsUnsupportedFormat,
  1589. "Only 8-bit, 16-bit or floating-point 32-bit images are supported" );
  1590. }
  1591. line_type = type == CV_8UC1 || type == CV_8UC3 ? CV_AA : 8;
  1592. if( !found )
  1593. {
  1594. CvScalar color(0,0,255,0);
  1595. if( cn == 1 )
  1596. color = cvScalarAll(200);
  1597. color.val[0] *= scale;
  1598. color.val[1] *= scale;
  1599. color.val[2] *= scale;
  1600. color.val[3] *= scale;
  1601. for( i = 0; i < count; i++ )
  1602. {
  1603. CvPoint pt;
  1604. pt.x = cvRound(corners[i].x*(1 << shift));
  1605. pt.y = cvRound(corners[i].y*(1 << shift));
  1606. cvLine( image, cvPoint( pt.x - r, pt.y - r ),
  1607. cvPoint( pt.x + r, pt.y + r ), color, 1, line_type, shift );
  1608. cvLine( image, cvPoint( pt.x - r, pt.y + r),
  1609. cvPoint( pt.x + r, pt.y - r), color, 1, line_type, shift );
  1610. cvCircle( image, pt, r+(1<<shift), color, 1, line_type, shift );
  1611. }
  1612. }
  1613. else
  1614. {
  1615. int x, y;
  1616. CvPoint prev_pt;
  1617. const int line_max = 7;
  1618. static const CvScalar line_colors[line_max] =
  1619. {
  1620. CvScalar(0,0,255),
  1621. CvScalar(0,128,255),
  1622. CvScalar(0,200,200),
  1623. CvScalar(0,255,0),
  1624. CvScalar(200,200,0),
  1625. CvScalar(255,0,0),
  1626. CvScalar(255,0,255)
  1627. };
  1628. for( y = 0, i = 0; y < pattern_size.height; y++ )
  1629. {
  1630. CvScalar color = line_colors[y % line_max];
  1631. if( cn == 1 )
  1632. color = cvScalarAll(200);
  1633. color.val[0] *= scale;
  1634. color.val[1] *= scale;
  1635. color.val[2] *= scale;
  1636. color.val[3] *= scale;
  1637. for( x = 0; x < pattern_size.width; x++, i++ )
  1638. {
  1639. CvPoint pt;
  1640. pt.x = cvRound(corners[i].x*(1 << shift));
  1641. pt.y = cvRound(corners[i].y*(1 << shift));
  1642. if( i != 0 )
  1643. cvLine( image, prev_pt, pt, color, 1, line_type, shift );
  1644. cvLine( image, cvPoint(pt.x - r, pt.y - r),
  1645. cvPoint(pt.x + r, pt.y + r), color, 1, line_type, shift );
  1646. cvLine( image, cvPoint(pt.x - r, pt.y + r),
  1647. cvPoint(pt.x + r, pt.y - r), color, 1, line_type, shift );
  1648. cvCircle( image, pt, r+(1<<shift), color, 1, line_type, shift );
  1649. prev_pt = pt;
  1650. }
  1651. }
  1652. }
  1653. }
  1654. bool cv::findChessboardCorners( InputArray _image, Size patternSize,
  1655. OutputArray corners, int flags )
  1656. {
  1657. int count = patternSize.area()*2;
  1658. std::vector<Point2f> tmpcorners(count+1);
  1659. Mat image = _image.getMat(); CvMat c_image = image;
  1660. bool ok = cvFindChessboardCorners(&c_image, patternSize,
  1661. (CvPoint2D32f*)&tmpcorners[0], &count, flags ) > 0;
  1662. if( count > 0 )
  1663. {
  1664. tmpcorners.resize(count);
  1665. Mat(tmpcorners).copyTo(corners);
  1666. }
  1667. else
  1668. corners.release();
  1669. return ok;
  1670. }
  1671. namespace
  1672. {
  1673. int quiet_error(int /*status*/, const char* /*func_name*/,
  1674. const char* /*err_msg*/, const char* /*file_name*/,
  1675. int /*line*/, void* /*userdata*/ )
  1676. {
  1677. return 0;
  1678. }
  1679. }
  1680. void cv::drawChessboardCorners( InputOutputArray _image, Size patternSize,
  1681. InputArray _corners,
  1682. bool patternWasFound )
  1683. {
  1684. Mat corners = _corners.getMat();
  1685. if( corners.empty() )
  1686. return;
  1687. Mat image = _image.getMat(); CvMat c_image = _image.getMat();
  1688. int nelems = corners.checkVector(2, CV_32F, true);
  1689. CV_Assert(nelems >= 0);
  1690. cvDrawChessboardCorners( &c_image, patternSize, (CvPoint2D32f*)corners.data,
  1691. nelems, patternWasFound );
  1692. }
  1693. bool cv::findCirclesGrid( InputArray _image, Size patternSize,
  1694. OutputArray _centers, int flags, const Ptr<FeatureDetector> &blobDetector )
  1695. {
  1696. bool isAsymmetricGrid = (flags & CALIB_CB_ASYMMETRIC_GRID) ? true : false;
  1697. bool isSymmetricGrid = (flags & CALIB_CB_SYMMETRIC_GRID ) ? true : false;
  1698. CV_Assert(isAsymmetricGrid ^ isSymmetricGrid);
  1699. Mat image = _image.getMat();
  1700. std::vector<Point2f> centers;
  1701. std::vector<KeyPoint> keypoints;
  1702. blobDetector->detect(image, keypoints);
  1703. std::vector<Point2f> points;
  1704. for (size_t i = 0; i < keypoints.size(); i++)
  1705. {
  1706. points.push_back (keypoints[i].pt);
  1707. }
  1708. if(flags & CALIB_CB_CLUSTERING)
  1709. {
  1710. CirclesGridClusterFinder circlesGridClusterFinder(isAsymmetricGrid);
  1711. circlesGridClusterFinder.findGrid(points, patternSize, centers);
  1712. Mat(centers).copyTo(_centers);
  1713. return !centers.empty();
  1714. }
  1715. CirclesGridFinderParameters parameters;
  1716. parameters.vertexPenalty = -0.6f;
  1717. parameters.vertexGain = 1;
  1718. parameters.existingVertexGain = 10000;
  1719. parameters.edgeGain = 1;
  1720. parameters.edgePenalty = -0.6f;
  1721. if(flags & CALIB_CB_ASYMMETRIC_GRID)
  1722. parameters.gridType = CirclesGridFinderParameters::ASYMMETRIC_GRID;
  1723. if(flags & CALIB_CB_SYMMETRIC_GRID)
  1724. parameters.gridType = CirclesGridFinderParameters::SYMMETRIC_GRID;
  1725. const int attempts = 2;
  1726. const size_t minHomographyPoints = 4;
  1727. Mat H;
  1728. for (int i = 0; i < attempts; i++)
  1729. {
  1730. centers.clear();
  1731. CirclesGridFinder boxFinder(patternSize, points, parameters);
  1732. bool isFound = false;
  1733. #define BE_QUIET 1
  1734. #if BE_QUIET
  1735. void* oldCbkData;
  1736. ErrorCallback oldCbk = redirectError(quiet_error, 0, &oldCbkData);
  1737. #endif
  1738. try
  1739. {
  1740. isFound = boxFinder.findHoles();
  1741. }
  1742. catch (cv::Exception)
  1743. {
  1744. }
  1745. #if BE_QUIET
  1746. redirectError(oldCbk, oldCbkData);
  1747. #endif
  1748. if (isFound)
  1749. {
  1750. switch(parameters.gridType)
  1751. {
  1752. case CirclesGridFinderParameters::SYMMETRIC_GRID:
  1753. boxFinder.getHoles(centers);
  1754. break;
  1755. case CirclesGridFinderParameters::ASYMMETRIC_GRID:
  1756. boxFinder.getAsymmetricHoles(centers);
  1757. break;
  1758. default:
  1759. CV_Error(CV_StsBadArg, "Unkown pattern type");
  1760. }
  1761. if (i != 0)
  1762. {
  1763. Mat orgPointsMat;
  1764. transform(centers, orgPointsMat, H.inv());
  1765. convertPointsFromHomogeneous(orgPointsMat, centers);
  1766. }
  1767. Mat(centers).copyTo(_centers);
  1768. return true;
  1769. }
  1770. boxFinder.getHoles(centers);
  1771. if (i != attempts - 1)
  1772. {
  1773. if (centers.size() < minHomographyPoints)
  1774. break;
  1775. H = CirclesGridFinder::rectifyGrid(boxFinder.getDetectedGridSize(), centers, points, points);
  1776. }
  1777. }
  1778. Mat(centers).copyTo(_centers);
  1779. return false;
  1780. }
  1781. /* End of file. */