정지 사진에서 잘 되던 인식이 영상에서는 결과가 떨립니다. 한 프레임은 "홍길동", 다음 프레임은 "미등록자", 그다음은 다시 "홍길동". 사람은 그대로인데 판정이 깜빡이는 것입니다. 이 장에서는 프레임 사이의 흔들림을 다스리는 두 기법, 트래킹과 보팅을 다룹니다.
왜 떨리는가
영상의 매 프레임은 미세하게 다릅니다. 조명이 흔들리고, 얼굴이 살짝 움직이고, 검출 박스가 조금씩 달라집니다. 이 작은 차이가 임계값 근처에서 판정을 뒤집습니다. 한 프레임만 보고 판단하면, 이 순간의 흔들림이 그대로 결과에 드러납니다.
해법의 핵심은 단순합니다. 한 프레임이 아니라 여러 프레임을 함께 보는 것입니다. 그러려면 먼저 "프레임 사이에서 같은 얼굴을 이어서 따라가는" 트래킹이 필요합니다.
간단한 트래킹 — 박스를 이어 붙이기
복잡한 추적 알고리즘 없이도, 프레임 간 박스의 겹침이나 중심점 거리로 "같은 얼굴"을 이을 수 있습니다. 이전 프레임의 박스와 가장 많이 겹치는(또는 가장 가까운) 현재 박스를 같은 사람으로 봅니다.
# 파일: simple_track.py"""IoU(겹침)로 프레임 간 같은 얼굴을 잇는 최소 트래커."""def iou(a, b): # a, b: (x1, y1, x2, y2) ix1, iy1 = max(a[0], b[0]), max(a[1], b[1]) ix2, iy2 = min(a[2], b[2]), min(a[3], b[3]) inter = max(0, ix2 - ix1) * max(0, iy2 - iy1) area_a = (a[2] - a[0]) * (a[3] - a[1]) area_b = (b[2] - b[0]) * (b[3] - b[1]) return inter / (area_a + area_b - inter + 1e-6)def match(prev_boxes, cur_box, thr=0.3): # 이전 박스들 중 현재 박스와 가장 많이 겹치는 것의 id를 찾는다 best_id, best = None, thr for tid, pbox in prev_boxes.items(): score = iou(pbox, cur_box) if score > best: best_id, best = tid, score return best_id # 없으면 None(새 얼굴)
iou는 두 박스가 얼마나 겹치는지(0~1)를 재고, match는 이전 박스들 중 현재 박스와 가장 많이 겹치는 것을 같은 얼굴로 잇습니다. 겹침이 기준 이하면 새로 등장한 얼굴(None)로 봅니다. 이렇게 각 얼굴에 일관된 id를 부여하면, 그 id의 결과를 여러 프레임에 걸쳐 모을 수 있습니다.
프레임 보팅 — 다수결로 안정화
같은 id의 얼굴이 최근 여러 프레임에서 어떤 이름으로 인식됐는지 모아, 가장 많이 나온 이름을 최종 결과로 삼습니다. 순간의 오인은 다수에 묻혀 사라집니다.
# 파일: voting.py"""최근 N프레임의 인식 결과를 다수결로 합친다."""from collections import deque, Counterhistory = {} # 얼굴 id → 최근 결과 큐def vote(track_id, name, window=7): q = history.setdefault(track_id, deque(maxlen=window)) q.append(name) # 최근 window개 중 가장 많이 나온 이름 return Counter(q).most_common(1)[0][0]
deque(maxlen=window)가 최근 N개 결과만 유지하고, Counter가 그중 최빈값을 고릅니다. 7프레임 중 6번 "홍길동", 1번 "미등록자"라면 결과는 "홍길동"으로 안정됩니다. 한 프레임의 흔들림이 전체를 뒤집지 못하게 막는 것입니다.
같은 얼굴 id 부여] B --> C[id별 최근 결과 모으기] C --> D[다수결 보팅] D --> E[안정된 판정]
안정화의 부수 효과
보팅과 트래킹은 안정성만 주는 게 아닙니다.
- 속도 절약: 트래킹으로 같은 얼굴임을 알면, 매 프레임 무거운 인식을 다시 하지 않고 몇 프레임에 한 번만 인식해도 됩니다(PART 06·07).
- 확신 판단: 보팅 결과가 7표 중 7표면 확실, 4:3이면 애매로 다룰 수 있어 신뢰도 판단에도 쓰입니다.
실무 팁. 보팅 윈도가 너무 길면(예: 30프레임) 반응이 느려져, 실제로 사람이 바뀌었는데도 한동안 이전 이름을 유지합니다. 너무 짧으면(예: 2프레임) 안정화 효과가 약합니다. 초당 프레임 수에 맞춰 0.5~1초 분량(예: 30fps면 약 15프레임)을 윈도로 두는 것이 출발점입니다. 반응 속도와 안정성 사이에서 환경에 맞게 조정하세요.
이 장에서 기억할 것
영상의 떨림은 한 프레임만 보기 때문이며, 여러 프레임을 함께 보면 잦아듭니다. IoU나 중심점 거리로 프레임 간 같은 얼굴을 이어 id를 부여하고(간단 트래킹), 그 id의 최근 N프레임 결과를 다수결로 합치면(보팅) 순간 오인이 사라집니다. 이는 속도 절약과 신뢰도 판단의 부수 효과도 줍니다. 보팅 윈도는 0.5~1초 분량이 출발점입니다. 다음 장에서는 추론 자체를 빠르게 만드는 성능 최적화로 들어갑니다.