yg log --graph --oneline --all

Home Stack Notes AboutRSS

1. OcclusionGateNet 개발기 1 — 선글라스를 쓰면 운전자 모니터링은 어떻게 될까?

작성 · 5분 읽기 · 조회수 —

OcclusionGateNet 개발기 · 1 / 7

들어가며

TabPFN 글에서 캡스톤 프로젝트가 우수상을 받았다고 잠깐 언급했었다. 이번에는 그 프로젝트 이야기를 해보려고 한다. 이름은 OcclusionGateNet이다.

운전자 모니터링 시스템, 흔히 DMS(Driver Monitoring System) 라고 부르는 것을 만들었다. 운전자가 어떤 행동을 하는지, 어디를 보는지, 손은 어떻게 두고 있는지, 대화하고 있는지를 영상으로 분류하는 프로젝트다.

여기까지만 보면 얼굴과 자세를 추출해서 분류기에 넣으면 될 것 같다. 그런데 운전자는 항상 카메라를 향해 얼굴을 드러내고 있지 않는다. 선글라스를 쓰기도 하고, 손으로 입을 가리기도 한다. 밤에는 조명 조건도 달라진다. 잘 보이는 얼굴을 잘 분류하는 것과, 얼굴이 가려져도 판단을 유지하는 것은 다른 문제였다.

우리가 집중한 것은 두 번째였다. 한 줄로 설명하면 이렇다.

가려진 얼굴의 랜드마크를 복원하고, 얼굴이 얼마나 보이는지를 이용해 얼굴·자세 정보를 섞는 운전자 모니터링 시스템.

나는 팀에서 얼굴 랜드마크 복원 파트를 맡았고, 융합 모델과 ablation 실험에도 함께 참여했다. 그래서 이 개발기는 완성된 구조를 소개하는 데서 끝내지 않고, 복원 모델을 가져와 학습시키면서 어디서 막혔는지까지 담으려고 한다. 데이터와 학습 기록까지 함께 정리하려니 나눠 쓸 이야기가 꽤 많아졌다.

Part 1. 어두운 것과 가려진 것은 어떻게 다를까?

NIR 카메라를 쓰면 해결되는 문제

프로젝트에서는 근적외선(Near-Infrared, NIR) 영상을 사용했다. 야간 운전자 영상을 다루기 위한 선택이다. 다만 여기서 바로 구분해야 하는 것이 있다. 카메라가 어두운 환경에서 영상을 얻을 수 있다는 것과, 가려진 부위의 정보를 얻을 수 있다는 것은 같지 않다.

예를 들어 손으로 입을 가린 장면을 생각해보자. 화면을 더 밝게 만든다고 손 뒤의 입 모양이 관측되지는 않는다. 모델 입장에서는 입력이 어두운 경우와 관측해야 할 정보 자체가 빠진 경우를 다르게 다뤄야 한다.

문제 프로젝트에서 대응한 부분 남는 문제
야간·조명 변화 NIR 영상 사용, NIR 데이터로 모델 조정 센서와 촬영 환경이 달라질 때의 일반화
눈·입 등의 가림 가시성 추정, 랜드마크 복원 가린 영역의 실제 움직임은 직접 관측되지 않음
손상된 얼굴 정보가 분류에 들어감 가시성을 조건으로 한 얼굴·자세 융합 복원이 그럴듯해도 분류에 항상 도움이 되는 것은 아님

이 마지막 줄이 중요하다. 얼굴 점을 예쁘게 복원하는 것만으로 최종 운전자 행동 분류가 좋아졌다고 말할 수는 없다. 복원된 정보가 실제 판단에 도움이 되는지를 따로 확인해야 한다.

처음의 Eye-Pose에서 Face-Pose-Occ로

초기 구상은 눈과 몸의 자세를 함께 보는 Eye-Pose였다. 눈은 시선과 관련이 있고, 몸의 자세는 휴대전화 사용이나 물건을 집는 행동을 설명할 수 있다.

그런데 눈을 주요 단서로 사용하는 구조라면, 눈이 가려지는 순간 가장 중요한 입력부터 흔들린다. 그래서 최종 구조에서는 얼굴 전체 랜드마크를 사용하고, 여기에 부위별 가시성을 별도의 입력으로 추가했다. 보고서에서 Face-Pose-Occ로 정리한 방향이다.

단순히 입력 하나를 더 붙인 것은 아니다. 가시성 정보는 두 군데에서 쓰인다. 앞에서는 어느 좌표를 복원 좌표로 바꿀지 결정하고, 뒤에서는 어떤 얼굴 부위와 모달리티를 얼마나 참고할지 조절한다.

Part 2. 전체 구조를 먼저 한 번 보자

OcclusionGateNet의 얼굴·몸 두 스트림과 가시성 기반 융합 구조

저장소의 아키텍처 그림을 바탕으로, 이 글에서는 구조 설명에 집중하도록 개별 모델의 성능 숫자를 제외했다. 실제 추론 경로는 full_system 구현을 기준으로 설명한다.

왼쪽에서 오른쪽으로 따라가면 다음과 같다.

① 얼굴과 몸에서 서로 다른 단서를 얻는다

얼굴 영상에서는 YOLO 얼굴 검출기로 crop을 만들고, MediaPipe FaceMesh로 478개 얼굴 랜드마크를 추출한다. 별도의 가시성 CNN은 왼쪽 눈·오른쪽 눈·코·입이 얼마나 보이는지 추정한다.

몸 영상에서는 YOLO-Pose로 17개 관절점을 추출한다. 얼굴이 눈과 입의 세부 변화를 제공한다면, 자세는 팔과 상체의 큰 움직임을 제공하는 식이다.

여기서 랜드마크는 이미지 자체가 아니라 점의 위치다. 픽셀 전체를 최종 분류기에 넣는 대신, 얼굴과 몸의 구조를 좌표 시퀀스로 전달한다.

② 가려졌다고 판단한 얼굴 부위를 복원한다

복원 경로에는 ORFormer와 HGNet이 들어간다. ORFormer가 얼굴 구조를 나타내는 reference heatmap을 만들고, HGNet이 이를 얼굴 영상과 함께 받아 랜드마크를 예측한다.

이때 복원하는 것은 선글라스를 지운 얼굴 사진이 아니다. 뒤에서 사용할 얼굴 구조와 좌표다. 복원 이미지가 사람 눈에 자연스러운지보다, 필요한 위치 정보를 얼마나 유지하는지가 문제다.

그리고 MediaPipe 좌표를 전부 버리지 않는다. 관측 가능한 부위는 기존 좌표를 유지하고, 가림으로 판정한 부위만 정렬된 복원 좌표로 바꾼다. 이 좌표 교체와 뒤의 feature fusion은 이름에 gate가 들어가더라도 서로 다른 연산이다.

③ 여러 프레임을 모아 네 가지 출력을 낸다

최종 분류기는 48프레임 창의 얼굴·자세·가시성 정보를 받아 네 가지 과제를 함께 수행한다.

출력 현재 분류 코드의 클래스 수 예시
Action 11 정상 운전, 문자 입력, 통화, 물 마시기 등
Gaze 9 전방, 좌우 방향, 미러, 인포테인먼트 등
Hands 4 운전대에 둔 손: 양손, 왼손만, 오른손만, 없음
Talk 2 대화 여부

자료를 정리하면서 가장 먼저 확인한 것 중 하나가 이 클래스 수였다. 발표에서는 이해를 돕기 위해 과제를 간단히 묶어 표현한 부분이 있지만, 실제 학습의 정답 공간은 위와 같다. 특히 gaze를 단순한 ‘전방/비전방’ 이진 분류로 읽으면 결과를 잘못 해석하게 된다.

Part 3. 이 프로젝트에서 확인하고 싶었던 것

모델을 만들고 숫자 하나를 얻는 것보다 중요한 질문이 있었다.

첫째, 얼굴이 가려져도 기존 성능을 얼마나 유지하는가? 같은 클립의 clean/masked 조건을 비교해야 가림으로 인해 무엇이 달라졌는지 보기 쉽다.

둘째, 복원 모듈이 실제로 필요한가? MediaPipe만으로 분류했을 때와 복원 좌표까지 사용했을 때를 비교해야 한다. 복원 결과 그림만으로는 답할 수 없는 질문이다.

셋째, 가시성을 알려주는 것이 단순 결합보다 나은가? 얼굴과 자세를 이어 붙이는 것에서 끝내지 않고, 가시성을 입력으로 주었을 때와 gate를 제거했을 때를 나눠 봐야 한다.

실험에서는 이 차이가 특히 gaze에 나타났다. 다만 모든 과제에서 모든 모듈이 이긴 것은 아니다. 예를 들어 얼굴을 제거한 모델이 action에서 더 높은 점수를 낸 결과도 있다. 이 부분까지 포함해야 ‘어떤 정보가 어느 과제에 도움이 되었는가’를 이야기할 수 있다. 구체적인 수치와 해석은 6편에서 다룬다.

앞으로 쓸 이야기

이 시리즈는 다음 흐름으로 구성했다.

편 중심 질문
1. 문제와 전체 구조 왜 가림을 별도로 다뤄야 했을까?
2. 데이터 보이지 않는 얼굴의 정답은 어디서 얻을까?
3. 복원 모델 ORFormer의 codebook과 messenger는 무엇을 할까?
4. 학습 기록 왜 학습을 돌려도 같은 code만 사용했을까?
5. 융합 모델 복원한 얼굴을 얼마나 믿어야 할까?
6. 실험 어떤 모듈이 실제로 도움이 되었을까?
7. 데모와 회고 모델들을 연결하면 바로 시스템이 될까?

마지막에는 영종도에서 야간 영상을 촬영한 기록과 실제 통합 코드의 실패 처리도 다룰 예정이다. 여기서 소개하는 시스템은 캡스톤에서 구현하고 실험한 프로토타입이다. 영상 데모, 저장된 평가 결과, 실제 차량에서 요구하는 검증은 구분해서 읽으면 좋겠다.

다음 편에서는 모델보다 먼저 데이터부터 살펴본다. 가려진 얼굴을 복원하라고 학습시키려면, 가려지기 전 얼굴의 좌표를 어떻게 준비해야 할까?

참고한 자료

이 시리즈의 코드 설명은 17d4211 커밋을 기준으로 한다. 학습 당시 기록과 현재 구현이 다른 곳은 해당 편에서 구분했다.