Search code examples
pythonopencvdetectionarucoapriltags

OpenCV Apriltag detection only detects a few markers


I'm using OpenCV's Aruco module in Python to detect my AprilTag calibration board. The problem is that only very few markers get detected, despite a rather good input image. From everything I tried, it seems that the AprilTag implementation is very sensitive and requires an almost ideal image to work. If this really is the case, that would make OpenCV's AprilTag detector almost unusable.

I'm using:

  • Windows
  • Python 3.10.5
  • opencv-contrib-python 4.7.0.72

First of all a minimal code example (following the OpenCV Aruco module documentation):

import cv2

img = cv2.imread("april_board_drawing.png", cv2.IMREAD_COLOR)

aruco_dict = cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_APRILTAG_36h11)
arucoParams = cv2.aruco.DetectorParameters()
arucoParams.markerBorderBits = 2

(corners, ids, rejected) = cv2.aruco.detectMarkers(img, aruco_dict, parameters=arucoParams)

cv2.aruco.drawDetectedMarkers(img, corners, ids)

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

I started out with an "ideal" image to test whether the tags get detected correctly and that there is no mismatch between my calibration board and the AprilTag dictionary. This worked out nicely, all markers were detected.

ideal image.png

I then proceeded with a recording from my camera. And here the problem ocurred. Only very few markers got detected (15/49). I chose one of the best images I took for this. Not all markers are perfect, there is some glare, but many have quite good contrast and are still not detected. I played around with the detection parameters, with no luck.

real image.png

Maybe the distortion is too strong I thought. So I rectified the image, thereby removing the distortion and tried again. This got me some additional detections (20/49), but many where still not detected.

real image rectified.png

I then had a look at the rejected markers. They seem to be rejected correctly. No issue there. Although, it is weird that multiple markers are almost correct. Not sure what's going on there. I specified the correct border size.

rejections.png

Other things I tried:

  • resizing, cropping, and flipping the input image
  • grayscale & color input
  • tuned all the aruco.DetectorParameters

I'm reluctant to experiment with adaptive contrast enhancement, since I expect the algorithm to work with this level of image quality. Are my expectations too high?

The geometry of the calibration board doesn't seem to be a problem, since the markers are detected correctly in the ideal drawing, right? I prefer using this type of board, due to its high marker density and the ability to perform subpixel refinement on the corners.

Any idea what's going wrong here? Any help is very much appreciated!

Here are all input images I used:

april_board_drawing.png

april_board_real.png

april_board_real_rectified.png


Solution

  • If you parameterize the aruco detector differently, you can detect more codes. It is most probable due the adaptive thresholding. If you change the default of arucoParams.adaptiveThreshWinSizeStep=10 to a smaler value, the detector detects more codes. I achived the best results (distorted: 48/49, undistorted: 47/49) with the parameter choice:

    arucoParams = cv2.aruco.DetectorParameters()
    arucoParams.markerBorderBits = 2
    params.adaptiveThreshWinSizeStep = 1
    

    When you change the default parameter arucoParams.minMarkerDistanceRate to arucoParams.minMarkerDistanceRate = 0.0, the detector detects in the undistorted image 1 tag more, but the detector result includes multiple detections for each tag.