HOWTO · Python

OpenCV ArUco 마커

OpenCV의 cv2.aruco.detectMarkers() 함수를 사용하여 ArUco 마커를 감지할 수 있습니다.

이 페이지의 내용

이미지에서 ArUco 마커를 찾으려면 이미지를 불러오고, 마커를 만들 때 사용한 것과 같은 ArUco 사전을 선택한 다음 두 항목을 모두 OpenCV의 cv2.aruco.detectMarkers() 함수에 전달합니다. 결과에는 디코딩된 마커의 모서리 좌표와 ID, 그리고 거부된 후보 모양이 포함됩니다.

OpenCV로 ArUco 마커 감지하기

ArUco 마커는 검은 테두리 안에 이진 패턴이 있는 정사각형 시각 코드입니다. 이 마커는 포즈 추정, 카메라 보정, 로보틱스, 증강 현실에 사용할 수 있는 알려진 이미지 점을 제공할 수 있습니다. 다만 마커를 감지하는 것만으로는 마커의 포즈를 계산하지 않습니다.

다음 Python 예시는 먼저 호출할 OpenCV 및 ArUco 속성이 모두 있는지 확인한 뒤, 이미지를 읽고 미리 정의된 사전을 선택해 cv2.aruco.detectMarkers()를 호출하는 과정을 보여 줍니다. 이미지 경로를 자신의 파일 경로로 바꾸세요. 설치된 빌드에 필요한 속성이 없으면 예시는 안내 메시지를 출력하고 해당 속성을 사용하기 전에 중단합니다. 이 예시는 여기서 실행하지 않았습니다. 사용 중인 설치 환경에서 사용할 수 있는 API는 OpenCV 문서에서 확인하세요.

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은 페이로드 비트가 4×4이고 마커 코드 100개를 포함합니다. 사전의 수용량과 개별 마커 ID는 서로 다른 개념입니다. 각 ID는 해당 사전에 있는 코드 하나를 식별합니다. 감지기가 예상한 패턴을 확인할 수 있도록 마커 생성과 감지에 같은 사전을 사용하세요. 예시는 ID와 함께 마커의 네 모서리 좌표를 출력하고, 반환된 감지 결과의 윤곽선을 그리며, 첫 번째 모서리 근처에 각 ID를 표시한 뒤 주석이 추가된 사본을 저장합니다. 진단이 필요하면 rejected에서 거부된 후보를 확인할 수 있지만, 이 후보가 확인된 마커라는 뜻은 아닙니다.

ArUco 사전, ID, 감지 결과 이해하기

사전은 OpenCV가 인식할 비트 패턴의 집합을 정의합니다. DICT_4X4_100에서는 각 코드의 페이로드 비트가 4×4이고 사전에 코드 100개가 들어 있습니다. ID는 개별 항목을 식별하며, 가장 큰 유효 ID가 항목의 개수를 뜻하지는 않습니다. 감지기는 선택한 사전을 기준으로 후보 영역을 비교하므로, 마커를 만들 때 사용한 것과 다른 사전을 선택하면 마커를 찾지 못하거나 다르게 디코딩할 수 있습니다.

detectMarkers()는 corners, ids, rejected 세 값을 반환합니다. corners의 각 항목에는 감지된 사각형 하나를 이루는 네 점의 이미지 좌표가 들어 있습니다. 이에 대응하는 ids 행에는 해당 마커의 ID가 들어 있습니다. 디코딩된 마커가 없으면 ids는 None입니다. rejected에는 선택한 사전의 마커로 디코딩되지 않은 사각형 후보가 들어 있습니다. 이는 유용한 진단 정보지만, 거부된 모양이 모두 마커라는 증거는 아닙니다.

이 함수는 마커를 찾아 디코딩하지만 카메라 포즈를 추정하지는 않습니다. 포즈를 추정하려면 감지 결과 외에도 카메라 보정 정보와 마커의 실제 크기가 필요합니다.

감지한 마커 그리기 및 레이블 표시하기

빠르게 이미지를 덧씌우려면 이미지, 반환된 모서리 배열, ID를 cv2.aruco.drawDetectedMarkers()에 전달하세요. 예시에는 사용자 지정 레이블을 추가하는 방법도 있습니다. cv2.putText()를 사용해 각 마커의 첫 번째 모서리에 ID를 표시합니다. 더 세밀하게 그리려면 cv2.line()으로 사각형의 변을 그리거나 cv2.circle()로 중심을 표시할 수 있습니다. 관련 cv2.putText() 안내에서 텍스트의 위치와 스타일을 확인할 수 있습니다.

컬러 이미지에서 OpenCV의 그리기 색상은 BGR 채널 순서를 사용하므로 (255, 0, 0)은 빨간색이 아니라 파란색입니다. 흑백 이미지에는 단일 명도 값을 사용하세요. 주석 좌표가 이미지 범위 안에 있도록 하고, 표시될 이미지 크기에서도 선 두께와 텍스트 크기가 잘 보이도록 선택하세요.

감지 결과 확인하기

저장된 주석 이미지를 열거나 화면에 표시해 윤곽선이 감지된 마커 모서리를 따라가는지, 각 레이블이 해당 모서리 좌표와 함께 출력된 ID와 일치하는지 확인하세요. corners가 비어 있고 ids가 None이면 디코딩된 마커가 없는 것입니다. 이미지가 제대로 불러와졌는지, 마커가 판독할 만큼 크고 선명한지, 선택한 사전이 마커 생성에 사용한 사전과 같은지 확인하세요. 흐림, 반사광, 원근 왜곡, 잘린 이미지, 작은 마커는 코드를 읽기 어렵게 만들 수 있으므로 입력 이미지를 개선하면 도움이 될 수 있습니다.

API 세부 정보는 OpenCV ArUco 감지 문서를 참조하세요. 이 예시는 설명을 위한 것이며 실행되지 않았으므로, 예시의 메시지와 저장 이미지에 대한 설명은 실제로 관찰된 출력이 아닙니다.