The source code of OpenCV is available, so I'd recommend just taking some time going through the code. The relevant file for this particular function is:
calib3d/src/calibinit.cpp
I've not looked into it in detail, but it looks like
CV_IMPL
int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
CvPoint2D32f* out_corners, int* out_corner_count,
int flags )
is the main implementation of this method. In here they
- Use
cvCheckChessboardto determine if a chessboard is in the image - Convert to binary (B&W) and dilate to split the corners apart
- Use
icvGenerateQuadsto find the squares.
The code then seems to go though a set of checks to condense these quads to chessboard corners, including icvFindConnectedQuads, icvCleanFoundConnectedQuads to remove extra corners, icvCheckQuadGroup, and icvCheckBoardMonotony.
All of these functions are implemented in the same file, apart from cvCheckChessboard which is in calib3d/src/checkchessboard.cpp. Depending how well you wanted to understand the code, there seem to be a number of debugging lines, which can be included if you #define DEBUG_CHESSBOARD, that may help you see what's going on.
python - Cv2 findChessboardCorners fails to find corners - Stack Overflow
[Question] Find Chessboard Corners Function Help
c - What is the OpenCV FindChessboardCorners convention? - Stack Overflow
Question about camera calibration: findChessboardCorners given different orientation - C++ - OpenCV
My approach for the problem is to perform color-segmentation to get a binary mask. Next, using binary mask to remove the background to make the board visible, removed from artifacts. Finally output the chess border features in an accurate way.
-
- Performing color-segmentation: We convert the loaded image to the HSV format define lower/upper ranges and perform color segmentation using
cv2.inRangeto obtain a binary mask.
- Performing color-segmentation: We convert the loaded image to the HSV format define lower/upper ranges and perform color segmentation using
-
- Extracting chess-board: After obtaining binary mask we will use it to remove the background and separate chess part from the rest of the image using
cv2.bitwise_and. Arithmetic operation and is highly useful for defining roi in hsv colored images.
- Extracting chess-board: After obtaining binary mask we will use it to remove the background and separate chess part from the rest of the image using
-
- Displaying chess-board features. After extracting the chessboard from the image, we will set the
patternSizeto (7, 7) andflagsto adaptive_thresh + fast_check + normalize image inspired from the source.
- Displaying chess-board features. After extracting the chessboard from the image, we will set the
Steps:
Color-segmentation to get the binary mask.

-
lwr = np.array([0, 0, 143]) upr = np.array([179, 61, 252]) hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) msk = cv2.inRange(hsv, lwr, upr)
Removing background using mask

-
krn = cv2.getStructuringElement(cv2.MORPH_RECT, (50, 30)) dlt = cv2.dilate(msk, krn, iterations=5) res = 255 - cv2.bitwise_and(dlt, msk)
Displaying Chess-board features

-
res = np.uint8(res) ret, corners = cv2.findChessboardCorners(res, (7, 7), flags=cv2.CALIB_CB_ADAPTIVE_THRESH + cv2.CALIB_CB_FAST_CHECK + cv2.CALIB_CB_NORMALIZE_IMAGE) if ret: print(corners) fnl = cv2.drawChessboardCorners(img, (7, 7), corners, ret) cv2.imshow("fnl", fnl) cv2.waitKey(0) else: print("No Checkerboard Found")
Code:
import cv2
import numpy as np
# Load the image
img = cv2.imread("kFM1C.jpg")
# Color-segmentation to get binary mask
lwr = np.array([0, 0, 143])
upr = np.array([179, 61, 252])
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
msk = cv2.inRange(hsv, lwr, upr)
# Extract chess-board
krn = cv2.getStructuringElement(cv2.MORPH_RECT, (50, 30))
dlt = cv2.dilate(msk, krn, iterations=5)
res = 255 - cv2.bitwise_and(dlt, msk)
# Displaying chess-board features
res = np.uint8(res)
ret, corners = cv2.findChessboardCorners(res, (7, 7),
flags=cv2.CALIB_CB_ADAPTIVE_THRESH +
cv2.CALIB_CB_FAST_CHECK +
cv2.CALIB_CB_NORMALIZE_IMAGE)
if ret:
print(corners)
fnl = cv2.drawChessboardCorners(img, (7, 7), corners, ret)
cv2.imshow("fnl", fnl)
cv2.waitKey(0)
else:
print("No Checkerboard Found")
To find lower and upper boundaries of the mask, you may find useful: HSV-Threshold-script
In my environment (opencv-python 4.7.0.68, opencv 4.5.4), just converting it to grey scale can make it work without additional adjustment (at least detected all but the lower left corners). After downsample by resize(), all corners are detected.
img_captured = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
# img_captured = cv2.resize(img_captured, (350, 350))
GRID = (7, 7)
found, corners = cv2.findChessboardCorners(
img_captured, GRID, cv2.CALIB_CB_ADAPTIVE_THRESH)
cv2.drawChessboardCorners(img_captured_corners, GRID, corners, found)
cv2.imshow('img_captured_corners', img_captured_corners)
findChessboardCorners no resize
There is also findChessboardCornersSB. From my experience, it works generally better than the plain version. However, I don't know benchmark difference between the two methods.
findChessboardCornersSB
Hello guys, I am trying to create a calibration script for a project I am in. Here is the general idea, I will have a reference image with the camera in the correct location. I will find the chessboard corners and save it in a text file. Then, when I calibrate the camera, I will take another image (Ill call it test image) and will get the chessboard corners and save that in a text file. I already have a script that reads in the text file corners and will create a homography matrix and perspective warp the test image to essentially look like the reference image.
I have been struggling to consistently get the chessboard corners function to actually find the corners. I do have some fundamental issues to overcome:
-
There are 4 smaller chessboards in the corner, that all always fixed there.
-
Lighting is not constant.
After cutting the image into quadrants for each chessboard, I have been doing is a mix of image processing techniques. CLAHE, blurring, adaptive filtering for lighting, sobel masks for edge detection as well as some the techniques from this form:
https://stackoverflow.com/questions/66225558/cv2-findchessboardcorners-fails-to-find-corners
I tried different chessboard sizes from 9x6 to 4x3. What are your guys approaches for this matter, so I can get a consistent chessboard corner detection script.
I can only post one image since I am a new user but here is the pipeline of all the image processing techniques. You can see the chessboard rather clearly but the actual function cannot for whatever reason.
diagnostic_pipeline_dot_img_test21920×1280 163 KB
I am writing this debug code in Python but the actual script will run on my Raspberry Pi with C++.
It seems to me the doc is lacking this kind of details.
For 3.2.0-dev it seems to me it depends on the angle of rotation of the chessboard. With this snippet:
cv::Size patternsize(4,3); //number of centers
cv::Mat cal = cv::imread(cal_name);
std::vector<cv::Point2f> centers; //this will be filled by the detected centers
bool found = cv::findChessboardCorners( cal, patternsize, centers, cv::CALIB_CB_ADAPTIVE_THRESH );
std::cout << found << "\n";
if(found){
cv::drawChessboardCorners(cal,patternsize,centers,found);
You will get these results:
First image:

First image rotated by 180 degrees:

Note the
colored corners connected with lines
drawn by drawChessboardCorners, they differ only by the color: in the original image the red line is at the bottom, in the rotated image the red line is at the top of the image.
If you pass to drawChessboardCorners a grayscale image you will loose this piece of information.
If I need the first corner at the top left of the image and if I can assume that:
- the angle of the chessboard in the scene will be only close to 0 or close to 180;
- the tilt of the camera will be negligible;
then the following snippet will reorder the corners if needed:
cv::Size patternsize(4,3); //number of centers
cv::Mat cal = cv::imread(cal_name);
std::vector<cv::Point2f> centers; //this will be filled by the detected centers
bool found = cv::findChessboardCorners( cal, patternsize, centers, cv::CALIB_CB_ADAPTIVE_THRESH );
std::cout << found << "\n";
if(found){
cv::drawChessboardCorners(cal,patternsize,centers,found);
// I need the first corner at top-left
if(centers.front().y > centers.back().y){
std::cout << "Reverse order\n";
std::reverse(centers.begin(),centers.end());
}
for(size_t r=0;r<patternsize.height;r++){
for(size_t c=0;c<patternsize.width;c++){
std::ostringstream oss;
oss << "("<<r<<","<<c<<")";
cv::putText(cal, oss.str(), centers[r*patternsize.width+c], cv::FONT_HERSHEY_PLAIN, 3, CV_RGB(0, 255, 0), 3);
}
}
}

I am pretty sure it orders the chessboard corners by rows, starting with the one closest to the top-left corner of the image.
The chessboard pattern has no specified origin (one of the deficiencies of that calibration device), so if you turn it 90 or 180 degrees the corners you get back won't be in the same order.
The way to make sure is to look at the actual point values you get back and see if they are what you expected.
Edit: at least in case of OpenCV 3.3.1 and 5x3 chessboard, the chessboard corners can be returned either starting top-left or bottom-right, depending on the rotation.
Hi,
So I’m using opencv and need to find the coordinates of the corners on a chessboard. My current approach is to take the return value of findChessboardCorners, then do math to determine the outer coordinates, then draw circles at each point.
I know there is drawChessboardCorners, but for this project I can’t quite use that. So when I went to draw the circles at the coordinates, I realized that the coordinates returned are not integers. So what exactly are they? I had been assuming they were the coordinates of the corners. I went through documentation and searched around for a while but can’t seem to find anything.
Any help is appreciated, thank you.