카메라 좌표와 월드 좌표 개념 잡기: Intrinsic / Extrinsic 기초

대상: ROS, OpenCV, SLAM, Vision 기반 로봇 개발 중 “카메라 좌표계가 뭐고, extrinsic이 왜 필요한지” 헷갈리는 개발자
환경: Ubuntu 20.04 + ROS Noetic + OpenCV / cv_bridge


1. 문제/주제 요약

카메라 데이터를 다루다 보면 다음과 같은 혼란을 자주 겪습니다 👇

  • 이미지 좌표 $(u, v)$ 와 실제 3D 좌표 $(X, Y, Z)$ 는 어떻게 연결되는가?
  • camera_infoK, D, R, P는 뭘 의미하는가?
  • 카메라가 “세계를 보는 방향”을 어떻게 수학적으로 표현하나?
  • SLAM이나 AprilTag 위치 추정에서 왜 extrinsic 보정이 필요한가?

이 글에서는 카메라 좌표 → 월드 좌표 변환의 개념
intrinsic, extrinsic 두 축으로 간단히 정리합니다.


2. 카메라 좌표계 기본 구조

카메라 관련 좌표계는 일반적으로 아래와 같이 3단계로 구분됩니다:

[World Coordinate]  →  [Camera Coordinate]  →  [Image Coordinate]
     (Xw, Yw, Zw)          (Xc, Yc, Zc)           (u, v)
단계의미변환
월드 좌표 (World)로봇, 지도, 3D 공간의 기준 좌표계SLAM, TF 등에서 기준
카메라 좌표 (Camera)카메라 렌즈 중심을 원점으로 한 좌표계Extrinsic (R, t)
이미지 좌표 (Image)2D 픽셀 좌표 (u, v)Intrinsic (K)

3. Extrinsic Parameters — “카메라의 위치와 자세”

Extrinsic은 카메라가 세상 안에서 어디 있고, 어디를 보는지를 나타냅니다.

수식적으로는 아래처럼 표현됩니다:

$$\begin{bmatrix} X_c \ Y_c \ Z_c \end{bmatrix}
= R \begin{bmatrix} X_w \ Y_w \ Z_w \end{bmatrix} + t$$

  • $$R$$: 회전 행렬 (3×3)
  • $$t$$: 이동 벡터 (3×1)

즉, 월드 좌표 → 카메라 좌표 변환입니다.

  • $$R$$: 카메라가 바라보는 방향
  • $$t$$: 카메라의 위치(월드 기준)

예시:

R = [0.999  0.002  0.045;
     -0.002 1.000  0.001;
     -0.045 -0.001 0.999]

t = [0.05, 0.10, 0.30]  # 카메라가 로봇 바닥에서 30cm 위

💡 ROS에서는 이 변환이 tf로 표현됩니다.
예: base_link → camera_link 변환이 extrinsic과 동일한 의미입니다.


4. Intrinsic Parameters — “카메라 내부 광학 특성”

Intrinsic은 **카메라 자체의 내부 설정(렌즈 특성)**을 나타냅니다.
이는 3D 점을 이미지 픽셀 좌표로 변환할 때 사용됩니다.

기본 수식:

$$s\begin{bmatrix} u \ v \ 1 \end{bmatrix}K
\begin{bmatrix} X_c \ Y_c \ Z_c \end{bmatrix}
$$

Intrinsic Matrix $K$:

$$
K =
\begin{bmatrix}
f_x & 0 & c_x \
0 & f_y & c_y \
0 & 0 & 1
\end{bmatrix}
$$

기호의미
$$f_x, f_y$$초점 거리 (픽셀 단위)
$$c_x, c_y$$이미지 중심 좌표 (principal point)
$$s$$스케일 (Zc에 비례)

예시 (640×480 카메라):

K: [525.0, 0.0, 319.5,
    0.0, 525.0, 239.5,
    0.0, 0.0, 1.0]

💡 ROS에서는 /camera/camera_info 토픽에 포함되어 있으며,
image_proc, depth_image_proc, aruco_detect 등에서 사용됩니다.


5. Intrinsic + Extrinsic 결합: 3D → 2D 투영

전체 변환을 합치면 다음과 같습니다:

$$s
\begin{bmatrix} u \ v \ 1 \end{bmatrix}

K [R|t]
\begin{bmatrix} X_w \ Y_w \ Z_w \ 1 \end{bmatrix}
$$

즉,

  • [R|t] : 월드 → 카메라 좌표 (extrinsic)
  • K : 카메라 내부 투영 (intrinsic)

이 조합을 통해 월드상의 3D 점이 이미지 상의 $(u,v)$ 로 투영됩니다.

예시 Python 코드 (OpenCV):

import cv2
import numpy as np

K = np.array([[525, 0, 319.5],
              [0, 525, 239.5],
              [0, 0, 1]])
R = np.eye(3)
t = np.array([[0], [0], [0.3]])  # 카메라가 30cm 위

point_3d = np.array([[1.0, 0.0, 2.0]])  # (Xw, Yw, Zw)
proj, _ = cv2.projectPoints(point_3d, cv2.Rodrigues(R)[0], t, K, None)
print(proj)

출력 예시:

[[[582.4, 312.7]]]

→ 실제 3D 점이 이미지 좌표 (582, 312)에 투영됨.


6. ROS 관점에서의 Intrinsic / Extrinsic

개념ROS 표현관련 토픽 / 노드
Intrinsic/camera_infoimage_proc, cv_bridge
ExtrinsicTF 변환base_link → camera_link, map → camera
보정(calibration)camera_calibration 패키지rosrun camera_calibration cameracalibrator.py

TF 트리 예시:

map
 └── odom
      └── base_link
           └── camera_link

⚙️ SLAM이나 AprilTag 위치 추정 시,
“카메라가 로봇에서 몇 cm 옆으로 붙어 있는가”가 바로 extrinsic입니다.
TF를 정확히 맞추지 않으면 좌표 계산이 엉뚱하게 됩니다.


7. 시각적 요약

     World (Xw, Yw, Zw)
          │   ↑
     [R|t]│   │ Extrinsic
          ▼   │
     Camera (Xc, Yc, Zc)
          │   ↑
          │   │ Intrinsic
          ▼   │
     Image (u, v)

8. 자주 하는 실수 & 팁

증상원인해결 방법
Depth → 3D 변환 값 이상Intrinsic K 행렬 잘못됨/camera_info 실제 값 사용
카메라와 로봇 좌표 불일치TF(base_link→camera_link) 오차static_transform_publisher 수정
이미지 왜곡 발생렌즈 왜곡 계수 D 미적용image_proc로 rectify 필요
3D→2D 매핑 뒤집힘좌표계 축 방향 혼동OpenCV (x→right, y→down, z→forward) 주의
ArUco 위치가 반대로 나옴Extrinsic 행렬의 회전(R) 방향 오류cv2.Rodrigues 변환 확인

9. 정리

구분의미ROS 연계예시
Intrinsic카메라 내부 특성 (초점, 중심, 왜곡)/camera_infoK, D
Extrinsic카메라의 위치·방향 (로봇 대비)tfbase_link → camera_link
전체 변환월드 → 카메라 → 이미지SLAM, Visual Odometry`K[R

📌 요약

  • Intrinsic = 카메라 “내부 렌즈 정보”
  • Extrinsic = 카메라 “세상 속 위치와 방향”
  • 전체 투영:
    $$
    s [u, v, 1]^T = K [R|t] [X, Y, Z, 1]^T
    $$
  • ROS에서는 camera_info + tf로 자동 반영됨
  • SLAM, Visual Odometry, AprilTag 인식 등은 모두 이 변환을 기반으로 동작

댓글 남기기