"진짜 두개골에서 눈이 어디 있는지 알아. 사진에서 어디 찍혔는지도 알고. solvePnP 는 그 사이를 잇는 카메라를 찾아."
solvePnP 가 답하는 질문
Perspective-n-Point, 줄여서 solvePnP 는 앞 레슨을 정확히 뒤집은 거야. 정방향은 자세를 받아 픽셀을 내놨지. 이건 픽셀을 받아 자세를 내놔. 구체적으로 보면 이래. 표준 머리 위에서 위치를 아는 3D 점들이 있고, 그 이목구비가 사진에 찍힌 2D 픽셀도 있어. 솔버는 그 3D 점들을 pinhole 모델로 통과시켰을 때 정확히 그 픽셀에 떨어지게 만드는 회전과 이동을 찾아내. 그 회전이 머리의 방향이야. 눈으로 어림한 게 아니라 계산해서 얻은 투시 상자지.
짝이 연료다
솔버는 짝을 먹고 돌아. 2D 픽셀 하나와 3D 점 하나를 묶은 짝이야. 3D 쪽은 표준 머리에서 와. 모든 landmark 의 위치를 아는 중립 얼굴이지. 2D 쪽은 검출기(다음 트랙)가 알려줘. 그 landmark 가 이 사진 어디에 나타났는지. 둘은 번호로 묶여. 사진의 33번이 모델의 33번이야. 그래서 검출기 출력과 표준 모델이 같은 번호 체계를 유지해야 해. 한쪽 번호만 바뀌면 모든 짝이 소리 없이 거짓말을 하게 되거든.
reprojection error 를 줄인다
모든 픽셀을 완벽히 맞히는 자세는 대개 없어. 진짜 얼굴은 중립 모델이 아니고 검출도 흔들리니까. 그래서 solvePnP 는 가장 가까운 자세를 찾아. 3D 점을 투영해서 찍힌 자리와 실제로 관측된 자리 사이 거리를 다 더한 값, 그러니까 reprojection error 를 최소로 만드는 거지. 남은 오차는 부산물이 아니라 엔진의 정직 계기야. 작으면 자세가 얼굴을 잘 설명한다는 뜻이고, 크면 무리해서 맞춘 값이니 덜 믿으라는 뜻이야. 솔버가 줄이려는 그 숫자가 나중에 화면에 신뢰도로 뜨는 바로 그 숫자고.
회전에서 상자로
솔버는 회전을 압축된 형태인 회전 벡터로 돌려주고, 그걸 펴면 머리의 상자 방향인 3×3 회전 행렬이 돼. 이 행렬을 사람이 읽는 yaw, pitch, roll 로 바꾸는 건 그 자체로 작은 지뢰밭이야. 순진하게 분해하면 거의 정면인 얼굴에서 값이 엉키거든. 그래서 Loomis 는 머리의 forward 와 up 벡터에서 각도를 읽어. 그 이야기는 두 레슨 뒤에 제대로 하고, 지금은 깔끔한 요약만 챙기자. 짝이 들어가고 자세가 나온다. 오차는 영수증이다.