"거의 대칭인 얼굴에다 '오차 낮은 쪽 고르기' 를 붙이면, 가끔 머리를 뒤로 돌려버리는 기계가 완성돼."
대칭 얼굴이 함정이다
사람 얼굴은 좌우가 거의 대칭이야. 그 순진한 사실이 카메라 계산에는 지뢰고. 왼쪽과 오른쪽이 거의 같으니까, 머리가 한쪽을 보는 답과 그걸 거울로 뒤집은 답이 거의 같은 오차로 landmark 에 맞아떨어져. 기하학적으로는 정반대인데, yaw 가 180도쯤 차이 나는데도 숫자로는 거의 동점이야. 데이터가 둘을 거의 못 갈라줘.
오차로 좌우를 정하지 마
솔깃한 임시방편이 저절로 떠올라. 정상과 뒤집힌 버전을 둘 다 풀어보고 오차가 낮은 쪽을 쓰자는 거지. 튼튼해 보이지? 동전 던지기야. 두 답이 수치 노이즈 차이로 갈릴 때 '낮은 오차 고르기' 는 좌우를 무작위로 정하는 장치가 돼. 대부분 사진은 운 좋게 맞고, 그러다 landmark 하나가 1픽셀 움직이는 순간 머리가 홱 돌아 뒤를 봐. 이 버그가 Loomis 에서 실제로 났어. 그래서 규칙이 이렇게 무뚝뚝해. 오차를 비교해서 좌우 뒤집힘을 고르지 마라.
고르는 데가 아니라 세우는 데서 고친다
진짜 해법은 두 후보 중에 더 똑똑하게 고르는 게 아니야. 애초에 틀린 후보가 안 만들어지게 하는 거지. 표준 머리는 y 축이 위, z 축이 보는 사람 쪽으로 정의돼 있고, x 축을 중심으로 180도 돌리면 OpenCV 카메라 기준에 정확히 맞아. 이 변환을 한 번 제대로 세워두면 solvePnP 가 좌우를 알아서 맞춰. 고를 두 번째 후보도 없고, 틀릴 검사도 없어. 이 가족이 계속 지키는 규율이 이거야. 증상을 하류에서 때우지 말고 모호함을 근원에서 없애라.
각도는 Euler 말고 벡터에서 읽는다
되찾은 회전을 사람이 읽는 yaw, pitch, roll 로 바꾸는 데도 사촌뻘 함정이 있어. 뻔한 방법인 Euler 분해는 값이 감기고 짐벌락에 걸려서, 하필 깔끔한 값이 제일 필요한 정면 얼굴에서 쓰레기를 내놔. 이 버그도 실제로 났고. 해법은 분해를 아예 건너뛰고 머리 자신의 forward 와 up 벡터에서 각도를 읽는 거야. 회전 행렬의 열이지. 정면에서도 안 흔들리고 뜻이 하나로 정해져. 함정 둘, 교훈 하나야. 얼굴이 대칭이거나 정면일 때 순진한 수치는 거짓말을 해. 그러니 그 거짓말이 아예 만들어질 수 없게 기하를 세워둬.