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