Help with detecting custom ArUco markers

Hey there,

I’ve been trying to detect custom markers similar to 5x5 ArUco markers such as the one below:

Using the following code adapted from this repo, it is able to detect normal ArUco markers with no issues, but is very inconsistent when trying to detect custom markers.

# Program to create custom ArUco dictionary using OpenCV and detect markers using webcam
# original code from: http://www.philipzucker.com/aruco-in-opencv/
# Modified by Iyad Aldaqre
# 12.07.2019

import numpy as np
import cv2
import cv2.aruco as aruco

# we will not use a built-in dictionary, but we could
# aruco_dict = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)

# define an empty custom dictionary with 
aruco_dict = aruco.Dictionary(0, 5, 1)
# add empty bytesList array to fill with 3 markers later
aruco_dict.bytesList = np.empty(shape = (4, 4, 4), dtype = np.uint8)

# add new marker(s)
mybits = np.array([[0,0,1,0,0],[0,1,0,1,0],[1,1,1,1,1],[1,0,0,0,1],[1,0,0,0,1]], dtype = np.uint8)  # A
aruco_dict.bytesList[0] = aruco.Dictionary.getByteListFromBits(mybits) 
mybits = np.array([[1,1,1,1,0],[1,0,0,0,1],[1,1,1,1,0],[1,0,0,0,1],[1,1,1,1,0]], dtype = np.uint8)  # B
aruco_dict.bytesList[1] = aruco.Dictionary.getByteListFromBits(mybits)
mybits = np.array([[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,0],[1,0,0,0,1],[0,1,1,1,0]], dtype = np.uint8)  # C 
aruco_dict.bytesList[2] = aruco.Dictionary.getByteListFromBits(mybits)
mybits = np.array([[1,0,1,0,0],[0,1,0,1,1],[0,1,1,0,0],[1,0,1,0,1],[1,1,1,0,0]], dtype = np.uint8)  # ArUco 5x5_50 id:0
aruco_dict.bytesList[3] = aruco.Dictionary.getByteListFromBits(mybits)

# save marker images
for i in range(len(aruco_dict.bytesList)):
    cv2.imwrite("custom_aruco_" + str(i) + ".png", aruco.generateImageMarker(aruco_dict, i, 128))

aruco_param = aruco.DetectorParameters()
aruco_detector = aruco.ArucoDetector(aruco_dict, aruco_param)

# open video capture from (first) webcam
cap = cv2.VideoCapture(0)

while(True):
    # Capture frame-by-frame
    ret, frame = cap.read()
    if ret == True:

        # Conver to grayscale
        grayscale = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        
        bw = cv2.threshold(grayscale, 128, 255, cv2.THRESH_BINARY)[1]

        #lists of ids and the corners beloning to each id
        corners, ids, rejectedImgPoints = aruco_detector.detectMarkers(grayscale)
        
        # draw markers on farme
        frame = aruco.drawDetectedMarkers(frame, corners, ids)

        # resize frame to show even on smaller screens
        frame = cv2.resize(frame, None, fx = 0.6, fy = 0.6)

        # Display the resulting frame
        cv2.imshow('frame',frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

Any idea why this might be? Are there parameters I need to tune to make this work for custom markers or does the ArUco detector simply not work for these?

Thank you!

just curious, how did you design those patterns ?

how so, exactly ? (type 1/2 errors ?)

These were just pixel representations of the alphabet, I’m assuming that ArUco markers must have some underlying data behind it that prohibits me from using any grid pattern?

It wouldn’t throw any errors; performance is just very poor when it comes to using the custom markers. It usually fails to detect the tag and when it does it is only at very precise angles/orientations.