This source file includes following definitions.
- PRINTF
- PRINTF
- meanDist
- icvCalcAffineTranf2D32f
- cvFindChessboardCorners
- icvCheckBoardMonotony
- icvOrderFoundConnectedQuads
- icvAddOuterQuad
- icvTrimCol
- icvTrimRow
- icvRemoveQuadFromGroup
- icvOrderQuad
- icvCleanFoundConnectedQuads
- icvFindConnectedQuads
- icvCheckQuadGroup
- icvFindQuadNeighbors
- icvGenerateQuads
- cvDrawChessboardCorners
- findChessboardCorners
- quiet_error
- drawChessboardCorners
- findCirclesGrid
#include "precomp.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/calib3d/calib3d_c.h"
#include "circlesgrid.hpp"
#include <stdarg.h>
#ifdef DEBUG_CHESSBOARD
# include "opencv2/opencv_modules.hpp"
# ifdef HAVE_OPENCV_HIGHGUI
# include "opencv2/highgui.hpp"
# else
# undef DEBUG_CHESSBOARD
# endif
#endif
#ifdef DEBUG_CHESSBOARD
static int PRINTF( const char* fmt, ... )
{
va_list args;
va_start(args, fmt);
return vprintf(fmt, args);
}
#else
static int PRINTF( const char*, ... )
{
return 0;
}
#endif
#define MAX_CONTOUR_APPROX 7
struct CvContourEx
{
CV_CONTOUR_FIELDS()
int counter;
};
struct CvCBCorner
{
CvPoint2D32f pt;
int row;
int count;
struct CvCBCorner* neighbors[4];
float meanDist(int *_n) const
{
float sum = 0;
int n = 0;
for( int i = 0; i < 4; i++ )
{
if( neighbors[i] )
{
float dx = neighbors[i]->pt.x - pt.x;
float dy = neighbors[i]->pt.y - pt.y;
sum += sqrt(dx*dx + dy*dy);
n++;
}
}
if(_n)
*_n = n;
return sum/MAX(n,1);
}
};
struct CvCBQuad
{
int count;
int group_idx;
int row, col;
bool ordered;
float edge_len;
CvCBCorner *corners[4];
struct CvCBQuad *neighbors[4];
};
static int icvGenerateQuads( CvCBQuad **quads, CvCBCorner **corners,
CvMemStorage *storage, CvMat *image, int flags );
static void icvFindQuadNeighbors( CvCBQuad *quads, int quad_count );
static int icvFindConnectedQuads( CvCBQuad *quads, int quad_count,
CvCBQuad **quad_group, int group_idx,
CvMemStorage* storage );
static int icvCheckQuadGroup( CvCBQuad **quad_group, int count,
CvCBCorner **out_corners, CvSize pattern_size );
static int icvCleanFoundConnectedQuads( int quad_count,
CvCBQuad **quads, CvSize pattern_size );
static int icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads,
int *all_count, CvCBQuad **all_quads, CvCBCorner **corners,
CvSize pattern_size, CvMemStorage* storage );
static void icvOrderQuad(CvCBQuad *quad, CvCBCorner *corner, int common);
#ifdef ENABLE_TRIM_COL_ROW
static int icvTrimCol(CvCBQuad **quads, int count, int col, int dir);
static int icvTrimRow(CvCBQuad **quads, int count, int row, int dir);
#endif
static int icvAddOuterQuad(CvCBQuad *quad, CvCBQuad **quads, int quad_count,
CvCBQuad **all_quads, int all_count, CvCBCorner **corners);
static void icvRemoveQuadFromGroup(CvCBQuad **quads, int count, CvCBQuad *q0);
static int icvCheckBoardMonotony( CvPoint2D32f* corners, CvSize pattern_size );
#if 0
static void
icvCalcAffineTranf2D32f(CvPoint2D32f* pts1, CvPoint2D32f* pts2, int count, CvMat* affine_trans)
{
int i, j;
int real_count = 0;
for( j = 0; j < count; j++ )
{
if( pts1[j].x >= 0 ) real_count++;
}
if(real_count < 3) return;
cv::Ptr<CvMat> xy = cvCreateMat( 2*real_count, 6, CV_32FC1 );
cv::Ptr<CvMat> uv = cvCreateMat( 2*real_count, 1, CV_32FC1 );
for( i = 0, j = 0; j < count; j++ )
{
if( pts1[j].x >= 0 )
{
CV_MAT_ELEM( *xy, float, i*2+1, 2 ) = CV_MAT_ELEM( *xy, float, i*2, 0 ) = pts2[j].x;
CV_MAT_ELEM( *xy, float, i*2+1, 3 ) = CV_MAT_ELEM( *xy, float, i*2, 1 ) = pts2[j].y;
CV_MAT_ELEM( *xy, float, i*2, 2 ) = CV_MAT_ELEM( *xy, float, i*2, 3 ) = CV_MAT_ELEM( *xy, float, i*2, 5 ) = \
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;
CV_MAT_ELEM( *xy, float, i*2, 4 ) = CV_MAT_ELEM( *xy, float, i*2+1, 5 ) = 1;
CV_MAT_ELEM( *uv, float, i*2, 0 ) = pts1[j].x;
CV_MAT_ELEM( *uv, float, i*2+1, 0 ) = pts1[j].y;
i++;
}
}
cvSolve( xy, uv, affine_trans, CV_SVD );
}
#endif
CV_IMPL
int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
CvPoint2D32f* out_corners, int* out_corner_count,
int flags )
{
int found = 0;
CvCBQuad *quads = 0, **quad_group = 0;
CvCBCorner *corners = 0, **corner_group = 0;
try
{
int k = 0;
const int min_dilations = 0;
const int max_dilations = 7;
cv::Ptr<CvMat> norm_img, thresh_img;
#ifdef DEBUG_CHESSBOARD
cv::Ptr<IplImage> dbg_img;
cv::Ptr<IplImage> dbg1_img;
cv::Ptr<IplImage> dbg2_img;
#endif
cv::Ptr<CvMemStorage> storage;
CvMat stub, *img = (CvMat*)arr;
int expected_corners_num = (pattern_size.width/2+1)*(pattern_size.height/2+1);
int prev_sqr_size = 0;
if( out_corner_count )
*out_corner_count = 0;
IplImage _img;
int quad_count = 0, group_idx = 0, dilations = 0;
img = cvGetMat( img, &stub );
if( CV_MAT_DEPTH( img->type ) != CV_8U || CV_MAT_CN( img->type ) == 2 )
CV_Error( CV_StsUnsupportedFormat, "Only 8-bit grayscale or color images are supported" );
if( pattern_size.width <= 2 || pattern_size.height <= 2 )
CV_Error( CV_StsOutOfRange, "Both width and height of the pattern should have bigger than 2" );
if( !out_corners )
CV_Error( CV_StsNullPtr, "Null pointer to corners" );
storage.reset(cvCreateMemStorage(0));
thresh_img.reset(cvCreateMat( img->rows, img->cols, CV_8UC1 ));
#ifdef DEBUG_CHESSBOARD
dbg_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3 );
dbg1_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3 );
dbg2_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3 );
#endif
if( CV_MAT_CN(img->type) != 1 || (flags & CV_CALIB_CB_NORMALIZE_IMAGE) )
{
norm_img.reset(cvCreateMat( img->rows, img->cols, CV_8UC1 ));
if( CV_MAT_CN(img->type) != 1 )
{
cvCvtColor( img, norm_img, CV_BGR2GRAY );
img = norm_img;
}
if( flags & CV_CALIB_CB_NORMALIZE_IMAGE )
{
cvEqualizeHist( img, norm_img );
img = norm_img;
}
}
if( flags & CV_CALIB_CB_FAST_CHECK)
{
cvGetImage(img, &_img);
int check_chessboard_result = cvCheckChessboard(&_img, pattern_size);
if(check_chessboard_result <= 0)
{
return 0;
}
}
for( k = 0; k < 6; k++ )
{
for( dilations = min_dilations; dilations <= max_dilations; dilations++ )
{
if (found)
break;
cvFree(&quads);
cvFree(&corners);
{
if( flags & CV_CALIB_CB_ADAPTIVE_THRESH )
{
int block_size = cvRound(prev_sqr_size == 0 ?
MIN(img->cols,img->rows)*(k%2 == 0 ? 0.2 : 0.1): prev_sqr_size*2)|1;
cvAdaptiveThreshold( img, thresh_img, 255,
CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, block_size, (k/2)*5 );
if (dilations > 0)
cvDilate( thresh_img, thresh_img, 0, dilations-1 );
}
else
{
double mean = cvAvg( img ).val[0];
int thresh_level = cvRound( mean - 10 );
thresh_level = MAX( thresh_level, 10 );
cvThreshold( img, thresh_img, thresh_level, 255, CV_THRESH_BINARY );
cvDilate( thresh_img, thresh_img, 0, dilations );
}
#ifdef DEBUG_CHESSBOARD
cvCvtColor(thresh_img,dbg_img,CV_GRAY2BGR);
#endif
cvRectangle( thresh_img, cvPoint(0,0), cvPoint(thresh_img->cols-1,
thresh_img->rows-1), CV_RGB(255,255,255), 3, 8);
quad_count = icvGenerateQuads( &quads, &corners, storage, thresh_img, flags );
PRINTF("Quad count: %d/%d\n", quad_count, expected_corners_num);
}
#ifdef DEBUG_CHESSBOARD
cvCopy(dbg_img, dbg1_img);
cvNamedWindow("all_quads", 1);
for(int i = 0; i < quad_count; i++ )
{
for (int k=0; k<4; k++)
{
CvPoint2D32f pt1, pt2;
CvScalar color = CV_RGB(30,255,30);
pt1 = quads[i].corners[k]->pt;
pt2 = quads[i].corners[(k+1)%4]->pt;
pt2.x = (pt1.x + pt2.x)/2;
pt2.y = (pt1.y + pt2.y)/2;
if (k>0)
color = CV_RGB(200,200,0);
cvLine( dbg1_img, cvPointFrom32f(pt1), cvPointFrom32f(pt2), color, 3, 8);
}
}
cvShowImage("all_quads", (IplImage*)dbg1_img);
cvWaitKey();
#endif
if( quad_count <= 0 )
continue;
icvFindQuadNeighbors( quads, quad_count );
cvFree(&quad_group);
cvFree(&corner_group);
quad_group = (CvCBQuad**)cvAlloc( sizeof(quad_group[0]) * (quad_count+quad_count / 2));
corner_group = (CvCBCorner**)cvAlloc( sizeof(corner_group[0]) * (quad_count+quad_count / 2)*4 );
for( group_idx = 0; ; group_idx++ )
{
int count = 0;
count = icvFindConnectedQuads( quads, quad_count, quad_group, group_idx, storage );
int icount = count;
if( count == 0 )
break;
PRINTF("Starting ordering of inner quads\n");
count = icvOrderFoundConnectedQuads(count, quad_group, &quad_count, &quads, &corners,
pattern_size, storage );
PRINTF("Orig count: %d After ordering: %d\n", icount, count);
#ifdef DEBUG_CHESSBOARD
cvCopy(dbg_img,dbg2_img);
cvNamedWindow("connected_group", 1);
for(int i = 0; i < quad_count; i++ )
{
if (quads[i].group_idx == group_idx)
for (int k=0; k<4; k++)
{
CvPoint2D32f pt1, pt2;
CvScalar color = CV_RGB(30,255,30);
if (quads[i].ordered)
color = CV_RGB(255,30,30);
pt1 = quads[i].corners[k]->pt;
pt2 = quads[i].corners[(k+1)%4]->pt;
pt2.x = (pt1.x + pt2.x)/2;
pt2.y = (pt1.y + pt2.y)/2;
if (k>0)
color = CV_RGB(200,200,0);
cvLine( dbg2_img, cvPointFrom32f(pt1), cvPointFrom32f(pt2), color, 3, 8);
}
}
cvShowImage("connected_group", (IplImage*)dbg2_img);
cvWaitKey();
#endif
if (count == 0)
continue;
count = icvCleanFoundConnectedQuads( count, quad_group, pattern_size );
PRINTF("Connected group: %d orig count: %d cleaned: %d\n", group_idx, icount, count);
count = icvCheckQuadGroup( quad_group, count, corner_group, pattern_size );
PRINTF("Connected group: %d count: %d cleaned: %d\n", group_idx, icount, count);
{
int n = count > 0 ? pattern_size.width * pattern_size.height : -count;
n = MIN( n, pattern_size.width * pattern_size.height );
float sum_dist = 0;
int total = 0;
for(int i = 0; i < n; i++ )
{
int ni = 0;
float avgi = corner_group[i]->meanDist(&ni);
sum_dist += avgi*ni;
total += ni;
}
prev_sqr_size = cvRound(sum_dist/MAX(total, 1));
if( count > 0 || (out_corner_count && -count > *out_corner_count) )
{
for(int i = 0; i < n; i++ )
out_corners[i] = corner_group[i]->pt;
if( out_corner_count )
*out_corner_count = n;
if( count == pattern_size.width*pattern_size.height &&
icvCheckBoardMonotony( out_corners, pattern_size ))
{
found = 1;
break;
}
}
}
}
}
}
if( found )
found = icvCheckBoardMonotony( out_corners, pattern_size );
if( found )
{
const int BORDER = 8;
for( k = 0; k < pattern_size.width*pattern_size.height; k++ )
{
if( out_corners[k].x <= BORDER || out_corners[k].x > img->cols - BORDER ||
out_corners[k].y <= BORDER || out_corners[k].y > img->rows - BORDER )
break;
}
found = k == pattern_size.width*pattern_size.height;
}
if( found && pattern_size.height % 2 == 0 && pattern_size.width % 2 == 0 )
{
int last_row = (pattern_size.height-1)*pattern_size.width;
double dy0 = out_corners[last_row].y - out_corners[0].y;
if( dy0 < 0 )
{
int n = pattern_size.width*pattern_size.height;
for(int i = 0; i < n/2; i++ )
{
CvPoint2D32f temp;
CV_SWAP(out_corners[i], out_corners[n-i-1], temp);
}
}
}
if( found )
{
cv::Ptr<CvMat> gray;
if( CV_MAT_CN(img->type) != 1 )
{
gray.reset(cvCreateMat(img->rows, img->cols, CV_8UC1));
cvCvtColor(img, gray, CV_BGR2GRAY);
}
else
{
gray.reset(cvCloneMat(img));
}
int wsize = 2;
cvFindCornerSubPix( gray, out_corners, pattern_size.width*pattern_size.height,
cvSize(wsize, wsize), cvSize(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 15, 0.1));
}
}
catch(...)
{
cvFree(&quads);
cvFree(&corners);
cvFree(&quad_group);
cvFree(&corner_group);
throw;
}
cvFree(&quads);
cvFree(&corners);
cvFree(&quad_group);
cvFree(&corner_group);
return found;
}
static int
icvCheckBoardMonotony( CvPoint2D32f* corners, CvSize pattern_size )
{
int i, j, k;
for( k = 0; k < 2; k++ )
{
for( i = 0; i < (k == 0 ? pattern_size.height : pattern_size.width); i++ )
{
CvPoint2D32f a = k == 0 ? corners[i*pattern_size.width] : corners[i];
CvPoint2D32f b = k == 0 ? corners[(i+1)*pattern_size.width-1] :
corners[(pattern_size.height-1)*pattern_size.width + i];
float prevt = 0, dx0 = b.x - a.x, dy0 = b.y - a.y;
if( fabs(dx0) + fabs(dy0) < FLT_EPSILON )
return 0;
for( j = 1; j < (k == 0 ? pattern_size.width : pattern_size.height) - 1; j++ )
{
CvPoint2D32f c = k == 0 ? corners[i*pattern_size.width + j] :
corners[j*pattern_size.width + i];
float t = ((c.x - a.x)*dx0 + (c.y - a.y)*dy0)/(dx0*dx0 + dy0*dy0);
if( t < prevt || t > 1 )
return 0;
prevt = t;
}
}
}
return 1;
}
static int
icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads,
int *all_count, CvCBQuad **all_quads, CvCBCorner **corners,
CvSize pattern_size, CvMemStorage* storage )
{
cv::Ptr<CvMemStorage> temp_storage(cvCreateChildMemStorage( storage ));
CvSeq* stack = cvCreateSeq( 0, sizeof(*stack), sizeof(void*), temp_storage );
CvCBQuad *start = NULL;
for (int i=0; i<quad_count; i++)
{
if (quads[i]->count == 4)
{
start = quads[i];
break;
}
}
if (start == NULL)
return 0;
int row_min = 0, col_min = 0, row_max=0, col_max = 0;
std::map<int, int> col_hist;
std::map<int, int> row_hist;
cvSeqPush(stack, &start);
start->row = 0;
start->col = 0;
start->ordered = true;
while( stack->total )
{
CvCBQuad* q;
cvSeqPop( stack, &q );
int col = q->col;
int row = q->row;
col_hist[col]++;
row_hist[row]++;
if (row > row_max) row_max = row;
if (row < row_min) row_min = row;
if (col > col_max) col_max = col;
if (col < col_min) col_min = col;
for(int i = 0; i < 4; i++ )
{
CvCBQuad *neighbor = q->neighbors[i];
switch(i)
{
case 0:
row--; col--; break;
case 1:
col += 2; break;
case 2:
row += 2; break;
case 3:
col -= 2; break;
}
if (neighbor && neighbor->ordered == false && neighbor->count == 4)
{
PRINTF("col: %d row: %d\n", col, row);
icvOrderQuad(neighbor, q->corners[i], (i+2)%4);
neighbor->ordered = true;
neighbor->row = row;
neighbor->col = col;
cvSeqPush( stack, &neighbor );
}
}
}
for (int i=col_min; i<=col_max; i++)
PRINTF("HIST[%d] = %d\n", i, col_hist[i]);
int w = pattern_size.width - 1;
int h = pattern_size.height - 1;
int drow = row_max - row_min + 1;
int dcol = col_max - col_min + 1;
if ((w > h && dcol < drow) ||
(w < h && drow < dcol))
{
h = pattern_size.width - 1;
w = pattern_size.height - 1;
}
PRINTF("Size: %dx%d Pattern: %dx%d\n", dcol, drow, w, h);
if (dcol < w || drow < h)
{
PRINTF("Too few inner quad rows/cols\n");
return 0;
}
#ifdef ENABLE_TRIM_COL_ROW
if (dcol == w+1)
{
PRINTF("Trimming cols\n");
if (col_hist[col_max] > col_hist[col_min])
{
PRINTF("Trimming left col\n");
quad_count = icvTrimCol(quads,quad_count,col_min,-1);
}
else
{
PRINTF("Trimming right col\n");
quad_count = icvTrimCol(quads,quad_count,col_max,+1);
}
}
if (drow == h+1)
{
PRINTF("Trimming rows\n");
if (row_hist[row_max] > row_hist[row_min])
{
PRINTF("Trimming top row\n");
quad_count = icvTrimRow(quads,quad_count,row_min,-1);
}
else
{
PRINTF("Trimming bottom row\n");
quad_count = icvTrimRow(quads,quad_count,row_max,+1);
}
}
#endif
int found = 0;
for (int i=0; i<quad_count; i++)
{
if (quads[i]->count == 4)
{
int col = quads[i]->col;
int row = quads[i]->row;
for (int j=0; j<4; j++)
{
switch(j)
{
case 0:
row--; col--; break;
case 1:
col += 2; break;
case 2:
row += 2; break;
case 3:
col -= 2; break;
}
CvCBQuad *neighbor = quads[i]->neighbors[j];
if (neighbor && !neighbor->ordered &&
col <= col_max && col >= col_min &&
row <= row_max && row >= row_min)
{
PRINTF("Adding inner: col: %d row: %d\n", col, row);
found++;
icvOrderQuad(neighbor, quads[i]->corners[j], (j+2)%4);
neighbor->ordered = true;
neighbor->row = row;
neighbor->col = col;
}
}
}
}
if (found > 0)
{
PRINTF("Found %d inner quads not connected to outer quads, repairing\n", found);
for (int i=0; i<quad_count; i++)
{
if (quads[i]->count < 4 && quads[i]->ordered)
{
int added = icvAddOuterQuad(quads[i],quads,quad_count,all_quads,*all_count,corners);
*all_count += added;
quad_count += added;
}
}
}
if (dcol == w && drow == h)
{
PRINTF("Inner bounds ok, check outer quads\n");
int rcount = quad_count;
for (int i=quad_count-1; i>=0; i--)
{
if (quads[i]->ordered == false)
{
bool outer = false;
for (int j=0; j<4; j++)
{
if (quads[i]->neighbors[j] && quads[i]->neighbors[j]->ordered)
outer = true;
}
if (!outer)
{
PRINTF("Removing quad %d\n", i);
icvRemoveQuadFromGroup(quads,rcount,quads[i]);
rcount--;
}
}
}
return rcount;
}
return 0;
}
static int
icvAddOuterQuad( CvCBQuad *quad, CvCBQuad **quads, int quad_count,
CvCBQuad **all_quads, int all_count, CvCBCorner **corners )
{
int added = 0;
for (int i=0; i<4; i++)
{
if (!quad->neighbors[i])
{
int j = (i+2)%4;
PRINTF("Adding quad as neighbor 2\n");
CvCBQuad *q = &(*all_quads)[all_count];
memset( q, 0, sizeof(*q) );
added++;
quads[quad_count] = q;
quad_count++;
quad->neighbors[i] = q;
quad->count += 1;
q->neighbors[j] = quad;
q->group_idx = quad->group_idx;
q->count = 1;
q->ordered = false;
q->edge_len = quad->edge_len;
CvPoint2D32f pt = quad->corners[i]->pt;
CvCBCorner* corner;
float dx = pt.x - quad->corners[j]->pt.x;
float dy = pt.y - quad->corners[j]->pt.y;
for (int k=0; k<4; k++)
{
corner = &(*corners)[all_count*4+k];
pt = quad->corners[k]->pt;
memset( corner, 0, sizeof(*corner) );
corner->pt = pt;
q->corners[k] = corner;
corner->pt.x += dx;
corner->pt.y += dy;
}
q->corners[j] = quad->corners[i];
if (quad->neighbors[(i+3)%4] &&
quad->neighbors[(i+3)%4]->ordered &&
quad->neighbors[(i+3)%4]->neighbors[i] &&
quad->neighbors[(i+3)%4]->neighbors[i]->ordered )
{
CvCBQuad *qn = quad->neighbors[(i+3)%4]->neighbors[i];
q->count = 2;
q->neighbors[(j+1)%4] = qn;
qn->neighbors[(i+1)%4] = q;
qn->count += 1;
q->corners[(j+1)%4] = qn->corners[(i+1)%4];
}
all_count++;
}
}
return added;
}
#ifdef ENABLE_TRIM_COL_ROW
static int
icvTrimCol(CvCBQuad **quads, int count, int col, int dir)
{
int rcount = count;
for (int i=0; i<count; i++)
{
#ifdef DEBUG_CHESSBOARD
if (quads[i]->ordered)
PRINTF("index: %d cur: %d\n", col, quads[i]->col);
#endif
if (quads[i]->ordered && quads[i]->col == col)
{
if (dir == 1)
{
if (quads[i]->neighbors[1])
{
icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[1]);
rcount--;
}
if (quads[i]->neighbors[2])
{
icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[2]);
rcount--;
}
}
else
{
if (quads[i]->neighbors[0])
{
icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[0]);
rcount--;
}
if (quads[i]->neighbors[3])
{
icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[3]);
rcount--;
}
}
}
}
return rcount;
}
static int
icvTrimRow(CvCBQuad **quads, int count, int row, int dir)
{
int i, rcount = count;
for (i=0; i<count; i++)
{
#ifdef DEBUG_CHESSBOARD
if (quads[i]->ordered)
PRINTF("index: %d cur: %d\n", row, quads[i]->row);
#endif
if (quads[i]->ordered && quads[i]->row == row)
{
if (dir == 1)
{
if (quads[i]->neighbors[2])
{
icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[2]);
rcount--;
}
if (quads[i]->neighbors[3])
{
icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[3]);
rcount--;
}
}
else
{
if (quads[i]->neighbors[0])
{
icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[0]);
rcount--;
}
if (quads[i]->neighbors[1])
{
icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[1]);
rcount--;
}
}
}
}
return rcount;
}
#endif
static void
icvRemoveQuadFromGroup(CvCBQuad **quads, int count, CvCBQuad *q0)
{
int i, j;
for(i = 0; i < count; i++ )
{
CvCBQuad *q = quads[i];
for(j = 0; j < 4; j++ )
{
if( q->neighbors[j] == q0 )
{
q->neighbors[j] = 0;
q->count--;
for(int k = 0; k < 4; k++ )
if( q0->neighbors[k] == q )
{
q0->neighbors[k] = 0;
q0->count--;
break;
}
break;
}
}
}
for(i = 0; i < count; i++ )
{
CvCBQuad *q = quads[i];
if (q == q0)
{
quads[i] = quads[count-1];
break;
}
}
}
static void
icvOrderQuad(CvCBQuad *quad, CvCBCorner *corner, int common)
{
int tc;
for (tc=0; tc<4; tc++)
if (quad->corners[tc]->pt.x == corner->pt.x &&
quad->corners[tc]->pt.y == corner->pt.y)
break;
while (tc != common)
{
CvCBCorner *tempc;
CvCBQuad *tempq;
tempc = quad->corners[3];
tempq = quad->neighbors[3];
for (int i=3; i>0; i--)
{
quad->corners[i] = quad->corners[i-1];
quad->neighbors[i] = quad->neighbors[i-1];
}
quad->corners[0] = tempc;
quad->neighbors[0] = tempq;
tc++;
tc = tc%4;
}
}
static int
icvCleanFoundConnectedQuads( int quad_count, CvCBQuad **quad_group, CvSize pattern_size )
{
CvPoint2D32f center;
int i, j, k;
int count = ((pattern_size.width + 1)*(pattern_size.height + 1) + 1)/2;
if( quad_count <= count )
return quad_count;
cv::AutoBuffer<CvPoint2D32f> centers( quad_count );
cv::Ptr<CvMemStorage> temp_storage(cvCreateMemStorage(0));
for( i = 0; i < quad_count; i++ )
{
CvPoint2D32f ci;
CvCBQuad* q = quad_group[i];
for( j = 0; j < 4; j++ )
{
CvPoint2D32f pt = q->corners[j]->pt;
ci.x += pt.x;
ci.y += pt.y;
}
ci.x *= 0.25f;
ci.y *= 0.25f;
centers[i] = ci;
center.x += ci.x;
center.y += ci.y;
}
center.x /= quad_count;
center.y /= quad_count;
for( ; quad_count > count; quad_count-- )
{
double min_box_area = DBL_MAX;
int skip, min_box_area_index = -1;
for( skip = 0; skip < quad_count; skip++ )
{
CvPoint2D32f temp = centers[skip];
centers[skip] = center;
CvMat pointMat = cvMat(1, quad_count, CV_32FC2, centers);
CvSeq *hull = cvConvexHull2( &pointMat, temp_storage, CV_CLOCKWISE, 1 );
centers[skip] = temp;
double hull_area = fabs(cvContourArea(hull, CV_WHOLE_SEQ));
if( hull_area < min_box_area )
{
min_box_area = hull_area;
min_box_area_index = skip;
}
cvClearMemStorage( temp_storage );
}
CvCBQuad *q0 = quad_group[min_box_area_index];
for( i = 0; i < quad_count; i++ )
{
CvCBQuad *q = quad_group[i];
for( j = 0; j < 4; j++ )
{
if( q->neighbors[j] == q0 )
{
q->neighbors[j] = 0;
q->count--;
for( k = 0; k < 4; k++ )
if( q0->neighbors[k] == q )
{
q0->neighbors[k] = 0;
q0->count--;
break;
}
break;
}
}
}
quad_count--;
quad_group[min_box_area_index] = quad_group[quad_count];
centers[min_box_area_index] = centers[quad_count];
}
return quad_count;
}
static int
icvFindConnectedQuads( CvCBQuad *quad, int quad_count, CvCBQuad **out_group,
int group_idx, CvMemStorage* storage )
{
cv::Ptr<CvMemStorage> temp_storage(cvCreateChildMemStorage( storage ));
CvSeq* stack = cvCreateSeq( 0, sizeof(*stack), sizeof(void*), temp_storage );
int i, count = 0;
for( i = 0; i < quad_count; i++ )
{
if( quad[i].count > 0 && quad[i].group_idx < 0)
break;
}
if( i < quad_count )
{
CvCBQuad* q = &quad[i];
cvSeqPush( stack, &q );
out_group[count++] = q;
q->group_idx = group_idx;
q->ordered = false;
while( stack->total )
{
cvSeqPop( stack, &q );
for( i = 0; i < 4; i++ )
{
CvCBQuad *neighbor = q->neighbors[i];
if( neighbor && neighbor->count > 0 && neighbor->group_idx < 0 )
{
cvSeqPush( stack, &neighbor );
out_group[count++] = neighbor;
neighbor->group_idx = group_idx;
neighbor->ordered = false;
}
}
}
}
return count;
}
static int
icvCheckQuadGroup( CvCBQuad **quad_group, int quad_count,
CvCBCorner **out_corners, CvSize pattern_size )
{
const int ROW1 = 1000000;
const int ROW2 = 2000000;
const int ROW_ = 3000000;
int result = 0;
int i, out_corner_count = 0, corner_count = 0;
std::vector<CvCBCorner*> corners(quad_count*4);
int j, k, kk;
int width = 0, height = 0;
int hist[5] = {0,0,0,0,0};
CvCBCorner* first = 0, *first2 = 0, *right, *cur, *below, *c;
for( i = 0; i < quad_count; i++ )
{
CvCBQuad* q = quad_group[i];
for( j = 0; j < 4; j++ )
{
if( q->neighbors[j] )
{
CvCBCorner *a = q->corners[j], *b = q->corners[(j+1)&3];
int row_flag = q->count == 1 ? ROW1 : q->count == 2 ? ROW2 : ROW_;
if( a->row == 0 )
{
corners[corner_count++] = a;
a->row = row_flag;
}
else if( a->row > row_flag )
a->row = row_flag;
if( q->neighbors[(j+1)&3] )
{
if( a->count >= 4 || b->count >= 4 )
goto finalize;
for( k = 0; k < 4; k++ )
{
if( a->neighbors[k] == b )
goto finalize;
if( b->neighbors[k] == a )
goto finalize;
}
a->neighbors[a->count++] = b;
b->neighbors[b->count++] = a;
}
}
}
}
if( corner_count != pattern_size.width*pattern_size.height )
goto finalize;
for( i = 0; i < corner_count; i++ )
{
int n = corners[i]->count;
assert( 0 <= n && n <= 4 );
hist[n]++;
if( !first && n == 2 )
{
if( corners[i]->row == ROW1 )
first = corners[i];
else if( !first2 && corners[i]->row == ROW2 )
first2 = corners[i];
}
}
if( !first )
first = first2;
if( !first || hist[0] != 0 || hist[1] != 0 || hist[2] != 4 ||
hist[3] != (pattern_size.width + pattern_size.height)*2 - 8 )
goto finalize;
cur = first;
right = below = 0;
out_corners[out_corner_count++] = cur;
for( k = 0; k < 4; k++ )
{
c = cur->neighbors[k];
if( c )
{
if( !right )
right = c;
else if( !below )
below = c;
}
}
if( !right || (right->count != 2 && right->count != 3) ||
!below || (below->count != 2 && below->count != 3) )
goto finalize;
cur->row = 0;
first = below;
for(j=1;;j++)
{
right->row = 0;
out_corners[out_corner_count++] = right;
if( right->count == 2 )
break;
if( right->count != 3 || out_corner_count >= MAX(pattern_size.width,pattern_size.height) )
goto finalize;
cur = right;
for( k = 0; k < 4; k++ )
{
c = cur->neighbors[k];
if( c && c->row > 0 )
{
for( kk = 0; kk < 4; kk++ )
{
if( c->neighbors[kk] == below )
break;
}
if( kk < 4 )
below = c;
else
right = c;
}
}
}
width = out_corner_count;
if( width == pattern_size.width )
height = pattern_size.height;
else if( width == pattern_size.height )
height = pattern_size.width;
else
goto finalize;
for( i = 1; ; i++ )
{
if( !first )
break;
cur = first;
first = 0;
for( j = 0;; j++ )
{
cur->row = i;
out_corners[out_corner_count++] = cur;
if( cur->count == 2 + (i < height-1) && j > 0 )
break;
right = 0;
for( k = 0; k < 4; k++ )
{
c = cur->neighbors[k];
if( c && c->row > i )
{
for( kk = 0; kk < 4; kk++ )
{
if( c->neighbors[kk] && c->neighbors[kk]->row == i-1 )
break;
}
if( kk < 4 )
{
right = c;
if( j > 0 )
break;
}
else if( j == 0 )
first = c;
}
}
if( !right )
goto finalize;
cur = right;
}
if( j != width - 1 )
goto finalize;
}
if( out_corner_count != corner_count )
goto finalize;
if( width != pattern_size.width )
{
CV_SWAP( width, height, k );
memcpy( &corners[0], out_corners, corner_count*sizeof(corners[0]) );
for( i = 0; i < height; i++ )
for( j = 0; j < width; j++ )
out_corners[i*width + j] = corners[j*height + i];
}
{
CvPoint2D32f p0 = out_corners[0]->pt, p1 = out_corners[pattern_size.width-1]->pt,
p2 = out_corners[pattern_size.width]->pt;
if( (p1.x - p0.x)*(p2.y - p1.y) - (p1.y - p0.y)*(p2.x - p1.x) < 0 )
{
if( width % 2 == 0 )
{
for( i = 0; i < height; i++ )
for( j = 0; j < width/2; j++ )
CV_SWAP( out_corners[i*width+j], out_corners[i*width+width-j-1], c );
}
else
{
for( j = 0; j < width; j++ )
for( i = 0; i < height/2; i++ )
CV_SWAP( out_corners[i*width+j], out_corners[(height - i - 1)*width+j], c );
}
}
}
result = corner_count;
finalize:
if( result <= 0 )
{
corner_count = MIN( corner_count, pattern_size.width*pattern_size.height );
for( i = 0; i < corner_count; i++ )
out_corners[i] = corners[i];
result = -corner_count;
if (result == -pattern_size.width*pattern_size.height)
result = -result;
}
return result;
}
static void icvFindQuadNeighbors( CvCBQuad *quads, int quad_count )
{
const float thresh_scale = 1.f;
int idx, i, k, j;
float dx, dy, dist;
for( idx = 0; idx < quad_count; idx++ )
{
CvCBQuad* cur_quad = &quads[idx];
for( i = 0; i < 4; i++ )
{
CvPoint2D32f pt;
float min_dist = FLT_MAX;
int closest_corner_idx = -1;
CvCBQuad *closest_quad = 0;
CvCBCorner *closest_corner = 0;
if( cur_quad->neighbors[i] )
continue;
pt = cur_quad->corners[i]->pt;
for( k = 0; k < quad_count; k++ )
{
if( k == idx )
continue;
for( j = 0; j < 4; j++ )
{
if( quads[k].neighbors[j] )
continue;
dx = pt.x - quads[k].corners[j]->pt.x;
dy = pt.y - quads[k].corners[j]->pt.y;
dist = dx * dx + dy * dy;
if( dist < min_dist &&
dist <= cur_quad->edge_len*thresh_scale &&
dist <= quads[k].edge_len*thresh_scale )
{
float ediff = cur_quad->edge_len - quads[k].edge_len;
if (ediff > 32*cur_quad->edge_len ||
ediff > 32*quads[k].edge_len)
{
PRINTF("Incompatible edge lengths\n");
continue;
}
closest_corner_idx = j;
closest_quad = &quads[k];
min_dist = dist;
}
}
}
if( closest_corner_idx >= 0 && min_dist < FLT_MAX )
{
closest_corner = closest_quad->corners[closest_corner_idx];
for( j = 0; j < 4; j++ )
{
if( cur_quad->neighbors[j] == closest_quad )
break;
dx = closest_corner->pt.x - cur_quad->corners[j]->pt.x;
dy = closest_corner->pt.y - cur_quad->corners[j]->pt.y;
if( dx * dx + dy * dy < min_dist )
break;
}
if( j < 4 || cur_quad->count >= 4 || closest_quad->count >= 4 )
continue;
for( j = 0; j < closest_quad->count; j++ )
{
if( closest_quad->neighbors[j] == cur_quad )
break;
}
if( j < closest_quad->count )
continue;
for( k = 0; k < quad_count; k++ )
{
CvCBQuad* q = &quads[k];
if( k == idx || q == closest_quad )
continue;
for( j = 0; j < 4; j++ )
if( !q->neighbors[j] )
{
dx = closest_corner->pt.x - q->corners[j]->pt.x;
dy = closest_corner->pt.y - q->corners[j]->pt.y;
dist = dx*dx + dy*dy;
if( dist < min_dist )
break;
}
if( j < 4 )
break;
}
if( k < quad_count )
continue;
closest_corner->pt.x = (pt.x + closest_corner->pt.x) * 0.5f;
closest_corner->pt.y = (pt.y + closest_corner->pt.y) * 0.5f;
cur_quad->count++;
cur_quad->neighbors[i] = closest_quad;
cur_quad->corners[i] = closest_corner;
closest_quad->count++;
closest_quad->neighbors[closest_corner_idx] = cur_quad;
}
}
}
}
static int
icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
CvMemStorage *storage, CvMat *image, int flags )
{
int quad_count = 0;
cv::Ptr<CvMemStorage> temp_storage;
if( out_quads )
*out_quads = 0;
if( out_corners )
*out_corners = 0;
CvSeq *src_contour = 0;
CvSeq *root;
CvContourEx* board = 0;
CvContourScanner scanner;
int i, idx, min_size;
CV_Assert( out_corners && out_quads );
min_size = 25;
temp_storage.reset(cvCreateChildMemStorage( storage ));
root = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvSeq*), temp_storage );
scanner = cvStartFindContours( image, temp_storage, sizeof(CvContourEx),
CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
while( (src_contour = cvFindNextContour( scanner )) != 0 )
{
CvSeq *dst_contour = 0;
CvRect rect = ((CvContour*)src_contour)->rect;
if( CV_IS_SEQ_HOLE(src_contour) && rect.width*rect.height >= min_size )
{
const int min_approx_level = 1, max_approx_level = MAX_CONTOUR_APPROX;
int approx_level;
for( approx_level = min_approx_level; approx_level <= max_approx_level; approx_level++ )
{
dst_contour = cvApproxPoly( src_contour, sizeof(CvContour), temp_storage,
CV_POLY_APPROX_DP, (float)approx_level );
if( dst_contour->total == 4 )
break;
dst_contour = cvApproxPoly( dst_contour, sizeof(CvContour), temp_storage,
CV_POLY_APPROX_DP, (float)approx_level );
if( dst_contour->total == 4 )
break;
}
if( dst_contour->total == 4 && cvCheckContourConvexity(dst_contour) )
{
CvPoint pt[4];
double d1, d2, p = cvContourPerimeter(dst_contour);
double area = fabs(cvContourArea(dst_contour, CV_WHOLE_SEQ));
double dx, dy;
for( i = 0; i < 4; i++ )
pt[i] = *(CvPoint*)cvGetSeqElem(dst_contour, i);
dx = pt[0].x - pt[2].x;
dy = pt[0].y - pt[2].y;
d1 = sqrt(dx*dx + dy*dy);
dx = pt[1].x - pt[3].x;
dy = pt[1].y - pt[3].y;
d2 = sqrt(dx*dx + dy*dy);
double d3, d4;
dx = pt[0].x - pt[1].x;
dy = pt[0].y - pt[1].y;
d3 = sqrt(dx*dx + dy*dy);
dx = pt[1].x - pt[2].x;
dy = pt[1].y - pt[2].y;
d4 = sqrt(dx*dx + dy*dy);
if( !(flags & CV_CALIB_CB_FILTER_QUADS) ||
(d3*4 > d4 && d4*4 > d3 && d3*d4 < area*1.5 && area > min_size &&
d1 >= 0.15 * p && d2 >= 0.15 * p) )
{
CvContourEx* parent = (CvContourEx*)(src_contour->v_prev);
parent->counter++;
if( !board || board->counter < parent->counter )
board = parent;
dst_contour->v_prev = (CvSeq*)parent;
cvSeqPush( root, &dst_contour );
}
}
}
}
cvEndFindContours( &scanner );
*out_quads = (CvCBQuad*)cvAlloc((root->total+root->total / 2) * sizeof((*out_quads)[0]));
*out_corners = (CvCBCorner*)cvAlloc((root->total+root->total / 2) * 4 * sizeof((*out_corners)[0]));
for( idx = 0; idx < root->total; idx++ )
{
CvCBQuad* q = &(*out_quads)[quad_count];
src_contour = *(CvSeq**)cvGetSeqElem( root, idx );
if( (flags & CV_CALIB_CB_FILTER_QUADS) && src_contour->v_prev != (CvSeq*)board )
continue;
memset( q, 0, sizeof(*q) );
q->group_idx = -1;
assert( src_contour->total == 4 );
for( i = 0; i < 4; i++ )
{
CvPoint2D32f pt = cvPointTo32f(*(CvPoint*)cvGetSeqElem(src_contour, i));
CvCBCorner* corner = &(*out_corners)[quad_count*4 + i];
memset( corner, 0, sizeof(*corner) );
corner->pt = pt;
q->corners[i] = corner;
}
q->edge_len = FLT_MAX;
for( i = 0; i < 4; i++ )
{
float dx = q->corners[i]->pt.x - q->corners[(i+1)&3]->pt.x;
float dy = q->corners[i]->pt.y - q->corners[(i+1)&3]->pt.y;
float d = dx*dx + dy*dy;
if( q->edge_len > d )
q->edge_len = d;
}
quad_count++;
}
return quad_count;
}
CV_IMPL void
cvDrawChessboardCorners( CvArr* _image, CvSize pattern_size,
CvPoint2D32f* corners, int count, int found )
{
const int shift = 0;
const int radius = 4;
const int r = radius*(1 << shift);
int i;
CvMat stub, *image;
double scale = 1;
int type, cn, line_type;
image = cvGetMat( _image, &stub );
type = CV_MAT_TYPE(image->type);
cn = CV_MAT_CN(type);
if( cn != 1 && cn != 3 && cn != 4 )
CV_Error( CV_StsUnsupportedFormat, "Number of channels must be 1, 3 or 4" );
switch( CV_MAT_DEPTH(image->type) )
{
case CV_8U:
scale = 1;
break;
case CV_16U:
scale = 256;
break;
case CV_32F:
scale = 1./255;
break;
default:
CV_Error( CV_StsUnsupportedFormat,
"Only 8-bit, 16-bit or floating-point 32-bit images are supported" );
}
line_type = type == CV_8UC1 || type == CV_8UC3 ? CV_AA : 8;
if( !found )
{
CvScalar color(0,0,255,0);
if( cn == 1 )
color = cvScalarAll(200);
color.val[0] *= scale;
color.val[1] *= scale;
color.val[2] *= scale;
color.val[3] *= scale;
for( i = 0; i < count; i++ )
{
CvPoint pt;
pt.x = cvRound(corners[i].x*(1 << shift));
pt.y = cvRound(corners[i].y*(1 << shift));
cvLine( image, cvPoint( pt.x - r, pt.y - r ),
cvPoint( pt.x + r, pt.y + r ), color, 1, line_type, shift );
cvLine( image, cvPoint( pt.x - r, pt.y + r),
cvPoint( pt.x + r, pt.y - r), color, 1, line_type, shift );
cvCircle( image, pt, r+(1<<shift), color, 1, line_type, shift );
}
}
else
{
int x, y;
CvPoint prev_pt;
const int line_max = 7;
static const CvScalar line_colors[line_max] =
{
CvScalar(0,0,255),
CvScalar(0,128,255),
CvScalar(0,200,200),
CvScalar(0,255,0),
CvScalar(200,200,0),
CvScalar(255,0,0),
CvScalar(255,0,255)
};
for( y = 0, i = 0; y < pattern_size.height; y++ )
{
CvScalar color = line_colors[y % line_max];
if( cn == 1 )
color = cvScalarAll(200);
color.val[0] *= scale;
color.val[1] *= scale;
color.val[2] *= scale;
color.val[3] *= scale;
for( x = 0; x < pattern_size.width; x++, i++ )
{
CvPoint pt;
pt.x = cvRound(corners[i].x*(1 << shift));
pt.y = cvRound(corners[i].y*(1 << shift));
if( i != 0 )
cvLine( image, prev_pt, pt, color, 1, line_type, shift );
cvLine( image, cvPoint(pt.x - r, pt.y - r),
cvPoint(pt.x + r, pt.y + r), color, 1, line_type, shift );
cvLine( image, cvPoint(pt.x - r, pt.y + r),
cvPoint(pt.x + r, pt.y - r), color, 1, line_type, shift );
cvCircle( image, pt, r+(1<<shift), color, 1, line_type, shift );
prev_pt = pt;
}
}
}
}
bool cv::findChessboardCorners( InputArray _image, Size patternSize,
OutputArray corners, int flags )
{
int count = patternSize.area()*2;
std::vector<Point2f> tmpcorners(count+1);
Mat image = _image.getMat(); CvMat c_image = image;
bool ok = cvFindChessboardCorners(&c_image, patternSize,
(CvPoint2D32f*)&tmpcorners[0], &count, flags ) > 0;
if( count > 0 )
{
tmpcorners.resize(count);
Mat(tmpcorners).copyTo(corners);
}
else
corners.release();
return ok;
}
namespace
{
int quiet_error(int , const char* ,
const char* , const char* ,
int , void* )
{
return 0;
}
}
void cv::drawChessboardCorners( InputOutputArray _image, Size patternSize,
InputArray _corners,
bool patternWasFound )
{
Mat corners = _corners.getMat();
if( corners.empty() )
return;
Mat image = _image.getMat(); CvMat c_image = _image.getMat();
int nelems = corners.checkVector(2, CV_32F, true);
CV_Assert(nelems >= 0);
cvDrawChessboardCorners( &c_image, patternSize, corners.ptr<CvPoint2D32f>(),
nelems, patternWasFound );
}
bool cv::findCirclesGrid( InputArray _image, Size patternSize,
OutputArray _centers, int flags, const Ptr<FeatureDetector> &blobDetector )
{
bool isAsymmetricGrid = (flags & CALIB_CB_ASYMMETRIC_GRID) ? true : false;
bool isSymmetricGrid = (flags & CALIB_CB_SYMMETRIC_GRID ) ? true : false;
CV_Assert(isAsymmetricGrid ^ isSymmetricGrid);
Mat image = _image.getMat();
std::vector<Point2f> centers;
std::vector<KeyPoint> keypoints;
blobDetector->detect(image, keypoints);
std::vector<Point2f> points;
for (size_t i = 0; i < keypoints.size(); i++)
{
points.push_back (keypoints[i].pt);
}
if(flags & CALIB_CB_CLUSTERING)
{
CirclesGridClusterFinder circlesGridClusterFinder(isAsymmetricGrid);
circlesGridClusterFinder.findGrid(points, patternSize, centers);
Mat(centers).copyTo(_centers);
return !centers.empty();
}
CirclesGridFinderParameters parameters;
parameters.vertexPenalty = -0.6f;
parameters.vertexGain = 1;
parameters.existingVertexGain = 10000;
parameters.edgeGain = 1;
parameters.edgePenalty = -0.6f;
if(flags & CALIB_CB_ASYMMETRIC_GRID)
parameters.gridType = CirclesGridFinderParameters::ASYMMETRIC_GRID;
if(flags & CALIB_CB_SYMMETRIC_GRID)
parameters.gridType = CirclesGridFinderParameters::SYMMETRIC_GRID;
const int attempts = 2;
const size_t minHomographyPoints = 4;
Mat H;
for (int i = 0; i < attempts; i++)
{
centers.clear();
CirclesGridFinder boxFinder(patternSize, points, parameters);
bool isFound = false;
#define BE_QUIET 1
#if BE_QUIET
void* oldCbkData;
ErrorCallback oldCbk = redirectError(quiet_error, 0, &oldCbkData);
#endif
try
{
isFound = boxFinder.findHoles();
}
catch (const cv::Exception &)
{
}
#if BE_QUIET
redirectError(oldCbk, oldCbkData);
#endif
if (isFound)
{
switch(parameters.gridType)
{
case CirclesGridFinderParameters::SYMMETRIC_GRID:
boxFinder.getHoles(centers);
break;
case CirclesGridFinderParameters::ASYMMETRIC_GRID:
boxFinder.getAsymmetricHoles(centers);
break;
default:
CV_Error(CV_StsBadArg, "Unkown pattern type");
}
if (i != 0)
{
Mat orgPointsMat;
transform(centers, orgPointsMat, H.inv());
convertPointsFromHomogeneous(orgPointsMat, centers);
}
Mat(centers).copyTo(_centers);
return true;
}
boxFinder.getHoles(centers);
if (i != attempts - 1)
{
if (centers.size() < minHomographyPoints)
break;
H = CirclesGridFinder::rectifyGrid(boxFinder.getDetectedGridSize(), centers, points, points);
}
}
Mat(centers).copyTo(_centers);
return false;
}