mirror of
https://github.com/zebrajr/opencv.git
synced 2025-12-06 00:19:46 +01:00
Merge pull request #24546 from thewoz:checkerboard
Check Checkerboard Corners #24546 What I did was get you to pull out of findChessboardCorners cornres the whole part that "checks" and sorts the corners of the checkerboard if present. The main reason for this is that findChessboardCorners is often very slow to find the corners and this depends in that the size the contrast etc of the checkerboards can be very different from each other and writing a function that works on all kinds of images is complicated. So I find it very useful to have the ability to write your own code to process the image and then have a function that controls or orders the corners. ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [ ] There is a reference to the original bug report and related work - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
parent
bee183f9bb
commit
e64c5dc4c6
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<cv::Point2f> 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:
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ void show_points( const Mat& gray, const Mat& expected, const vector<Point2f>& 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<size_t>(expected.cols * expected.rows);
|
||||
Size pattern_size = expected.size();
|
||||
|
||||
Mat ori;
|
||||
vector<Point2f> 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
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user