@ -76,6 +76,9 @@
# include <stdarg.h>
# include <vector>
using namespace cv ;
using namespace std ;
//#define ENABLE_TRIM_COL_ROW
//#define DEBUG_CHESSBOARD
@ -88,13 +91,9 @@ static int PRINTF( const char* fmt, ... )
return vprintf ( fmt , args ) ;
}
# else
static int PRINTF ( const char * , . . . )
{
return 0 ;
}
# define PRINTF(...)
# endif
//=====================================================================================
// Implementation for the enhanced calibration object detection
//=====================================================================================
@ -155,10 +154,42 @@ struct CvCBQuad
//=====================================================================================
//static CvMat* debug_img = 0;
# ifdef DEBUG_CHESSBOARD
# include "opencv2/highgui.hpp"
# include "opencv2/imgproc.hpp"
static void SHOW ( const std : : string & name , Mat & img )
{
imshow ( name , img ) ;
while ( ( uchar ) waitKey ( 0 ) ! = ' q ' ) { }
}
static void SHOW_QUADS ( const std : : string & name , const Mat & img_ , CvCBQuad * quads , int quads_count )
{
Mat img = img_ . clone ( ) ;
if ( img . channels ( ) = = 1 )
cvtColor ( img , img , COLOR_GRAY2BGR ) ;
for ( int i = 0 ; i < quads_count ; + + i )
{
CvCBQuad & quad = quads [ i ] ;
for ( int j = 0 ; j < 4 ; + + j )
{
line ( img , quad . corners [ j ] - > pt , quad . corners [ ( j + 1 ) % 4 ] - > pt , Scalar ( 0 , 240 , 0 ) , 1 , LINE_AA ) ;
}
}
imshow ( name , img ) ;
while ( ( uchar ) waitKey ( 0 ) ! = ' q ' ) { }
}
# else
# define SHOW(...)
# define SHOW_QUADS(...)
# endif
//=====================================================================================
static int icvGenerateQuads ( CvCBQuad * * quads , CvCBCorner * * corners ,
CvMemStorage * storage , CvMat * image , int flags , int * max_quad_buf_size ) ;
CvMemStorage * storage , const Mat & image_ , int flags , int * max_quad_buf_size ) ;
static bool processQuads ( CvCBQuad * quads , int quad_count , CvSize pattern_size , int max_quad_buf_size ,
CvMemStorage * storage , CvCBCorner * corners , CvPoint2D32f * out_corners , int * out_corner_count , int & prev_sqr_size ) ;
/*static int
icvGenerateQuadsEx ( CvCBQuad * * out_quads , CvCBCorner * * out_corners ,
@ -195,35 +226,24 @@ static void icvRemoveQuadFromGroup(CvCBQuad **quads, int count, CvCBQuad *q0);
static int icvCheckBoardMonotony ( CvPoint2D32f * corners , CvSize pattern_size ) ;
int cvCheckChessboardBinary ( IplImage * src , CvSize size ) ;
/***************************************************************************************************/
//COMPUTE INTENSITY HISTOGRAM OF INPUT IMAGE
static int icvGetIntensityHistogram ( unsigned char * pucImage , int iSizeCols , int iSizeRows , std : : vector < int > & piHist ) ;
//SMOOTH HISTOGRAM USING WINDOW OF SIZE 2*iWidth+1
static int icvSmoothHistogram ( const std : : vector < int > & piHist , std : : vector < int > & piHistSmooth , int iWidth ) ;
//COMPUTE FAST HISTOGRAM GRADIENT
static int icvGradientOfHistogram ( const std : : vector < int > & piHist , std : : vector < int > & piHistGrad ) ;
//PERFORM SMART IMAGE THRESHOLDING BASED ON ANALYSIS OF INTENSTY HISTOGRAM
static bool icvBinarizationHistogramBased ( unsigned char * pucImg , int iCols , int iRows ) ;
/***************************************************************************************************/
int icvGetIntensityHistogram ( unsigned char * pucImage , int iSizeCols , int iSizeRows , std : : vector < int > & piHist )
static int icvGetIntensityHistogram ( const Mat & img , std : : vector < int > & piHist )
{
int iVal ;
// sum up all pixel in row direction and divide by number of columns
for ( int j = 0 ; j < iSizeR ows ; j + + )
for ( int j = 0 ; j < img . rows ; j + + )
{
for ( int i = 0 ; i < iSizeCols ; i + + )
const uchar * row = img . ptr ( j ) ;
for ( int i = 0 ; i < img . cols ; i + + )
{
iVal = ( int ) pucImage [ j * iSizeCols + i ] ;
piHist [ iVal ] + + ;
piHist [ row [ i ] ] + + ;
}
}
return 0 ;
}
/***************************************************************************************************/
int icvSmoothHistogram ( const std : : vector < int > & piHist , std : : vector < int > & piHistSmooth , int iWidth )
//SMOOTH HISTOGRAM USING WINDOW OF SIZE 2*iWidth+1
static int icvSmoothHistogram ( const std : : vector < int > & piHist , std : : vector < int > & piHistSmooth , int iWidth )
{
int iIdx ;
for ( int i = 0 ; i < 256 ; i + + )
@ -242,7 +262,8 @@ int icvSmoothHistogram( const std::vector<int>& piHist, std::vector<int>& piHist
return 0 ;
}
/***************************************************************************************************/
int icvGradientOfHistogram ( const std : : vector < int > & piHist , std : : vector < int > & piHistGrad )
//COMPUTE FAST HISTOGRAM GRADIENT
static int icvGradientOfHistogram ( const std : : vector < int > & piHist , std : : vector < int > & piHistGrad )
{
piHistGrad [ 0 ] = 0 ;
for ( int i = 1 ; i < 255 ; i + + )
@ -259,8 +280,12 @@ int icvGradientOfHistogram( const std::vector<int>& piHist, std::vector<int>& pi
return 0 ;
}
/***************************************************************************************************/
bool icvBinarizationHistogramBased ( unsigned char * pucImg , int iCols , int iRows )
//PERFORM SMART IMAGE THRESHOLDING BASED ON ANALYSIS OF INTENSTY HISTOGRAM
static bool icvBinarizationHistogramBased ( Mat & img )
{
CV_Assert ( img . channels ( ) = = 1 & & img . depth ( ) = = CV_8U ) ;
int iCols = img . cols ;
int iRows = img . rows ;
int iMaxPix = iCols * iRows ;
int iMaxPix1 = iMaxPix / 100 ;
const int iNumBins = 256 ;
@ -273,7 +298,7 @@ bool icvBinarizationHistogramBased( unsigned char* pucImg, int iCols, int iRows
int iIdx ;
int iWidth = 1 ;
icvGetIntensityHistogram ( pucImg , iCols , iRows , piHistIntensity ) ;
icvGetIntensityHistogram ( img , piHistIntensity ) ;
// get accumulated sum starting from bright
piAccumSum [ iNumBins - 1 ] = piHistIntensity [ iNumBins - 1 ] ;
@ -381,12 +406,13 @@ bool icvBinarizationHistogramBased( unsigned char* pucImg, int iCols, int iRows
{
for ( int jj = 0 ; jj < iRows ; jj + + )
{
uchar * row = img . ptr ( jj ) ;
for ( int ii = 0 ; ii < iCols ; ii + + )
{
if ( pucImg [ jj * iCols + ii ] < iThresh )
pucImg [ jj * iCols + ii ] = 0 ;
if ( row [ ii ] < iThresh )
row [ ii ] = 0 ;
else
pucImg [ jj * iCols + ii ] = 255 ;
row [ ii ] = 255 ;
}
}
}
@ -400,38 +426,23 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
int flags )
{
int found = 0 ;
CvCBQuad * quads = 0 , * * quad_group = 0 ;
CvCBCorner * corners = 0 , * * corner_group = 0 ;
IplImage * cImgSeg = 0 ;
CvCBQuad * quads = 0 ;
CvCBCorner * corners = 0 ;
cv : : Ptr < CvMemStorage > storage ;
try
{
int k = 0 ;
const int min_dilations = 0 ;
const int max_dilations = 7 ;
cv : : Ptr < CvMat > norm_img , thresh_img ;
cv : : Ptr < CvMemStorage > storage ;
CvMat stub , * img = ( CvMat * ) arr ;
cImgSeg = cvCreateImage ( cvGetSize ( img ) , IPL_DEPTH_8U , 1 ) ;
memcpy ( cImgSeg - > imageData , cvPtr1D ( img , 0 ) , img - > rows * img - > cols ) ;
CvMat stub2 , * thresh_img_new ;
thresh_img_new = cvGetMat ( cImgSeg , & stub2 , 0 , 0 ) ;
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 ;
int quad_count = 0 , group_idx = 0 , dilations = 0 ;
img = cvGetMat ( img , & stub ) ;
//debug_img = img;
Mat img = cvarrToMat ( ( CvMat * ) arr ) . clone ( ) ;
if ( CV_MAT_DEPTH ( img - > type ) ! = CV_8U | | CV_MAT_CN ( img - > type ) = = 2 )
if ( img . depth ( ) ! = CV_8U | | ( img . channels ( ) ! = 1 & & img . channels ( ) ! = 3 ) )
CV_Error ( CV_StsUnsupportedFormat , " Only 8-bit grayscale or color images are supported " ) ;
if ( pattern_size . width < = 2 | | pattern_size . height < = 2 )
@ -440,273 +451,124 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
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 ) ) ;
if ( CV_MAT_CN ( img - > type ) ! = 1 | | ( flags & CV_CALIB_CB_NORMALIZE_IMAGE ) )
if ( img . channels ( ) ! = 1 )
{
// equalize the input image histogram -
// that should make the contrast between "black" and "white" areas big enough
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 ;
cvtColor ( img , img , COLOR_BGR2GRAY ) ;
}
if ( flags & CV_CALIB_CB_NORMALIZE_IMAGE )
{
cvEqualizeHist ( img , norm_img ) ;
img = norm_img ;
}
}
Mat thresh_img_new = img . clone ( ) ;
icvBinarizationHistogramBased ( thresh_img_new ) ; // process image in-place
SHOW ( " New binarization " , thresh_img_new ) ;
if ( flags & CV_CALIB_CB_FAST_CHECK )
{
//perform new method for checking chessboard using a binary image.
//image is binarised using a threshold dependent on the image histogram
icvBinarizationHistogramBased ( ( unsigned char * ) cImgSeg - > imageData , cImgSeg - > width , cImgSeg - > height ) ;
int check_chessboard_result = cvCheckChessboardBinary ( cImgSeg , pattern_size ) ;
if ( check_chessboard_result < = 0 ) //fall back to the old method
if ( checkChessboardBinary ( thresh_img_new , pattern_size ) < = 0 ) //fall back to the old method
{
IplImage _img ;
cvGetImage ( img , & _img ) ;
check_chessboard_result = cvCheckChessboard ( & _img , pattern_size ) ;
if ( check_chessboard_result < = 0 )
if ( checkChessboard ( img , pattern_size ) < = 0 )
{
return 0 ;
return found ;
}
}
}
storage . reset ( cvCreateMemStorage ( 0 ) ) ;
int prev_sqr_size = 0 ;
// Try our standard "1" dilation, but if the pattern is not found, iterate the whole procedure with higher dilations.
// This is necessary because some squares simply do not separate properly with a single dilation. However,
// we want to use the minimum number of dilations possible since dilations cause the squares to become smaller,
// making it difficult to detect smaller squares.
for ( dilations = min_dilations ; dilations < = max_dilations ; dilations + + )
for ( int dilations = min_dilations ; dilations < = max_dilations ; dilations + + )
{
if ( found )
break ; // already found it
cvFree ( & quads ) ;
cvFree ( & corners ) ;
int max_quad_buf_size = 0 ;
//USE BINARY IMAGE COMPUTED USING icvBinarizationHistogramBased METHOD
cvD ilate( thresh_img_new , thresh_img_new , 0 , 1 ) ;
dilate ( thresh_img_new , thresh_img_new , Mat ( ) , Point ( - 1 , - 1 ) , 1 ) ;
// So we can find rectangles that go to the edge, we draw a white line around the image edge.
// Otherwise FindContours will miss those clipped rectangle contours.
// The border color will be the image mean, because otherwise we risk screwing up filters like cvSmooth()...
cvRectangle ( thresh_img_new , cvPoint ( 0 , 0 ) , cvPoint ( thresh_img_new - > cols - 1 , thresh_img_new - > rows - 1 ) , CV_RGB ( 255 , 255 , 255 ) , 3 , 8 ) ;
quad_count = icvGenerateQuads ( & quads , & corners , storage , thresh_img_new , flags , & max_quad_buf_size ) ;
PRINTF ( " Quad count: %d/%d \n " , quad_count , expected_corners_num ) ;
if ( quad_count < = 0 )
{
continue ;
}
// Find quad's neighbors
icvFindQuadNeighbors ( quads , quad_count ) ;
// allocate extra for adding in icvOrderFoundQuads
cvFree ( & quad_group ) ;
cvFree ( & corner_group ) ;
quad_group = ( CvCBQuad * * ) cvAlloc ( sizeof ( quad_group [ 0 ] ) * max_quad_buf_size ) ;
corner_group = ( CvCBCorner * * ) cvAlloc ( sizeof ( corner_group [ 0 ] ) * max_quad_buf_size * 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 ;
// order the quad corners globally
// maybe delete or add some
PRINTF ( " Starting ordering of inner quads \n " ) ;
count = icvOrderFoundConnectedQuads ( count , quad_group , & quad_count , & quads , & corners , pattern_size , max_quad_buf_size , storage ) ;
PRINTF ( " Orig count: %d After ordering: %d \n " , icount , count ) ;
if ( count = = 0 )
continue ; // haven't found inner quads
// If count is more than it should be, this will remove those quads
// which cause maximum deviation from a nice square pattern.
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 ) )
{
// copy corners to output array
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 ) )
{
rectangle ( thresh_img_new , Point ( 0 , 0 ) , Point ( thresh_img_new . cols - 1 , thresh_img_new . rows - 1 ) , Scalar ( 255 , 255 , 255 ) , 3 , LINE_8 ) ;
int max_quad_buf_size = 0 ;
cvFree ( & quads ) ;
cvFree ( & corners ) ;
int quad_count = icvGenerateQuads ( & quads , & corners , storage , thresh_img_new , flags , & max_quad_buf_size ) ;
PRINTF ( " Quad count: %d/%d \n " , quad_count , ( pattern_size . width / 2 + 1 ) * ( pattern_size . height / 2 + 1 ) ) ;
SHOW_QUADS ( " New quads " , thresh_img_new , quads , quad_count ) ;
if ( processQuads ( quads , quad_count , pattern_size , max_quad_buf_size , storage , corners , out_corners , out_corner_count , prev_sqr_size ) )
found = 1 ;
break ;
}
}
}
} //dilations
PRINTF ( " Chessboard detection result 0: %d \n " , found ) ;
// revert to old, slower, method if detection failed
if ( ! found )
{
if ( flags & CV_CALIB_CB_NORMALIZE_IMAGE )
{
equalizeHist ( img , img ) ;
}
Mat thresh_img ;
prev_sqr_size = 0 ;
PRINTF ( " Fallback to old algorithm \n " ) ;
const bool useAdaptive = flags & CV_CALIB_CB_ADAPTIVE_THRESH ;
if ( ! useAdaptive )
{
// empiric threshold level
// thresholding performed here and not inside the cycle to save processing time
int thresh_level ;
if ( ! ( flags & CV_CALIB_CB_ADAPTIVE_THRESH ) )
{
double mean = cvAvg ( img ) . val [ 0 ] ;
thresh_level = cvRound ( mean - 10 ) ;
thresh_level = MAX ( thresh_level , 10 ) ;
cvThreshold ( img , thresh_img , thresh_level , 255 , CV_THRESH_BINARY ) ;
double mean = cv : : mean ( img ) . val [ 0 ] ;
int thresh_level = MAX ( cvRound ( mean - 10 ) , 10 ) ;
threshold ( img , thresh_img , thresh_level , 255 , THRESH_BINARY ) ;
}
for ( k = 0 ; k < 6 ; k + + )
//if flag CV_CALIB_CB_ADAPTIVE_THRESH is not set it doesn't make sense to iterate over k
int max_k = useAdaptive ? 6 : 1 ;
for ( k = 0 ; k < max_k ; k + + )
{
int max_quad_buf_size = 0 ;
for ( dilations = min_dilations ; dilations < = max_dilations ; dilations + + )
for ( int dilations = min_dilations ; dilations < = max_dilations ; dilations + + )
{
if ( found )
break ; // already found it
cvFree ( & quads ) ;
cvFree ( & corners ) ;
// convert the input grayscale image to binary (black-n-white)
if ( flags & CV_CALIB_CB_ADAPTIVE_THRESH )
if ( useAdaptive )
{
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 ;
int block_size = cvRound ( prev_sqr_size = = 0
? MIN ( img . cols , img . rows ) * ( k % 2 = = 0 ? 0.2 : 0.1 )
: prev_sqr_size * 2 ) ;
block_size = block_size | 1 ;
// convert to binary
cvAdaptiveThreshold ( img , thresh_img , 255 ,
CV_ADAPTIVE_THRESH_MEAN_C , CV_THRESH_BINARY , block_size , ( k / 2 ) * 5 ) ;
adaptiveThreshold ( img , thresh_img , 255 , ADAPTIVE_THRESH_MEAN_C , THRESH_BINARY , block_size , ( k / 2 ) * 5 ) ;
if ( dilations > 0 )
cvDilate ( thresh_img , thresh_img , 0 , dilations - 1 ) ;
dilate ( thresh_img , thresh_img , Mat ( ) , Point ( - 1 , - 1 ) , dilations - 1 ) ;
}
//if flag CV_CALIB_CB_ADAPTIVE_THRESH is not set it doesn't make sense
//to iterate over k
else
{
k = 6 ;
cvDilate ( thresh_img , thresh_img , 0 , 1 ) ;
dilate ( thresh_img , thresh_img , Mat ( ) , Point ( - 1 , - 1 ) , 1 ) ;
}
SHOW ( " Old binarization " , thresh_img ) ;
// So we can find rectangles that go to the edge, we draw a white line around the image edge.
// Otherwise FindContours will miss those clipped rectangle contours.
// The border color will be the image mean, because otherwise we risk screwing up filters like cvSmooth()...
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 , & max_quad_buf_size ) ;
PRINTF ( " Quad count: %d/%d \n " , quad_count , expected_corners_num ) ;
if ( quad_count < = 0 )
{
continue ;
}
// Find quad's neighbors
icvFindQuadNeighbors ( quads , quad_count ) ;
// allocate extra for adding in icvOrderFoundQuads
cvFree ( & quad_group ) ;
cvFree ( & corner_group ) ;
quad_group = ( CvCBQuad * * ) cvAlloc ( sizeof ( quad_group [ 0 ] ) * max_quad_buf_size ) ;
corner_group = ( CvCBCorner * * ) cvAlloc ( sizeof ( corner_group [ 0 ] ) * max_quad_buf_size * 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 ;
// order the quad corners globally
// maybe delete or add some
PRINTF ( " Starting ordering of inner quads \n " ) ;
count = icvOrderFoundConnectedQuads ( count , quad_group , & quad_count , & quads , & corners , pattern_size , max_quad_buf_size , storage ) ;
PRINTF ( " Orig count: %d After ordering: %d \n " , icount , count ) ;
if ( count = = 0 )
continue ; // haven't found inner quads
// If count is more than it should be, this will remove those quads
// which cause maximum deviation from a nice square pattern.
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 ) )
{
// copy corners to output array
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 ) )
{
rectangle ( thresh_img , Point ( 0 , 0 ) , Point ( thresh_img . cols - 1 , thresh_img . rows - 1 ) , Scalar ( 255 , 255 , 255 ) , 3 , LINE_8 ) ;
int max_quad_buf_size = 0 ;
cvFree ( & quads ) ;
cvFree ( & corners ) ;
int quad_count = icvGenerateQuads ( & quads , & corners , storage , thresh_img , flags , & max_quad_buf_size ) ;
PRINTF ( " Quad count: %d/%d \n " , quad_count , ( pattern_size . width / 2 + 1 ) * ( pattern_size . height / 2 + 1 ) ) ;
SHOW_QUADS ( " Old quads " , thresh_img , quads , quad_count ) ;
if ( processQuads ( quads , quad_count , pattern_size , max_quad_buf_size , storage , corners , out_corners , out_corner_count , prev_sqr_size ) )
found = 1 ;
break ;
}
}
}
} //dilations
} // for k = 0 -> 6
}
PRINTF ( " Chessboard detection result 1: %d \n " , found ) ;
@ -722,8 +584,8 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
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 )
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 ;
}
@ -748,18 +610,9 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
}
}
}
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 ,
CvMat old_img ( img ) ;
cvFindCornerSubPix ( & old_img , out_corners , pattern_size . width * pattern_size . height ,
cvSize ( wsize , wsize ) , cvSize ( - 1 , - 1 ) ,
cvTermCriteria ( CV_TERMCRIT_EPS + CV_TERMCRIT_ITER , 15 , 0.1 ) ) ;
}
@ -768,17 +621,10 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
{
cvFree ( & quads ) ;
cvFree ( & corners ) ;
cvFree ( & quad_group ) ;
cvFree ( & corner_group ) ;
cvFree ( & cImgSeg ) ;
throw ;
}
cvFree ( & quads ) ;
cvFree ( & corners ) ;
cvFree ( & quad_group ) ;
cvFree ( & corner_group ) ;
cvFree ( & cImgSeg ) ;
return found ;
}
@ -1866,8 +1712,9 @@ static void icvFindQuadNeighbors( CvCBQuad *quads, int quad_count )
static int
icvGenerateQuads ( CvCBQuad * * out_quads , CvCBCorner * * out_corners ,
CvMemStorage * storage , CvMat * image , int flags , int * max_quad_buf_size )
CvMemStorage * storage , const cv : : Mat & image_ , int flags , int * max_quad_buf_size )
{
CvMat image_old ( image_ ) , * image = & image_old ;
int quad_count = 0 ;
cv : : Ptr < CvMemStorage > temp_storage ;
@ -2011,6 +1858,88 @@ icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
return quad_count ;
}
static bool processQuads ( CvCBQuad * quads , int quad_count , CvSize pattern_size , int max_quad_buf_size ,
CvMemStorage * storage , CvCBCorner * corners , CvPoint2D32f * out_corners , int * out_corner_count , int & prev_sqr_size )
{
if ( quad_count < = 0 )
return false ;
bool found = false ;
// Find quad's neighbors
icvFindQuadNeighbors ( quads , quad_count ) ;
// allocate extra for adding in icvOrderFoundQuads
CvCBQuad * * quad_group = 0 ;
CvCBCorner * * corner_group = 0 ;
quad_group = ( CvCBQuad * * ) cvAlloc ( sizeof ( quad_group [ 0 ] ) * max_quad_buf_size ) ;
corner_group = ( CvCBCorner * * ) cvAlloc ( sizeof ( corner_group [ 0 ] ) * max_quad_buf_size * 4 ) ;
for ( int group_idx = 0 ; ; group_idx + + )
{
int count = icvFindConnectedQuads ( quads , quad_count , quad_group , group_idx , storage ) ;
if ( count = = 0 )
break ;
// order the quad corners globally
// maybe delete or add some
PRINTF ( " Starting ordering of inner quads (%d) \n " , count ) ;
count = icvOrderFoundConnectedQuads ( count , quad_group , & quad_count , & quads , & corners ,
pattern_size , max_quad_buf_size , storage ) ;
PRINTF ( " Finished ordering of inner quads (%d) \n " , count ) ;
if ( count = = 0 )
continue ; // haven't found inner quads
// If count is more than it should be, this will remove those quads
// which cause maximum deviation from a nice square pattern.
count = icvCleanFoundConnectedQuads ( count , quad_group , pattern_size ) ;
PRINTF ( " Connected group: %d, count: %d \n " , group_idx , count ) ;
count = icvCheckQuadGroup ( quad_group , count , corner_group , pattern_size ) ;
PRINTF ( " Connected group: %d, count: %d \n " , group_idx , 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 ) )
{
// copy corners to output array
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 = true ;
break ;
}
}
}
cvFree ( & quad_group ) ;
cvFree ( & corner_group ) ;
return found ;
}
//==================================================================================================
CV_IMPL void
cvDrawChessboardCorners ( CvArr * _image , CvSize pattern_size ,