OpenCV Chessboard Detection: Looking for Solutions to Identify and Extract Chessboard Squares

249 Views Asked by At

I am trying to write a program that could record chess moves played on a physical chessboard. The first step is to identify the chessboard and the individual squares. I have come up with a code that looks like it could work, but unfortunately, it's not functioning as expected. I have tried it on various chessboards with different viewing angles, but I still can't get it to work. After some research, I found that cv2.findChessboardCorners can be quite confusing. Can someone please help?

The following code is what I have tried. I expected it to find the chessboard, extract individual squares to temporary files, and print out the file names of the temporary files. However, I keep getting "Chessboard not found."

import cv2
import numpy as np
import tempfile

def extract_chessboard_squares(image_path, rows, columns):
    # Load the chessboard image
    image = cv2.imread(image_path)

    # Convert the image to grayscale
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # Find the chessboard corners
    found, corners = cv2.findChessboardCorners(gray, (rows, columns), None)

    if found:
        # Refine the corner locations
        corners = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.1))

        # Create a 2D list to store file names of chessboard squares
        square_files = [[None] * columns for _ in range(rows)]

        # Iterate over each chessboard square
        for row in range(rows):
            for col in range(columns):
                # Calculate the square corners' coordinates
                pt1 = corners[row * columns + col]
                pt2 = corners[(row + 1) * columns + col]
                pt3 = corners[(row + 1) * columns + col + 1]
                pt4 = corners[row * columns + col + 1]

                # Create a mask for the current square
                mask = np.zeros_like(image)
                cv2.fillConvexPoly(mask, np.int32([pt1, pt2, pt3, pt4]), (255, 255, 255))

                # Apply the mask to the original image
                masked_image = cv2.bitwise_and(image, mask)

                # Save the masked image to a temporary file
                _, temp_filename = tempfile.mkstemp(suffix='.jpg')
                cv2.imwrite(temp_filename, masked_image)

                # Store the temporary file name in the 2D list
                square_files[row][col] = temp_filename

        return square_files

    else:
        print("Chessboard not found.")
        return None

# Example usage:
image_path = 'path/to/chessboard_image.jpg'
rows = 8
columns = 8

result = extract_chessboard_squares(image_path, rows, columns)
if result:
    square_files = result
    # Use the square_files list as per your requirements

Make sure to replace 'path/to/chessboard_image.jpg' with the actual path to your chessboard image file.

1

There are 1 best solutions below

0
fish_brain On

following Lelouch suggestion this is what i came up with. note this solution is still not perfect as it ONLY extract the inner 6x6 squares that is surrounded by the 7x7 inner corners.

import cv2
import numpy as np
import tempfile

def extract_chessboard_squares(image_path, rows, columns):
    inner_rows = rows - 1
    inner_columns = columns - 1
    # Load the chessboard image
    image = cv2.imread(image_path)

    # Convert the image to grayscale
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # Find the chessboard inner corners
    found, corners = cv2.findChessboardCorners(gray, (inner_rows, inner_columns), None)

    if found:
        # Refine the corner locations
        corners = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.1))

        # Create a 2D list to store file names of chessboard squares
        square_files = [[None] * (columns-2) for _ in range(rows-2)]

        # Iterate over each chessboard square
        for row in range(rows-2):
            for col in range(columns-2):
                # Calculate the square corners' coordinates
                pt1 = corners[row * inner_columns + col]
                pt2 = corners[(row + 1) * inner_columns + col]
                pt3 = corners[(row + 1) * inner_columns + col + 1]
                pt4 = corners[row * inner_columns + col + 1]

                # Create a mask for the current square
                mask = np.zeros_like(image)
                cv2.fillConvexPoly(mask, np.int32([pt1, pt2, pt3, pt4]), (255, 255, 255))

                # Apply the mask to the original image
                masked_image = cv2.bitwise_and(image, mask)

                # Save the masked image to a temporary file
                _, temp_filename = tempfile.mkstemp(suffix='.jpg')
                cv2.imwrite(temp_filename, masked_image)

                # Store the temporary file name in the 2D list
                square_files[row][col] = temp_filename

        return square_files

    else:
        print("Chessboard not found.")
        return None

# Example usage:
image_path = r'C:\Users\Admin\Downloads\chess_board.jpg'
rows = 8
columns = 8

result = extract_chessboard_squares(image_path, rows, columns)