pythonopencvimage-processingaugmented-realityaruco

OpenCV not able to detect aruco marker within image created with opencv


I encountered an issue while trying out a simple example of creating and detecting aruco-images. In the following code-snippet, I generate aruco images, save them to a file and then load one of these files for detection:

import cv2

aruco_dict= cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_ARUCO_ORIGINAL)

params = cv2.aruco.DetectorParameters()

##create aruco

marker_size = 500 #mm

for i in range(6):

    marker_image = cv2.aruco.generateImageMarker(aruco_dict, i, marker_size)

    cv2.imwrite(f"marker_{i}.png", marker_image)


##load aruco image

img = cv2.imread("marker_5.png")

#detect markers

aruco_detector = cv2.aruco.ArucoDetector(aruco_dict,params)

corners, ids, _ = aruco_detector.detectMarkers(img) 

print(corners)

print(ids)

This code results in an empty list of corners (e.g. the detector wasn't able to find the aruco). I assumed it should be able to detect it easily if I simply re-use the image created by OpenCV.

Does someone have an idea what I did wrong or where the issue lies? Any tips are welcome. Kind regards!


Solution

  • These markers need a "quiet zone" around them so the edge of the marker is detectable. That quiet zone should be a white border. You may have heard of this in relation to QR codes.

    generateImageMarker() does not produce a quiet zone around the marker. This is as it should be. The image contains just the imagery that goes inside the marker's bounds.

    Just the marker:

    pure marker

    Use copyMakeBorder() to add a quiet zone. The recommended width is one "module". Half a module may work marginally but I would not recommend operating near that limit.

    The width of the quiet zone also matters when you print and cut out markers. That quiet zone must be visible on the paper. You can't just cut the marker right up to its edge. Maintain one module of quiet zone.

    Your marker is sized as 7x7 modules (5x5 of data, and 1 of border all around), resolved at 500 pixels width. One module would figure to be 500/7 ~= 71 pixels wide.

    The size of a marker (counted in modules) depends on the dictionary you chose (which was "original"). 4x4 and 6x6 flavors are popular. This specifies the data area, so those would be sized 6x6 and 8x8 respectively.

    border_width = int(500 / 7)
    marker_image = cv.copyMakeBorder(
        marker_image,
        border_width, border_width, border_width, border_width,
        borderType=cv.BORDER_CONSTANT, value=255)
    

    The marker, padded to about one module of quiet zone, will now be detectable:

    result