\************************************************************************************/
+/************************************************************************************\
+ This version adds a new and improved variant of chessboard corner detection
+ that works better in poor lighting condition. It is based on work from
+ Oliver Schreer and Stefano Masneri. This method works faster than the previous
+ one and reverts back to the older method in case no chessboard detection is
+ possible. Overall performance improves also because now the method avoids
+ performing the same computation multiple times when not necessary.
+
+\************************************************************************************/
+
#include "precomp.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/calib3d/calib3d_c.h"
#include "circlesgrid.hpp"
#include <stdarg.h>
+#include <vector>
//#define ENABLE_TRIM_COL_ROW
static int icvCheckBoardMonotony( CvPoint2D32f* corners, CvSize pattern_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 )
+{
+ int iVal;
+
+ // sum up all pixel in row direction and divide by number of columns
+ for ( int j=0; j<iSizeRows; j++ )
+ {
+ for ( int i=0; i<iSizeCols; i++ )
+ {
+ iVal = (int)pucImage[j*iSizeCols+i];
+ piHist[iVal]++;
+ }
+ }
+ return 0;
+}
+/***************************************************************************************************/
+int icvSmoothHistogram( const std::vector<int>& piHist, std::vector<int>& piHistSmooth, int iWidth )
+{
+ int iIdx;
+ for ( int i=0; i<256; i++)
+ {
+ int iSmooth = 0;
+ for ( int ii=-iWidth; ii<=iWidth; ii++)
+ {
+ iIdx = i+ii;
+ if (iIdx > 0 && iIdx < 256)
+ {
+ iSmooth += piHist[iIdx];
+ }
+ }
+ piHistSmooth[i] = iSmooth/(2*iWidth+1);
+ }
+ return 0;
+}
+/***************************************************************************************************/
+int icvGradientOfHistogram( const std::vector<int>& piHist, std::vector<int>& piHistGrad )
+{
+ piHistGrad[0] = 0;
+ for ( int i=1; i<255; i++)
+ {
+ piHistGrad[i] = piHist[i-1] - piHist[i+1];
+ if ( abs(piHistGrad[i]) < 100 )
+ {
+ if ( piHistGrad[i-1] == 0)
+ piHistGrad[i] = -100;
+ else
+ piHistGrad[i] = piHistGrad[i-1];
+ }
+ }
+ return 0;
+}
+/***************************************************************************************************/
+bool icvBinarizationHistogramBased( unsigned char* pucImg, int iCols, int iRows )
+{
+ int iMaxPix = iCols*iRows;
+ int iMaxPix1 = iMaxPix/100;
+ const int iNumBins = 256;
+ std::vector<int> piHistIntensity(iNumBins, 0);
+ std::vector<int> piHistSmooth(iNumBins, 0);
+ std::vector<int> piHistGrad(iNumBins, 0);
+ std::vector<int> piAccumSum(iNumBins, 0);
+ std::vector<int> piMaxPos(20, 0);
+ int iThresh = 0;
+ int iIdx;
+ int iWidth = 1;
+
+ icvGetIntensityHistogram( pucImg, iCols, iRows, piHistIntensity );
+
+ // get accumulated sum starting from bright
+ piAccumSum[iNumBins-1] = piHistIntensity[iNumBins-1];
+ for ( int i=iNumBins-2; i>=0; i-- )
+ {
+ piAccumSum[i] = piHistIntensity[i] + piAccumSum[i+1];
+ }
+
+ // first smooth the distribution
+ icvSmoothHistogram( piHistIntensity, piHistSmooth, iWidth );
+
+ // compute gradient
+ icvGradientOfHistogram( piHistSmooth, piHistGrad );
+
+ // check for zeros
+ int iCntMaxima = 0;
+ for ( int i=iNumBins-2; (i>2) && (iCntMaxima<20); i--)
+ {
+ if ( (piHistGrad[i-1] < 0) && (piHistGrad[i] > 0) )
+ {
+ piMaxPos[iCntMaxima] = i;
+ iCntMaxima++;
+ }
+ }
+
+ iIdx = 0;
+ int iSumAroundMax = 0;
+ for ( int i=0; i<iCntMaxima; i++ )
+ {
+ iIdx = piMaxPos[i];
+ iSumAroundMax = piHistSmooth[iIdx-1] + piHistSmooth[iIdx] + piHistSmooth[iIdx+1];
+ if ( iSumAroundMax < iMaxPix1 && iIdx < 64 )
+ {
+ for ( int j=i; j<iCntMaxima-1; j++ )
+ {
+ piMaxPos[j] = piMaxPos[j+1];
+ }
+ iCntMaxima--;
+ i--;
+ }
+ }
+ if ( iCntMaxima == 1)
+ {
+ iThresh = piMaxPos[0]/2;
+ }
+ else if ( iCntMaxima == 2)
+ {
+ iThresh = (piMaxPos[0] + piMaxPos[1])/2;
+ }
+ else // iCntMaxima >= 3
+ {
+ // CHECKING THRESHOLD FOR WHITE
+ int iIdxAccSum = 0, iAccum = 0;
+ for (int i=iNumBins-1; i>0; i--)
+ {
+ iAccum += piHistIntensity[i];
+ // iMaxPix/18 is about 5,5%, minimum required number of pixels required for white part of chessboard
+ if ( iAccum > (iMaxPix/18) )
+ {
+ iIdxAccSum = i;
+ break;
+ }
+ }
+
+ int iIdxBGMax = 0;
+ int iBrightMax = piMaxPos[0];
+ // printf("iBrightMax = %d\n", iBrightMax);
+ for ( int n=0; n<iCntMaxima-1; n++)
+ {
+ iIdxBGMax = n+1;
+ if ( piMaxPos[n] < iIdxAccSum )
+ {
+ break;
+ }
+ iBrightMax = piMaxPos[n];
+ }
+
+ // CHECKING THRESHOLD FOR BLACK
+ int iMaxVal = piHistIntensity[piMaxPos[iIdxBGMax]];
+
+ //IF TOO CLOSE TO 255, jump to next maximum
+ if ( piMaxPos[iIdxBGMax] >= 250 && iIdxBGMax < iCntMaxima )
+ {
+ iIdxBGMax++;
+ iMaxVal = piHistIntensity[piMaxPos[iIdxBGMax]];
+ }
+
+ for ( int n=iIdxBGMax + 1; n<iCntMaxima; n++)
+ {
+ if ( piHistIntensity[piMaxPos[n]] >= iMaxVal )
+ {
+ iMaxVal = piHistIntensity[piMaxPos[n]];
+ iIdxBGMax = n;
+ }
+ }
+
+ //SETTING THRESHOLD FOR BINARIZATION
+ int iDist2 = (iBrightMax - piMaxPos[iIdxBGMax])/2;
+ iThresh = iBrightMax - iDist2;
+ PRINTF("THRESHOLD SELECTED = %d, BRIGHTMAX = %d, DARKMAX = %d\n", iThresh, iBrightMax, piMaxPos[iIdxBGMax]);
+ }
+
+
+ if ( iThresh > 0 )
+ {
+ for ( int jj=0; jj<iRows; jj++)
+ {
+ for ( int ii=0; ii<iCols; ii++)
+ {
+ if ( pucImg[jj*iCols+ii]< iThresh )
+ pucImg[jj*iCols+ii] = 0;
+ else
+ pucImg[jj*iCols+ii] = 255;
+ }
+ }
+ }
+
+ return true;
+}
#if 0
static void
icvCalcAffineTranf2D32f(CvPoint2D32f* pts1, CvPoint2D32f* pts2, int count, CvMat* affine_trans)
int found = 0;
CvCBQuad *quads = 0, **quad_group = 0;
CvCBCorner *corners = 0, **corner_group = 0;
+ IplImage* cImgSeg = 0;
try
{
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);
if( out_corner_count )
*out_corner_count = 0;
- IplImage _img;
int quad_count = 0, group_idx = 0, dilations = 0;
img = cvGetMat( img, &stub );
if( flags & CV_CALIB_CB_FAST_CHECK)
{
- cvGetImage(img, &_img);
- int check_chessboard_result = cvCheckChessboard(&_img, pattern_size);
- if(check_chessboard_result <= 0)
+ //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 );
+ check_chessboard_result = cvCheckChessboardBinary(cImgSeg, pattern_size);
+ if(check_chessboard_result <= 0) //fall back to the old method
{
- return 0;
+ IplImage _img;
+ cvGetImage(img, &_img);
+ check_chessboard_result = cvCheckChessboard(&_img, pattern_size);
+ if(check_chessboard_result <= 0)
+ {
+ return 0;
+ }
}
}
+ // 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 );
+ }
// 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( k = 0; k < 6; k++ )
+ for( dilations = min_dilations; dilations <= max_dilations; dilations++ )
{
- int max_quad_buf_size = 0;
- for( dilations = min_dilations; dilations <= max_dilations; dilations++ )
- {
- if (found)
- break; // already found it
+ if (found)
+ break; // already found it
- cvFree(&quads);
- cvFree(&corners);
+ cvFree(&quads);
+ cvFree(&corners);
- /*if( k == 1 )
- {
- //Pattern was not found using binarization
- // Run multi-level quads extraction
- // In case one-level binarization did not give enough number of quads
- CV_CALL( quad_count = icvGenerateQuadsEx( &quads, &corners, storage, img, thresh_img, dilations, flags ));
- PRINTF("EX quad count: %d/%d\n", quad_count, expected_corners_num);
- }
- else*/
- {
- // convert the input grayscale image to binary (black-n-white)
- 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;
-
- // convert to binary
- 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
- {
- // Make dilation before the thresholding.
- // It splits chessboard corners
- //cvDilate( img, thresh_img, 0, 1 );
+ //USE BINARY IMAGE COMPUTED USING icvBinarizationHistogramBased METHOD
+ cvDilate( thresh_img_new, thresh_img_new, 0, 1 );
- // empiric threshold level
- double mean = cvAvg( img ).val[0];
- int thresh_level = cvRound( mean - 10 );
- thresh_level = MAX( thresh_level, 10 );
+ // 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);
- cvThreshold( img, thresh_img, thresh_level, 255, CV_THRESH_BINARY );
- cvDilate( thresh_img, thresh_img, 0, dilations );
- }
+ if( quad_count <= 0 )
+ {
+ continue;
+ }
-#ifdef DEBUG_CHESSBOARD
- cvCvtColor(thresh_img,dbg_img,CV_GRAY2BGR);
-#endif
+ // Find quad's neighbors
+ icvFindQuadNeighbors( quads, quad_count );
- // 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);
+ // 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 );
- quad_count = icvGenerateQuads( &quads, &corners, storage, thresh_img, flags, &max_quad_buf_size);
+ for( group_idx = 0; ; group_idx++ )
+ {
+ int count = 0;
+ count = icvFindConnectedQuads( quads, quad_count, quad_group, group_idx, storage );
- PRINTF("Quad count: %d/%d\n", quad_count, expected_corners_num);
- }
+ 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, 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 ))
+ {
+ found = 1;
+ break;
+ }
+ }
+ }
+ }//dilations
+ // revert to old, slower, method if detection failed
+ if (!found)
+ {
+ for( k = 0; k < 6; k++ )
+ {
+ int max_quad_buf_size = 0;
+ for( 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 )
+ {
+ 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;
+
+ // convert to binary
+ 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 );
+ }
+ //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 );
+ }
#ifdef DEBUG_CHESSBOARD
- cvCopy(dbg_img, dbg1_img);
- cvNamedWindow("all_quads", 1);
- // copy corners to temp array
- 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);
- }
- }
+ cvCvtColor(thresh_img,dbg_img,CV_GRAY2BGR);
+#endif
+ // 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);
- cvShowImage("all_quads", (IplImage*)dbg1_img);
- cvWaitKey();
+ quad_count = icvGenerateQuads( &quads, &corners, storage, thresh_img, flags, &max_quad_buf_size);
+ PRINTF("Quad count: %d/%d\n", quad_count, expected_corners_num);
+
+#ifdef DEBUG_CHESSBOARD
+ cvCopy(dbg_img, dbg1_img);
+ cvNamedWindow("all_quads", 1);
+ // copy corners to temp array
+ for(int i = 0; i < quad_count; i++ )
+ {
+ for (int z=0; z<4; z++)
+ {
+ CvPoint2D32f pt1, pt2;
+ CvScalar color = CV_RGB(30,255,30);
+ pt1 = quads[i].corners[z]->pt;
+ pt2 = quads[i].corners[(z+1)%4]->pt;
+ pt2.x = (pt1.x + pt2.x)/2;
+ pt2.y = (pt1.y + pt2.y)/2;
+ if (z>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;
+ if( quad_count <= 0 )
+ {
+ continue;
+ }
- // Find quad's neighbors
- icvFindQuadNeighbors( quads, quad_count );
+ // 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 );
+ // 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 );
+ 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;
+ 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);
+ // 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);
#ifdef DEBUG_CHESSBOARD
- cvCopy(dbg_img,dbg2_img);
- cvNamedWindow("connected_group", 1);
- // copy corners to temp array
- 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();
+ cvCopy(dbg_img,dbg2_img);
+ cvNamedWindow("connected_group", 1);
+ // copy corners to temp array
+ for(int i = 0; i < quad_count; i++ )
+ {
+ if (quads[i].group_idx == group_idx)
+ for (int z=0; z<4; z++)
+ {
+ CvPoint2D32f pt1, pt2;
+ CvScalar color = CV_RGB(30,255,30);
+ if (quads[i].ordered)
+ color = CV_RGB(255,30,30);
+ pt1 = quads[i].corners[z]->pt;
+ pt2 = quads[i].corners[(z+1)%4]->pt;
+ pt2.x = (pt1.x + pt2.x)/2;
+ pt2.y = (pt1.y + pt2.y)/2;
+ if (z>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; // haven't found inner quads
+ 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);
+ // 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);
+ 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;
+ 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));
+ 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( 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( out_corner_count )
+ *out_corner_count = n;
- if( count == pattern_size.width*pattern_size.height &&
- icvCheckBoardMonotony( out_corners, pattern_size ))
- {
- found = 1;
- break;
- }
- }
- }
+ if( count == pattern_size.width*pattern_size.height && icvCheckBoardMonotony( out_corners, pattern_size ))
+ {
+ found = 1;
+ break;
+ }
}
+ }
}//dilations
- }//
+ }// for k = 0 -> 6
+ }
+
if( found )
found = icvCheckBoardMonotony( out_corners, pattern_size );
cvFree(&corners);
cvFree(&quad_group);
cvFree(&corner_group);
+ cvFree(&cImgSeg);
throw;
}
cvFree(&corners);
cvFree(&quad_group);
cvFree(&corner_group);
+ cvFree(&cImgSeg);
return found;
}