HOWTO · Python

Marcadores OpenCV ArUco

Uno puede detectar marcadores ArUco utilizando la función cv2.aruco.detectMarkers() de OpenCV.

En esta página

Para detectar marcadores ArUco en una imagen, cárgala, selecciona el mismo diccionario ArUco con el que se crearon los marcadores y pasa ambos a la función cv2.aruco.detectMarkers() de OpenCV. El resultado incluye las coordenadas de las esquinas y los ID de los marcadores decodificados, además de las formas candidatas rechazadas.

Detectar marcadores ArUco con OpenCV

Un marcador ArUco es un código visual cuadrado, con un borde negro y un patrón binario en su interior. Estos marcadores pueden proporcionar puntos de imagen conocidos para la estimación de pose, la calibración de cámaras, la robótica y la realidad aumentada; la detección por sí sola no calcula la pose de un marcador.

Este ejemplo ilustrativo en Python comprueba primero que estén disponibles todos los atributos de OpenCV y ArUco que utilizará. Después, lee una imagen, selecciona un diccionario predefinido y llama a cv2.aruco.detectMarkers(). Sustituye la ruta de la imagen por la de tu propio archivo. Si la compilación instalada no incluye algún atributo necesario, el ejemplo muestra un mensaje orientativo y se detiene antes de utilizarlo. El ejemplo no se ha ejecutado aquí; consulta la documentación de OpenCV para conocer la API disponible en tu instalación. Los bloques de código se conservan sin traducir, por lo que cualquier etiqueta textual que incluyan permanece en inglés.

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 tiene una carga útil de 4 por 4 bits y contiene 100 códigos de marcador. La capacidad del diccionario es distinta del ID de cada marcador: cada ID identifica un código de ese diccionario. Usa el mismo diccionario para generar y detectar los marcadores, de modo que el detector compruebe los patrones esperados. El ejemplo muestra el ID junto a las cuatro coordenadas de las esquinas, dibuja contornos alrededor de las detecciones devueltas, coloca cada ID cerca de su primera esquina y guarda una copia anotada. Los candidatos rechazados están disponibles en rejected para ayudar al diagnóstico; no son marcadores confirmados.

Entender los diccionarios ArUco, los ID y los resultados de detección

Un diccionario define el conjunto de patrones de bits que reconocerá OpenCV. En DICT_4X4_100, cada código tiene una carga útil de 4 por 4 bits y el diccionario contiene 100 códigos. Los ID identifican entradas individuales; el ID válido más alto no equivale al número de entradas. El detector compara las regiones candidatas con el diccionario seleccionado, así que elegir uno distinto del utilizado para crear el marcador puede hacer que no se detecte o que se decodifique de otra manera.

detectMarkers() devuelve tres valores: corners, ids y rejected. Cada elemento de corners contiene los cuatro puntos, en coordenadas de imagen, de un cuadrilátero detectado. La fila correspondiente de ids indica el ID del marcador. ids vale None cuando no se ha decodificado ningún marcador. rejected contiene cuadriláteros candidatos que no se decodificaron como marcadores del diccionario seleccionado; sirve para diagnosticar problemas, pero no demuestra que cada forma rechazada sea un marcador.

La función localiza y decodifica marcadores, pero no estima la pose de la cámara. Para estimar la pose se necesitan la calibración de la cámara y el tamaño físico del marcador, además de los resultados de detección.

Dibujar y etiquetar los marcadores detectados

Para superponer rápidamente las detecciones, pasa la imagen, los arreglos de esquinas devueltos y los ID a cv2.aruco.drawDetectedMarkers(). El ejemplo también muestra cómo añadir etiquetas personalizadas: coloca cada ID en la primera esquina de su marcador mediante cv2.putText(). Para controlar el dibujo con más detalle, traza los lados del cuadrilátero con cv2.line() o marca el centro con cv2.circle(). La guía relacionada sobre cv2.putText() explica cómo colocar y dar estilo al texto.

En las imágenes en color, OpenCV usa el orden de canales BGR; por eso, (255, 0, 0) representa azul, no rojo. Para una imagen en escala de grises, usa un único valor de intensidad. Mantén las coordenadas de las anotaciones dentro de la imagen y elige un grosor de línea y una escala de texto que sigan siendo visibles al tamaño con que se muestra.

Comprobar el resultado de la detección

Abre o muestra la imagen anotada guardada para confirmar que los contornos siguen las esquinas de los marcadores detectados y que cada etiqueta coincide con el ID mostrado junto a esas esquinas. Si corners está vacío e ids vale None, no se ha decodificado ningún marcador. Comprueba que la imagen se haya cargado, que el marcador sea lo bastante grande y nítido para distinguirlo y que el diccionario seleccionado coincida con el utilizado para crearlo. El desenfoque, los reflejos, la perspectiva, el recorte o un marcador pequeño pueden dificultar la lectura del código; mejorar la imagen de entrada podría ayudar.

Para consultar los detalles de la API, visita la documentación de detección ArUco de OpenCV. El ejemplo es ilustrativo y no se ha ejecutado, por lo que sus mensajes y la descripción de la imagen guardada no son resultados observados.