투영 전에 좌표계를 정한다
핀홀 모형은 3차원 점에서 카메라 중심을 지나는 광선이 영상 평면의 어느 위치로 가는지 나타낸다. 렌즈 왜곡을 먼저 제외하고, optical 프레임의 +x는 영상 오른쪽/+y는 아래/+z는 전방으로 정한다. 열벡터 p_C=(X,Y,Z)를 이 프레임에서 m 단위로 표현한다. 세계나 로봇 base 좌표를 그대로 넣지 말고 먼저 카메라 optical 좌표로 변환해야 한다. 외부 보정/프레임 계약은 M14.01에서 더 다룬다.
그림 M12.02-1. 왜곡 없는 pinhole 모델의 X/Z 단면이다. 앞쪽 가상 영상면에서 같은 광선 위 P와 2P는 같은 픽셀에 투영된다. 이 그림은 깊이 Z와 광선 거리의 차이, 한 영상만으로 깊이가 정해지지 않는 이유를 보여 준다. 직접 제작.
영상의 가로/세로 픽셀 좌표는 u/v, focal 수치 f_x/f_y와 주점 c_x/c_y는 pixel 단위다. 주점은 광축이 영상 평면과 만나는 기준 위치로 이해하며 항상 영상 정중앙이라고 가정하지 않는다. 여기서는 유효한 f_x/f_y>0, skew가 0인 표준 모형과 Z>0의 전방 점을 쓴다. 내부 행렬 K와 투영은 다음과 같다.
X/Z와 Y/Z는 무차원이라 pixel 단위 focal 수치를 곱해 픽셀을 얻는다. 물리 렌즈 초점거리의 mm 숫자와 f_x의 pixel 숫자는 다르다. 예를 들어 초점거리 4 mm, 센서 가로 6.4 mm, 영상 너비 640 pixel이라는 이상 조건이면 f_x=640×4/6.4=400 pixel이다. 실제 값은 보정 모형/영상 경로에 맞춰 확인하며 외형 사양만으로 완전한 보정을 대신하지 않는다.
가상 K에서 f_x=f_y=400, c_x=320/c_y=240, 영상 640×480이라고 하자. p_C=(0.1,0.05,1) m면 X/Z=0.1/Y/Z=0.05이므로(u,v)=(360,260) pixel이다. 같은 X/Y에서 Z=0.5 m로 가까워지면(400,280)이다. 반대로 점 전체를 2배 한(0.2,0.1,2) m는 원래와 같은(360,260)이다. 투영이 깊이에 대해 가진 모호성이 이 계산에서 드러난다.
Z=0은 나눗셈이 정의되지 않고 Z<0은 전방 영상의 보이는 점으로 승인하지 않는다. 수식이 유한해도 이미지 범위 밖이면 현재 영상에 들어온 점이 아니다. 가림/렌즈 시야·클리핑도 별도다. OpenCV 공식 calib3d의 카메라 좌표/내부 행렬 정의를 기준으로 쓴다.
왜곡은 정규화 좌표의 다른 변형이다
실제 렌즈는 핀홀에서 벗어날 수 있다. 왜곡 계수는 정한 모델과 함께 읽는다. radial과 tangential, fisheye 모형 등은 같은 계수 배열로 무조건 바꿔 끼울 수 없다. 여기서는 계산을 위해 radial 한 항만 쓰고 나머지 항을 0으로 둔 단순 모형을 명시한다. x=X/Z/y=Y/Z는 정규화 좌표, r²=x²+y², k₁은 무차원 radial 계수다. 왜곡 좌표는 x_d=x(1+k₁r²), y_d=y(1+k₁r²)이고 이를 f/c로 픽셀에 옮긴다.
별도 예로(X,Y,Z)=(0.2,0,1) m, k₁=0.1이면 r²=0.04, 배율은 1.004, x_d=0.2008이다. 위 K의 u는 400.32로 무왜곡 400보다 0.32 pixel 바깥으로 간다. k₁을 물리 m 단위 이동으로 읽거나 픽셀 u 자체에 이 배율을 바로 곱하면 다르다. 이 한 항 계산이 실제 렌즈의 모든 왜곡을 보정했다고 뜻하지는 않는다.
원본 distorted 영상과 undistorted/rectified 영상의 파라미터를 구분한다. 왜곡 제거 과정이 새 내부 행렬/잘린 영역을 만들 수 있으므로 원본 K/D를 출력 영상에 그대로 재사용하지 않는다. D는 정한 모델의 왜곡 계수 집합이다. Jazzy CameraInfo의 K/D/P와 영상 크기/프레임 계약도 확인한다.
resize와 crop은 픽셀 좌표도 바꾼다
이번 교육용 연속 좌표 변환을 u'=s u/v'=s v라고 명시하자. s=0.5로 640×480을 320×240에 대응시키면 focal과 주점도 각각 절반인 200/200/160/120이다. 원래 점(360,260)은(180,130)으로 간다. 실제 resizer의 pixel-center 규약에는 반 픽셀 이동 등이 있을 수 있으므로 이 간단한 대응을 어떤 API에도 무조건 적용하지 않는다. 영상 좌표의 실제 변환식을 기준으로 보정값을 갱신한다.
다른 변형으로 왼쪽 100/위 50 pixel에서 시작하는 crop을 하고 resize는 하지 않는다고 하자. u'=u−100/v'=v−50이므로 점은(260,210), 주점은(220,190)이 되고 focal은 400 그대로다. crop과 resize를 함께 하면 순서와 전체 좌표 변환을 적용한다. 원본/변환 영상의 해상도만 같은지 보는 것이 아니라 어떤 픽셀이 어디로 옮겨졌는지 확인한다.
영상만 절반으로 줄이고 예전 K를 쓰면 잘못된 3차원 광선을 얻는다. 예를 들어 새 u=180을 예전 f_x=400/c_x=320에 넣으면 정규화 x=−0.35이지만 바른 새 K에서는(180−160)/200=0.1이다. 모델이 돌아가도 기하가 틀리는 조용한 오류다. 이미지 변환·보정 개정/해상도·단위/프레임·취득 시각을 함께 기록한다.
한 픽셀은 광선이고 깊이가 있어야 점이 된다
왜곡이 없거나 이미 같은 모형으로 제거된 픽셀과 깊이 Z를 안다면 역투영할 수 있다. Z는 optical z축 방향 깊이다. 아래 X/Y/Z는 m이고 f/c/u/v는 같은 픽셀 좌표 체계다.
(360,260), Z=1이면 X=0.1/Y=0.05로 원래 점을 복원한다. Z를 모르면 λ를 m 단위의 양의 깊이라 두었을 때 λ(0.1,0.05,1)인 모든 점이 같은 픽셀로 간다. 단일 핀홀 투영만으로 λ를 고를 수 없다. 학습 기반 깊이 추정은 다른 자료/가정을 쓰는 추정이며 이 모호성을 기하적으로 없앤 직접 측정과 같지 않다.
range는 카메라 중심에서 점까지의 유클리드 거리로 √(X²+Y²+Z²)다. 위 점에서는 약 1.006231 m로 Z=1 m와 다르다. 센서가 range를 주는데 Z로 그대로 쓰면 광선 방향에 따라 좌표 오차가 생긴다. 반대로 range ρ를 알면 정규화 광선(x,y,1)을 그 길이√(x²+y²+1)로 나눈 단위 방향에ρ를 곱한다. 깊이 0/비유한/무효 코드·프레임/시각 불일치도 입력 정책에 따라 거부/표시한다.
기존 4.1 핀홀에서 물리 센서/좌표를 이어 볼 수 있다. 선택 투영 개념 모형은 별도 핀홀/제한된 시간 이동을 조작하는 보충이며 왜곡·rolling shutter·완전한 6자유도 운동이나 실제 보정 실행은 아니다. 아래 기본 계산은 위젯 없이 수행한다.