Cv2 findChessboardCorners fails to find corners
Asked Answered
B

2

8

I am using cv2 findChessBoardCorners for camera calibration in a vision application. My call to the function looks like this:

def auto_detect_checkerboard(self, image):
    retval, corners = cv2.findChessboardCorners(image, (7, 7), flags=cv2.CALIB_CB_ADAPTIVE_THRESH
                                                + cv2.CALIB_CB_EXHAUSTIVE)
    if(retval):
        return corners[0][0], corners[0][1]
    else:
        print("No Checkerboard Found")
        assert False

But it seems to fail to find any corners on all images I have tried with it so far. The most trivial example I have used is960 x 1280 photograph of a checkerboard on a wooden table

Is there an issue with my use of the the function? Or is there an issue with the image that I need to deal with in preprocessing?

So far I have tried converting to grayscale, and applying a Gaussian filter, neither of which seem to have made a difference.

Barr answered 16/2, 2021 at 13:46 Comment(4)
When you tried with cv.findChessboardCorners(image, (7,7), None) ? Also when you changed (7,7) with 3,6 or 6,7 the results still dont change ?Pictorial
Try using return corners[0][0], corners[1][0]. corners[0][1] gives me an error. But the code detects 49 corners. The problem might be in the code you didn't post.Pugging
@YunusTemurlenk I've tried without the additional flags and its no different, its somewhat more successful when looking for a smaller checkerboard, but really my application requires me to be able to detect the whole thing.Barr
@Pugging You're right, there was an error in how I was accessing the corners, but that doesn't appear to be the entire issue. It still frequently doesn't hit that code block at all due to not detecting the board.Barr
Y
9

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.

    1. Performing color-segmentation: We convert the loaded image to the HSV format define lower/upper ranges and perform color segmentation using cv2.inRange to obtain a binary mask.
    1. 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.
    1. Displaying chess-board features. After extracting the chessboard from the image, we will set the patternSizeto (7, 7) and flags to adaptive_thresh + fast_check + normalize image inspired from the source.

Steps:

  • Color-segmentation to get the binary mask.

    • enter image description here

    • 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

    • enter image description here

    • 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

    • enter image description here

    • 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

Yearbook answered 16/2, 2021 at 21:21 Comment(4)
By themselves these instructions didn't help me detect any chessboard corners, but additionally changing cv2.findChessboardCorners(img, (7, 7), flags=...) to cv2.findChessboardCornersSB(img, (7, 7), flags=cv2.CALIB_CB_EXHAUSTIVE) did the trick.Gigantopithecus
There is no specific parameter list to guarantee the problem. Even if the image changes by pixel, the user must modify the parameter to make the system work. In my solution, the shown parameters work. Kudos to you for finding a solution by adding a flag parameter.Yearbook
I didn't just change the flags, I used an entirely different function which, in my case, has proven to be way more reliable.Gigantopithecus
Very interesting approach. It seems that it helped a bit in my case, but nevertheless I was still unable to detect checkerboard due to the low quality of the video and a lot of black/dark colors recorded in the peripheries of the scene.Dunston
S
2

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

Springspringboard answered 5/1, 2023 at 4:15 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Pernick

© 2022 - 2024 — McMap. All rights reserved.