15장. 비디오 처리와 실시간 영상처리
프레임 차이로 움직임 찾기
틀린 그림 찾기는 두 그림을 나란히 놓고 다른 곳을 찾는 놀이입니다. 같은 자리에 같은 것이 있으면 넘어가고, 달라진 곳에 동그라미를 칩니다. 움직이는 물체를 찾는 가장 쉬운 방법도 이것입니다. 앞 프레임과 지금 프레임을 칸마다 빼면, 그대로인 배경은 0 이 되고 물체가 움직인 곳만 숫자가 남습니다.
그림의 다섯 단계는 앞 장들에서 배운 도구를 이어 붙인 것입니다. 차이는 cv2.absdiff, 이진화는 8장의 cv2.threshold, 다듬기는 9장의 팽창이나 열기, 상자 그리기는 12장에서 본 윤곽선과 Bounding Box 입니다. 여기서 두 그림을 나란히 놓는 일이 앞뒤 프레임을 고르는 일이고, 동그라미를 치는 일이 상자를 그리는 일입니다.
그림은 마당 동영상(ch15_yard.mp4)에서 이웃한 두 장의 차이입니다. 차이 그림에서 빨간 공과 파란 수레가 있던 자리만 밝습니다. 공은 속이 같은 색이라, 앞 장과 겹치는 가운데는 차이가 없어 초승달 두 개처럼 테두리 쪽만 남습니다. 이것이 프레임 차이의 약점입니다.
왜 absdiff 일까
uint8 끼리 그냥 빼면 음수가 0~255 안으로 되돌아 들어가(1장에서 본 넘침) 엉뚱한 큰 값이 됩니다. cv2.absdiff 는 부호를 뗀 차이를 구합니다.
| 앞 칸 | 지금 칸 | 그냥 빼기(지금 − 앞) | cv2.absdiff |
|---|---|---|---|
| 60 | 50 | 50 − 60 = −10 → 246 | 10 |
| 50 | 60 | 10 | 10 |
| 200 | 200 | 0 | 0 |
import cv2
import numpy as np
prev = np.array([[60, 50, 200]], dtype=np.uint8)
cur = np.array([[50, 60, 200]], dtype=np.uint8)
print(cur - prev) # 결과: [[246 10 0]] → 음수가 246 으로 넘쳤다
print(cv2.absdiff(cur, prev)) # 결과: [[10 10 0]] → 부호를 뗀 차이
# 차이가 25 보다 큰 칸만 "움직임"(255)으로 본다(8차시의 이진화)
_, mask = cv2.threshold(cv2.absdiff(cur, prev), 25, 255, cv2.THRESH_BINARY)
print(mask) # 결과: [[0 0 0]] → 10 은 잡음 정도라 움직임이 아니다주의할 점
- 카메라 잡음과 동영상 압축 때문에 가만히 있는 배경도 차이가 0 이 아닙니다. 그래서 이진화 기준값(위에서는 25)으로 작은 차이를 버리고, 블러를 먼저 걸면 더 깨끗합니다.
- 물체가 멈추면 차이가 0 이 되어 사라집니다. 물체가 천천히 움직이면 테두리만 조금 잡힙니다. 이럴 때는 다음 절의 배경 빼기가 낫습니다.