ArUco 마커
dictionary = cv.aruco.getPredefinedDictionary(
cv.aruco.DICT_6X6_250
)
기준 마커의 구조
ArUco 마커는 검은 테두리 안에 이진 코드를 넣은 정사각형 기준 마커(fiducial marker). 네 꼭짓점과 내부 코드를 함께 검출하여 마커의 ID와 방향을 구분.
- 내부 코드는 마커 사전(dictionary)에 등록된 ID를 표현
- 회전된 마커도 ID와 방향을 함께 식별 가능
- 네 꼭짓점이 모두 보여야 단일 마커를 안정적으로 검출 가능
- 카메라 교정값과 실제 마커 크기를 알면 위치와 자세 추정 가능
- 증강 현실, 로봇 위치 추정, 카메라 교정 등에 활용

마커 사전과 ID
마커 사전은 같은 비트 크기를 사용하는 여러 마커 코드의 집합. 마커 생성과 검출에 같은 사전 선택 필요.
| 사전 | 내부 비트 | ID 범위 |
|---|---|---|
cv.aruco.DICT_4X4_50 |
4×4 | 0–49 |
cv.aruco.DICT_5X5_100 |
5×5 | 0–99 |
cv.aruco.DICT_6X6_250 |
6×6 | 0–249 |
사전 이름의 앞 숫자는 내부 코드의 가로·세로 비트 수, 뒤 숫자는 사전에 포함된 마커 수.
마커 생성
cv.aruco.generateImageMarker()로 지정한 사전의 마커 이미지 생성.
marker_id = 23
marker_size = 400 # 출력 이미지 한 변의 픽셀 수
marker = cv.aruco.generateImageMarker(
dictionary,
marker_id,
marker_size,
)
cv.imwrite("aruco-marker-23.png", marker)
marker.shape
(400, 400)

marker_id는 선택한 사전의 ID 범위 안에서 선택. marker_size는 출력 이미지 한 변의 픽셀 수이며 실제 인쇄 크기와는 별개.
마커 검출
검출 장면은 aruco-scene.jpg. 앞에서 만든 ID 23 마커를 가상 카메라로 비스듬히 촬영한 것처럼 합성한 960×640 이미지.

검출 이미지와 같은 사전으로 cv.aruco.ArucoDetector 생성. 코너 위치를 더 정밀하게 다듬기 위해 서브픽셀 코너 보정 사용.
image = cv.imread("aruco-scene.jpg")
parameters = cv.aruco.DetectorParameters()
# 꼭짓점을 픽셀보다 작은 단위까지 다듬어 자세 추정 정확도 향상
parameters.cornerRefinementMethod = cv.aruco.CORNER_REFINE_SUBPIX
detector = cv.aruco.ArucoDetector(
dictionary, # 생성할 때와 같은 사전
parameters,
)
corners, ids, rejected = detector.detectMarkers(image)
ids
array([[23]], dtype=int32)
| 반환값 | 의미 |
|---|---|
corners |
검출된 각 마커의 네 꼭짓점 좌표 |
ids |
corners와 같은 순서의 마커 ID |
rejected |
사각형 후보였지만 사전의 코드와 일치하지 않은 영역 |
각 마커의 꼭짓점은 왼쪽 위에서 시작하여 시계 방향으로 정렬됨. detectMarkers()는 2차원 꼭짓점과 ID를 찾으며 위치와 자세를 바로 계산하지는 않음.
검출 결과 표시
cv.aruco.drawDetectedMarkers()로 검출된 마커의 경계와 ID를 이미지에 표시.
detected = image.copy() # 원본을 그대로 두고 사본에 표시
cv.aruco.drawDetectedMarkers(
detected,
corners,
ids,
)
to_pil(detected)

검출되지 않으면 먼저 사전 일치 여부 확인. 이후 마커 크기, 초점, 조명, 흰 여백, 가림, 원근 왜곡 점검.
카메라 값과 마커 좌표 정하기
자세 추정에는 카메라 행렬 mtx, 왜곡 계수 dist, 마커의 3차원 기준점 object_points가 필요.
scene_width, scene_height = 960, 640
mtx = np.array(
[
[900, 0, scene_width / 2], # 초점 거리(픽셀), 주점 x
[0, 900, scene_height / 2], # 초점 거리(픽셀), 주점 y
[0, 0, 1],
],
dtype=np.float64,
)
dist = np.zeros((5, 1), dtype=np.float64) # 왜곡 없음
mtx: 3차원 좌표를 이미지 평면으로 옮기는 카메라 행렬. 대각선의 두 값은 초점 거리, 마지막 열은 광축이 이미지와 만나는 주점(principal point). 이 장면은 초점 거리 900픽셀의 가상 카메라로 합성하고 마커를 이미지 중앙 기준으로 배치하여 주점은 이미지 중심 (480,320)으로 설정dist: 렌즈 왜곡 계수. 합성 이미지에는 렌즈 왜곡이 없으므로 모두0으로 둠
marker_length = 0.08 # 마커 한 변의 실제 길이(m)
half = marker_length / 2
object_points = np.array(
[
[-half, half, 0], # 왼쪽 위
[half, half, 0], # 오른쪽 위
[half, -half, 0], # 오른쪽 아래
[-half, -half, 0], # 왼쪽 아래
],
dtype=np.float32,
)
object_points는 마커 자체의 좌표계에서 네 꼭짓점이 어디에 있는지를 나타냄.
- 마커 중심을 원점으로 설정: 추정한
tvec은 마커 중심 위치 - 마커는 z=0인 평면. x는 오른쪽, y는 위쪽 방향
- 순서를
detectMarkers()가 반환하는 꼭짓점 순서(왼쪽 위 → 시계 방향)와 똑같이 맞춤. 순서가 어긋나면 엉뚱한 회전으로 추정됨 - 길이를 미터로 넣었으므로 결과인
tvec의 단위도 미터가 됨
마커의 위치와 자세 추정
마커의 네 꼭짓점은 평면의 3차원 기준점과 대응. object_points, mtx, dist를 cv.solvePnP()에 전달하여 회전 벡터와 이동 벡터 계산.
pose = detected.copy()
for marker_corners in corners:
image_points = marker_corners.reshape(4, 2) # (1, 4, 2)를 (4, 2)로
success, rvec, tvec = cv.solvePnP(
object_points,
image_points,
mtx,
dist,
flags=cv.SOLVEPNP_IPPE_SQUARE, # 정사각 평면 마커 전용 해법
)
if success:
cv.drawFrameAxes(
pose,
mtx,
dist,
rvec,
tvec,
marker_length / 2, # 축의 길이는 마커 절반 크기
)
to_pil(pose)

표시된 좌표축 읽기
cv.drawFrameAxes()는 추정한 rvec와 tvec를 이용하여 마커의 좌표축을 이미지 위에 표시. 세 선이 만나는 지점은 마커 중심.
| 색상 | 축 | 이미지에서 확인할 방향 |
|---|---|---|
| 빨강 | 마커의 +x축 | 마커의 오른쪽 방향 |
| 초록 | 마커의 +y축 | 마커의 위쪽 방향 |
| 파랑 | 마커의 +z축 | 마커 앞면에서 수직으로 나오는 방향 |
빨간 축과 초록 축은 화면에서 마커 평면의 회전과 기울기를 표현. 파란 축은 마커 앞면의 방향을 표현. 이 축들은 카메라 좌표축이 아니라 카메라에서 관찰한 마커 좌표축.
rvec: 좌표축을 어느 방향으로 표시할지 결정하는 마커의 회전 정보tvec: 세 좌표축을 어디에서 시작할지 결정하는 마커 중심의 위치tvec의 단위:marker_length에 사용한 단위와 동일
실제 마커 길이를 잘못 입력하면 추정한 거리의 크기도 같은 비율로 잘못됨. 카메라 교정이 정확하지 않으면 축이 흔들리거나 위치 오차가 커질 수 있음.
ArUco 보드
여러 마커의 상대 위치를 아는 보드는 일부 마커가 보이지 않아도 나머지 검출 결과를 이용 가능. 단일 마커보다 많은 꼭짓점을 사용해 보드 전체 자세를 더 안정적으로 추정하는 데 유리. cv.aruco.GridBoard로 격자 배치 정의.

ChArUco 보드
ChArUco 보드는 체커보드와 ArUco 마커를 결합. ArUco ID로 보드 위치를 구분하고 체커보드 교차점을 정밀하게 찾을 수 있어 카메라 교정과 자세 추정에 활용. cv.aruco.CharucoBoard로 정의하고 cv.aruco.CharucoDetector로 검출.

다이아몬드 마커
다이아몬드 마커는 네 개의 ArUco 마커를 체커보드 형태로 배치. 네 마커의 ID 조합으로 다이아몬드를 식별하고 가운데 영역의 코너를 정밀하게 계산.

퀴즈
ArUco 마커를 생성할 때와 검출할 때 같은 사전을 사용해야 하는 이유는?
퀴즈를 풀려면 대화형 기능을 불러와야 합니다.