본문 바로가기
C.W.K.
Stream
Lesson 04 of 05 · published

좌우는 절대 뒤집지 않는다

~13 min · chirality, no-flip, euler, stability

Level 0빈 종이
0 XP0/35 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"거의 대칭인 얼굴에다 '오차 낮은 쪽 고르기' 를 붙이면, 가끔 머리를 뒤로 돌려버리는 기계가 완성돼."

대칭 얼굴이 함정이다

사람 얼굴은 좌우가 거의 대칭이야. 그 순진한 사실이 카메라 계산에는 지뢰고. 왼쪽과 오른쪽이 거의 같으니까, 머리가 한쪽을 보는 답과 그걸 거울로 뒤집은 답이 거의 같은 오차로 landmark 에 맞아떨어져. 기하학적으로는 정반대인데, yaw 가 180도쯤 차이 나는데도 숫자로는 거의 동점이야. 데이터가 둘을 거의 못 갈라줘.

오차로 좌우를 정하지 마

솔깃한 임시방편이 저절로 떠올라. 정상과 뒤집힌 버전을 둘 다 풀어보고 오차가 낮은 쪽을 쓰자는 거지. 튼튼해 보이지? 동전 던지기야. 두 답이 수치 노이즈 차이로 갈릴 때 '낮은 오차 고르기' 는 좌우를 무작위로 정하는 장치가 돼. 대부분 사진은 운 좋게 맞고, 그러다 landmark 하나가 1픽셀 움직이는 순간 머리가 홱 돌아 뒤를 봐. 이 버그가 Loomis 에서 실제로 났어. 그래서 규칙이 이렇게 무뚝뚝해. 오차를 비교해서 좌우 뒤집힘을 고르지 마라.

고르는 데가 아니라 세우는 데서 고친다

진짜 해법은 두 후보 중에 더 똑똑하게 고르는 게 아니야. 애초에 틀린 후보가 안 만들어지게 하는 거지. 표준 머리는 y 축이 위, z 축이 보는 사람 쪽으로 정의돼 있고, x 축을 중심으로 180도 돌리면 OpenCV 카메라 기준에 정확히 맞아. 이 변환을 한 번 제대로 세워두면 solvePnP 가 좌우를 알아서 맞춰. 고를 두 번째 후보도 없고, 틀릴 검사도 없어. 이 가족이 계속 지키는 규율이 이거야. 증상을 하류에서 때우지 말고 모호함을 근원에서 없애라.

각도는 Euler 말고 벡터에서 읽는다

되찾은 회전을 사람이 읽는 yaw, pitch, roll 로 바꾸는 데도 사촌뻘 함정이 있어. 뻔한 방법인 Euler 분해는 값이 감기고 짐벌락에 걸려서, 하필 깔끔한 값이 제일 필요한 정면 얼굴에서 쓰레기를 내놔. 이 버그도 실제로 났고. 해법은 분해를 아예 건너뛰고 머리 자신의 forward 와 up 벡터에서 각도를 읽는 거야. 회전 행렬의 열이지. 정면에서도 안 흔들리고 뜻이 하나로 정해져. 함정 둘, 교훈 하나야. 얼굴이 대칭이거나 정면일 때 순진한 수치는 거짓말을 해. 그러니 그 거짓말이 아예 만들어질 수 없게 기하를 세워둬.

Code

동전 던지기 임시방편 대 구조적 해법·python
# WRONG (a real bug we hit): pick chirality by comparing reprojection error.
# Faces are near-symmetric, so both fits score almost the same -- this is a
# coin toss that randomly flips yaw by ~180 degrees on noisy detections.
fit_a = solve(landmarks, canonical)
fit_b = solve(landmarks, mirror(canonical))
best  = fit_a if fit_a.err < fit_b.err else fit_b   # <-- DON'T. noise decides.

# RIGHT: build the canonical -> camera transform correctly ONCE (a proper
# 180-degree rotation about x). Then solvePnP recovers handedness unaided --
# there is no second candidate and no flip test.
R, t = solve(landmarks, CANONICAL_IN_CAMERA_FRAME)

# And read angles from the head's OWN axes, never an Euler decomposition:
fwd, up = R[:, 2], R[:, 1]     # forward + up vectors, stable on frontal faces
yaw, pitch, roll = angles_from_vectors(fwd, up)   # NOT RQDecomp3x3 (it wraps)

External links

Exercise

네 분야에서 대칭 때문에 생기는 모호함을 하나 찾아봐. 크기만으론 못 정하는 부호, 이차식의 두 근, 180도까지만 정해지는 위상 같은 거. 그 예에서 '둘 다 계산하고 점수 좋은 쪽 쓰기' 가 어떻게 생겼을지 적어보고, 둘이 거의 동점일 때 왜 그게 사실상 무작위인지 설명해봐. 마지막으로 옳은 답만 나올 수 있게 만드는 구조적 해법을 스케치해.
Hint
패턴은 늘 같아. 거의 똑같은 두 후보 사이에서 나중에 고르는 장치는 노이즈에 휘둘려. 구조적 해법은 빠진 정보를 더 앞에서 넣어. 관례든 제약이든 좌표계 방향이든. 그래서 모호한 짝이 애초에 둘 다 생기지 않게 하는 거지. Loomis 는 그걸 변환에 밀어 넣었고, 네 해법도 세우는 단계로 밀어 넣으면 돼.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인 — 댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.