My intention is to create a charuco board object, which supports custom ids. Here is the code snippet being used.
def __init__(self, squaresX=11, squaresY=8, squareLength=0.015, markerLength=0.011,
dict=cv2.aruco.DICT_5X5_250, start_id=0):
self.squaresX = squaresX
self.squaresY = squaresY
self.squareLength = squareLength
self.markerLength = markerLength
self.aruco_dict = cv2.aruco.getPredefinedDictionary(dict)
self.start_id = start_id
num_markers_x = squaresX - 1
num_markers_y = squaresY - 1
num_markers = num_markers_x * num_markers_y
if start_id + num_markers > self.aruco_dict.bytesList.shape[0]:
raise ValueError(f"Not enough markers in dictionary for board (required: {num_markers})")
marker_ids = np.arange(start_id, start_id + num_markers, dtype=np.int32).reshape(num_markers_y, num_markers_x)
self.board = cv2.aruco.CharucoBoard(
(self.squaresX, self.squaresY),
self.squareLength,
self.markerLength,
self.aruco_dict,
marker_ids
)
However when I create self.board
, there is a segmentation error (keep in mind when I'm creating the object, I'm using the same arguments as the default arguments to the __init__
method.
cv2.__version__
returns 4.11.0
The problem seems to be: You are providing way too many marker_ids
. ChArUco uses one marker per white chessboard square, as is also mentioned in its OpenCV documentation:
ChArUco board is a planar chessboard where the markers are placed inside the white squares of a chessboard.
The pattern you currently seem to employ is: one ID per square corner inside the board (as a 2-d array). The pattern you actually need is: exactly as many marker_ids
as there are white squares in the chessboard of the given square count (as a 1-d array).
The following code works for me – it basically fixes the creation of the marker_ids
array:
import cv2
import numpy as np
squaresX = 11
squaresY = 8
squareLength = 0.015
markerLength = 0.011
dct = cv2.aruco.DICT_5X5_250
start_id = 0
num_white_squares = (squaresX * squaresY) // 2
marker_ids = np.arange(start_id, start_id + num_white_squares)
board = cv2.aruco.CharucoBoard(
(squaresX, squaresY),
squareLength,
markerLength,
cv2.aruco.getPredefinedDictionary(dct),
marker_ids
)
board_image = board.generateImage((1000, 1000), None, 0, 1)
cv2.imshow("charuco", board_image)
cv2.waitKey(0)
This produces (OpenCV 4.12.0):
Using floor/integer division (//
) in num_white_squares
's calculation seems to be the correct approach:
squaresX
, squaresY
, or both being even), there are always exactly as many black squares as there are white squares. This is reflected by the integer division, which will produce the same result as a regular division in this case.squaresX
and squaresY
being odd), ChArUco boards always seem to have black corners (I tried it with various combinations of values for squaresX
and squaresY
, and both with the current and the legacy pattern, as chosen by setLegacyPattern()
), so the number of white squares will be one less than the number of black squares. This is again reflected by the integer division, which will round down the result in this case.Side note: I would not use dict
as a variable name (I replaced it with dct
in my code), as it shadows the name of the built-in dictionary type dict
.