opencv / opencv

Open Source Computer Vision Library
https://opencv.org
Apache License 2.0
76.67k stars 55.65k forks source link

Off by ~0.5 pixel error in `cv2.aruco.CharucoDetector` compared to `cv2.findChessboardCorners` #25539

Open matthewbaran opened 1 month ago

matthewbaran commented 1 month ago

System Information

OpenCV python version: 4.9.0 Operating System / Platform: Windows 11 Python version: 3.10.8

Detailed description

There is a discrepancy in the estimated corners between the "new detector" charuco_detector.detectBoard and the "old detector" cv2.findChessboardCorners.

If I run both detectors and compare the results I get differences of

[old vs new] ---> mean: -0.501, max: -0.471, std: -0.471

Visually inspecting the results, it is clear that the "old detector" looks better. Here are a few zoomed in locations.

image image

Steps to reproduce

import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import cv2

plt.ion()
matplotlib.use('Qt5Agg')

# Get the test image
rgb_image = cv2.cvtColor(cv2.imread('opencv_ticket.jpg'), cv2.COLOR_BGR2RGB)

# Setup the board
mm_to_m = 0.001
charuco_dict = cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_4X4_250)
charuco_board = cv2.aruco.CharucoBoard((14, 9),
                                       squareLength=60 * mm_to_m,
                                       markerLength=45 * mm_to_m,
                                       dictionary=charuco_dict)

# Setup the charuco detector
charuco_params = cv2.aruco.CharucoParameters()
detector_params = cv2.aruco.DetectorParameters()
refine_params = cv2.aruco.RefineParameters()

detector_params.adaptiveThreshConstant = 19
detector_params.cornerRefinementMethod = cv2.aruco.CORNER_REFINE_SUBPIX
detector_params.cornerRefinementMinAccuracy = 0.001
detector_params.cornerRefinementMaxIterations = 30
detector_params.cornerRefinementWinSize = 11

charuco_detector = cv2.aruco.CharucoDetector(board=charuco_board,
                                             charucoParams=charuco_params,
                                             detectorParams=detector_params,
                                             refineParams=refine_params)

# Run the detector
new_corners_pix, _, _, _ = charuco_detector.detectBoard(rgb_image)
new_corners_pix = new_corners_pix.squeeze()

# Run the old detector
gray_image = cv2.cvtColor(rgb_image, cv2.COLOR_RGB2GRAY)

width, height = np.array(charuco_board.getChessboardSize()) - 1
_, old_corners_pix = cv2.findChessboardCorners(gray_image, (width, height), None)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
old_corners_pix = cv2.cornerSubPix(gray_image, old_corners_pix, (11, 11), (-1, -1), criteria)
old_corners_pix = old_corners_pix.squeeze()

# Compare
deltas = (old_corners_pix - new_corners_pix).flatten()
print(f'[old vs new] ---> mean: {np.mean(deltas):0.3f}, max: {np.max(deltas):0.3f}, std: {np.max(deltas):0.3f}')

plt.figure()
plt.imshow(rgb_image)
plt.plot(old_corners_pix[:, 0], old_corners_pix[:, 1], '.', color='red', label='old')
plt.plot(new_corners_pix[:, 0], new_corners_pix[:, 1], 'x', color='green', label='new')
plt.legend()

opencv_ticket.zip

Issue submission checklist