diff --git a/modules/calib3d/include/opencv2/calib3d.hpp b/modules/calib3d/include/opencv2/calib3d.hpp index 63ceae6fa9..e3630e2a8e 100644 --- a/modules/calib3d/include/opencv2/calib3d.hpp +++ b/modules/calib3d/include/opencv2/calib3d.hpp @@ -490,7 +490,8 @@ enum { CALIB_CB_ADAPTIVE_THRESH = 1, CALIB_CB_EXHAUSTIVE = 16, CALIB_CB_ACCURACY = 32, CALIB_CB_LARGER = 64, - CALIB_CB_MARKER = 128 + CALIB_CB_MARKER = 128, + CALIB_CB_PLAIN = 256 }; enum { CALIB_CB_SYMMETRIC_GRID = 1, @@ -1235,6 +1236,10 @@ square-like shape) to filter out false quads extracted at the contour retrieval - @ref CALIB_CB_FAST_CHECK Run a fast check on the image that looks for chessboard corners, and shortcut the call if none is found. This can drastically speed up the call in the degenerate condition when no chessboard is observed. +- @ref CALIB_CB_PLAIN All other flags are ignored. The input image is taken as is. +No image processing is done to improve to find the checkerboard. This has the effect of speeding up the +execution of the function but could lead to not recognizing the checkerboard if the image +is not previously binarized in the appropriate manner. The function attempts to determine whether the input image is a view of the chessboard pattern and locate the internal chessboard corners. The function returns a non-zero value if all of the corners diff --git a/modules/calib3d/src/calibinit.cpp b/modules/calib3d/src/calibinit.cpp index 9bab740bc5..bdf61695f6 100644 --- a/modules/calib3d/src/calibinit.cpp +++ b/modules/calib3d/src/calibinit.cpp @@ -480,8 +480,7 @@ bool findChessboardCorners(InputArray image_, Size pattern_size, bool found = false; - const int min_dilations = 0; - const int max_dilations = 7; + const bool is_plain = (flags & CALIB_CB_PLAIN) != 0; int type = image_.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); Mat img = image_.getMat(); @@ -497,6 +496,9 @@ bool findChessboardCorners(InputArray image_, Size pattern_size, std::vector out_corners; + if (is_plain) + CV_CheckType(type, depth == CV_8U && cn == 1, "Only 8-bit grayscale images are supported whith CALIB_CB_PLAIN flag enable"); + if (img.channels() != 1) { cvtColor(img, img, COLOR_BGR2GRAY); @@ -505,10 +507,11 @@ bool findChessboardCorners(InputArray image_, Size pattern_size, int prev_sqr_size = 0; Mat thresh_img_new = img.clone(); - icvBinarizationHistogramBased(thresh_img_new); // process image in-place + if(!is_plain) + icvBinarizationHistogramBased(thresh_img_new); // process image in-place SHOW("New binarization", thresh_img_new); - if (flags & CALIB_CB_FAST_CHECK) + if (flags & CALIB_CB_FAST_CHECK && !is_plain) { //perform new method for checking chessboard using a binary image. //image is binarised using a threshold dependent on the image histogram @@ -524,6 +527,9 @@ bool findChessboardCorners(InputArray image_, Size pattern_size, ChessBoardDetector detector(pattern_size); + const int min_dilations = 0; + const int max_dilations = is_plain ? 0 : 7; + // 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, @@ -531,7 +537,8 @@ bool findChessboardCorners(InputArray image_, Size pattern_size, for (int dilations = min_dilations; dilations <= max_dilations; dilations++) { //USE BINARY IMAGE COMPUTED USING icvBinarizationHistogramBased METHOD - dilate( thresh_img_new, thresh_img_new, Mat(), Point(-1, -1), 1 ); + if(!is_plain) + 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. @@ -552,7 +559,7 @@ bool findChessboardCorners(InputArray image_, Size pattern_size, DPRINTF("Chessboard detection result 0: %d", (int)found); // revert to old, slower, method if detection failed - if (!found) + if (!found && !is_plain) { if (flags & CALIB_CB_NORMALIZE_IMAGE) { @@ -663,7 +670,6 @@ bool findChessboardCorners(InputArray image_, Size pattern_size, return found; } - // // Checks that each board row and column is pretty much monotonous curve: // It analyzes each row and each column of the chessboard as following: diff --git a/modules/calib3d/test/test_chesscorners.cpp b/modules/calib3d/test/test_chesscorners.cpp index 7226da999a..56cb81e4ab 100644 --- a/modules/calib3d/test/test_chesscorners.cpp +++ b/modules/calib3d/test/test_chesscorners.cpp @@ -73,7 +73,7 @@ void show_points( const Mat& gray, const Mat& expected, const vector& a #define show_points(...) #endif -enum Pattern { CHESSBOARD,CHESSBOARD_SB,CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID}; +enum Pattern { CHESSBOARD, CHESSBOARD_SB, CHESSBOARD_PLAIN, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID}; class CV_ChessboardDetectorTest : public cvtest::BaseTest { @@ -149,6 +149,25 @@ void CV_ChessboardDetectorTest::run( int /*start_from */) case CHESSBOARD_SB: checkByGeneratorHighAccuracy(); // not supported by CHESSBOARD /* fallthrough */ + case CHESSBOARD_PLAIN: + checkByGenerator(); + if (ts->get_err_code() != cvtest::TS::OK) + { + break; + } + + run_batch("negative_list.dat"); + if (ts->get_err_code() != cvtest::TS::OK) + { + break; + } + + run_batch("chessboard_list.dat"); + if (ts->get_err_code() != cvtest::TS::OK) + { + break; + } + break; case CHESSBOARD: checkByGenerator(); if (ts->get_err_code() != cvtest::TS::OK) @@ -191,6 +210,7 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename ) { case CHESSBOARD: case CHESSBOARD_SB: + case CHESSBOARD_PLAIN: folder = string(ts->get_data_path()) + "cv/cameracalibration/"; break; case CIRCLES_GRID: @@ -215,6 +235,9 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename ) int progress = 0; int max_idx = (int)board_list.size()/2; + if(filename.compare("chessboard_list.dat") == 0 && pattern == CHESSBOARD_PLAIN) + max_idx = 7; + double sum_error = 0.0; int count = 0; @@ -247,6 +270,7 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename ) size_t count_exp = static_cast(expected.cols * expected.rows); Size pattern_size = expected.size(); + Mat ori; vector v; int flags = 0; switch( pattern ) @@ -254,14 +278,30 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename ) case CHESSBOARD: flags = CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE; break; + case CHESSBOARD_PLAIN: { + flags = CALIB_CB_PLAIN; + ori = gray.clone(); + int min_size = cvRound((gray.cols * gray.rows * 0.05) / ((pattern_size.width+1) * (pattern_size.height+1))); + if(min_size%2==0) min_size += 1; + adaptiveThreshold(gray, gray, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, min_size, 0); + dilate(gray, gray, Mat(), Point(-1, -1), 1); + break; + } case CIRCLES_GRID: case CHESSBOARD_SB: case ASYMMETRIC_CIRCLES_GRID: default: flags = 0; } + bool result = findChessboardCornersWrapper(gray, pattern_size,v,flags); - if(result && sharpness && (pattern == CHESSBOARD_SB || pattern == CHESSBOARD)) + + if(result && pattern == CHESSBOARD_PLAIN) { + gray = ori; + cornerSubPix(gray, v, Size(6,6), Size(-1,-1), TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 30, 0.1)); + } + + if(result && sharpness && (pattern == CHESSBOARD_SB || pattern == CHESSBOARD || pattern == CHESSBOARD_PLAIN)) { Scalar s= estimateChessboardSharpness(gray,pattern_size,v); if(fabs(s[0] - sharpness) > 0.1) @@ -287,7 +327,7 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename ) double err = calcError(v, expected); max_rough_error = MAX( max_rough_error, err ); #endif - if( pattern == CHESSBOARD ) + if( pattern == CHESSBOARD || pattern == CHESSBOARD_PLAIN ) cornerSubPix( gray, v, Size(5, 5), Size(-1,-1), TermCriteria(TermCriteria::EPS|TermCriteria::MAX_ITER, 30, 0.1)); //find4QuadCornerSubpix(gray, v, Size(5, 5)); show_points( gray, expected, v, result ); @@ -381,6 +421,7 @@ bool CV_ChessboardDetectorTest::findChessboardCornersWrapper(InputArray image, S switch(pattern) { case CHESSBOARD: + case CHESSBOARD_PLAIN: return findChessboardCorners(image,patternSize,corners,flags); case CHESSBOARD_SB: // check default settings until flags have been specified @@ -631,6 +672,7 @@ bool CV_ChessboardDetectorTest::checkByGeneratorHighAccuracy() TEST(Calib3d_ChessboardDetector, accuracy) { CV_ChessboardDetectorTest test( CHESSBOARD ); test.safe_run(); } TEST(Calib3d_ChessboardDetector2, accuracy) { CV_ChessboardDetectorTest test( CHESSBOARD_SB ); test.safe_run(); } +TEST(Calib3d_ChessboardDetector3, accuracy) { CV_ChessboardDetectorTest test( CHESSBOARD_PLAIN ); test.safe_run(); } TEST(Calib3d_CirclesPatternDetector, accuracy) { CV_ChessboardDetectorTest test( CIRCLES_GRID ); test.safe_run(); } TEST(Calib3d_AsymmetricCirclesPatternDetector, accuracy) { CV_ChessboardDetectorTest test( ASYMMETRIC_CIRCLES_GRID ); test.safe_run(); } #ifdef HAVE_OPENCV_FLANN