HOWTO · Python

OpenCV ArUco-Marker

Man kann ArUco-Marker mit der Funktion cv2.aruco.detectMarkers() von OpenCV erkennen.

Auf dieser Seite

Um ArUco-Marker in einem Bild zu finden, laden Sie das Bild, wählen Sie dasselbe ArUco-Wörterbuch, mit dem die Marker erstellt wurden, und übergeben Sie beides an OpenCVs Funktion cv2.aruco.detectMarkers(). Das Ergebnis enthält die Eckkoordinaten und IDs decodierter Marker sowie Kandidatenformen, die verworfen wurden.

ArUco-Marker mit OpenCV erkennen

Ein ArUco-Marker ist ein quadratischer visueller Code mit schwarzem Rand und einem binären Muster im Inneren. Diese Marker können bekannte Bildpunkte für die Posenschätzung, Kamerakalibrierung, Robotik und Augmented Reality liefern; die Erkennung allein berechnet jedoch nicht die Pose eines Markers.

Dieses beispielhafte Python-Programm prüft zunächst, ob alle darin verwendeten OpenCV- und ArUco-Attribute verfügbar sind. Anschließend liest es ein Bild ein, wählt ein vordefiniertes Wörterbuch aus und ruft cv2.aruco.detectMarkers() auf. Ersetzen Sie den Bildpfad durch den Pfad zu Ihrer Datei. Fehlt dem installierten Build ein benötigtes Attribut, gibt das Beispiel einen Hinweis aus und wird beendet, bevor es dieses Attribut verwendet. Das Beispiel wurde hier nicht ausgeführt. Informationen zur API, die in Ihrer Installation verfügbar ist, finden Sie in der OpenCV-Dokumentation.

try:
    import cv2
except ImportError as error:
    print("OpenCV is unavailable:", type(error).__name__)
else:
    aruco = getattr(cv2, "aruco", None)
    required_cv2 = ("imread", "putText", "FONT_HERSHEY_SIMPLEX", "imwrite")
    required_aruco = (
        "DICT_4X4_100",
        "getPredefinedDictionary",
        "detectMarkers",
        "drawDetectedMarkers",
    )

    if (
        aruco is None
        or any(not hasattr(cv2, name) for name in required_cv2)
        or any(not hasattr(aruco, name) for name in required_aruco)
    ):
        print("The installed OpenCV build lacks an API required by this example")
    else:
        image_path = "path/to/your-image.png"
        image = cv2.imread(image_path)

        if image is None:
            print("Could not load image:", image_path)
        else:
            dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_100)
            corners, ids, rejected = aruco.detectMarkers(image, dictionary)

            if ids is None:
                print("No markers detected")
            else:
                for marker_corners, marker_id in zip(corners, ids.flatten()):
                    print(f"ID {marker_id}: corners {marker_corners[0].tolist()}")

                annotated = image.copy()
                aruco.drawDetectedMarkers(annotated, corners, ids)
                for marker_corners, marker_id in zip(corners, ids.flatten()):
                    label_position = tuple(marker_corners[0][0].astype(int))
                    cv2.putText(
                        annotated,
                        str(marker_id),
                        label_position,
                        cv2.FONT_HERSHEY_SIMPLEX,
                        0.6,
                        (0, 255, 0),
                        2,
                    )

                if cv2.imwrite("annotated-markers.png", annotated):
                    print("Saved annotated image: annotated-markers.png")
                else:
                    print("Could not save annotated image")

DICT_4X4_100 verwendet Nutzdaten mit 4 × 4 Bits und enthält 100 Markercodes. Die Kapazität des Wörterbuchs ist von der ID eines einzelnen Markers zu unterscheiden: Jede ID bezeichnet einen Code in diesem Wörterbuch. Verwenden Sie für die Erzeugung und Erkennung dasselbe Wörterbuch, damit der Detektor nach den erwarteten Mustern sucht. Dem Beispiel zufolge gibt das Programm die ID zusammen mit den vier Eckkoordinaten aus, zeichnet Umrisse um die zurückgegebenen Erkennungen, setzt die jeweilige ID nahe der ersten Ecke und speichert eine annotierte Kopie. Die verworfenen Kandidaten stehen in rejected für Diagnosezwecke zur Verfügung; sie sind keine bestätigten Marker. Diese Beschreibung gibt das vorgesehene Verhalten wieder, nicht beobachtete Ausgaben.

ArUco-Wörterbücher, IDs und Erkennungsergebnisse verstehen

Ein Wörterbuch legt fest, welche Bitmuster OpenCV erkennt. In DICT_4X4_100 hat jeder Code Nutzdaten mit 4 × 4 Bits; das Wörterbuch umfasst 100 Codes. IDs bezeichnen einzelne Einträge. Die höchste gültige ID ist nicht gleich der Anzahl der Einträge. Der Detektor vergleicht mögliche Bildbereiche mit dem ausgewählten Wörterbuch. Wird ein anderes Wörterbuch als das zur Erstellung eines Markers verwendete ausgewählt, kann der Marker übersehen oder anders decodiert werden.

detectMarkers() gibt drei Werte zurück: corners, ids und rejected. Jeder Eintrag in corners enthält die vier Bildkoordinatenpunkte eines erkannten Vierecks. Die entsprechende Zeile in ids enthält die ID dieses Markers. Wenn kein Marker decodiert wurde, ist ids gleich None. rejected enthält Viereckkandidaten, die nicht als Marker des ausgewählten Wörterbuchs decodiert wurden. Diese Informationen sind für die Diagnose nützlich, belegen aber nicht, dass jede verworfene Form ein Marker ist.

Die Funktion lokalisiert und decodiert Marker, schätzt jedoch nicht die Kamerapose. Für die Posenschätzung sind zusätzlich zu den Erkennungsergebnissen eine Kamerakalibrierung und die physische Größe des Markers erforderlich.

Erkannte Marker zeichnen und beschriften

Für eine schnelle Überlagerung übergeben Sie das Bild, die zurückgegebenen Eckkoordinaten-Arrays und die IDs an cv2.aruco.drawDetectedMarkers(). Das Beispiel zeigt außerdem eigene Beschriftungen: Mit cv2.putText() setzt es jede ID an die erste Ecke des jeweiligen Markers. Für mehr Kontrolle können Sie die Kanten des Vierecks mit cv2.line() zeichnen oder den Mittelpunkt mit cv2.circle() markieren. Der zugehörige Leitfaden zu cv2.putText() erläutert Textpositionierung und Gestaltung.

Bei Farbbildern verwendet OpenCV für Zeichenfarben die Kanalreihenfolge BGR. Daher steht (255, 0, 0) für Blau und nicht für Rot. Verwenden Sie bei Graustufenbildern einen einzelnen Intensitätswert. Achten Sie darauf, dass die Koordinaten der Annotationen innerhalb des Bildes liegen, und wählen Sie eine Linienbreite und Textgröße, die bei der angezeigten Bildgröße gut erkennbar sind.

Erkennungsergebnis überprüfen

Öffnen oder zeigen Sie das gespeicherte annotierte Bild an, um zu prüfen, ob die Umrisse den erkannten Markerecken folgen und jede Beschriftung mit der ID übereinstimmt, die für diese Ecken ausgegeben wird. Sind corners leer und ids gleich None, wurde kein Marker decodiert. Prüfen Sie, ob das Bild geladen wurde, der Marker groß und deutlich genug ist und das ausgewählte Wörterbuch mit dem bei der Erstellung verwendeten übereinstimmt. Unschärfe, Spiegelungen, Perspektive, Beschnitt oder ein kleiner Marker können das Lesen eines Codes erschweren; ein besseres Eingabebild kann helfen.

API-Details finden Sie in der OpenCV-Dokumentation zur ArUco-Erkennung. Das Beispiel dient der Veranschaulichung und wurde nicht ausgeführt. Seine Meldungen und die Beschreibung des gespeicherten Bildes sind daher keine beobachteten Ausgaben.