OpenCV 비전 실무15장 · 비디오 처리와 실시간 영상처리8 / 22← 이전목차다음 →MetaContents

15장. 비디오 처리와 실시간 영상처리

프레임 차이로 움직임 찾기

틀린 그림 찾기는 두 그림을 나란히 놓고 다른 곳을 찾는 놀이입니다. 같은 자리에 같은 것이 있으면 넘어가고, 달라진 곳에 동그라미를 칩니다. 움직이는 물체를 찾는 가장 쉬운 방법도 이것입니다. 앞 프레임과 지금 프레임을 칸마다 빼면, 그대로인 배경은 0 이 되고 물체가 움직인 곳만 숫자가 남습니다.

앞 프레임, 차이 구하기, 이진화, 다듬기, 상자 그리기의 다섯 단계를 이은 흐름도

그림의 다섯 단계는 앞 장들에서 배운 도구를 이어 붙인 것입니다. 차이는 cv2.absdiff, 이진화는 8장의 cv2.threshold, 다듬기는 9장의 팽창이나 열기, 상자 그리기는 12장에서 본 윤곽선과 Bounding Box 입니다. 여기서 두 그림을 나란히 놓는 일이 앞뒤 프레임을 고르는 일이고, 동그라미를 치는 일이 상자를 그리는 일입니다.

마당 동영상의 34번과 35번 프레임, 두 프레임의 차이, 이진화한 움직임 마스크를 나란히 놓은 그림

그림은 마당 동영상(ch15_yard.mp4)에서 이웃한 두 장의 차이입니다. 차이 그림에서 빨간 공과 파란 수레가 있던 자리만 밝습니다. 공은 속이 같은 색이라, 앞 장과 겹치는 가운데는 차이가 없어 초승달 두 개처럼 테두리 쪽만 남습니다. 이것이 프레임 차이의 약점입니다.

왜 absdiff 일까

uint8 끼리 그냥 빼면 음수가 0~255 안으로 되돌아 들어가(1장에서 본 넘침) 엉뚱한 큰 값이 됩니다. cv2.absdiff 는 부호를 뗀 차이를 구합니다.

앞 칸지금 칸그냥 빼기(지금 − 앞)cv2.absdiff
605050 − 60 = −10 → 24610
50601010
20020000
Python
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 이 되어 사라집니다. 물체가 천천히 움직이면 테두리만 조금 잡힙니다. 이럴 때는 다음 절의 배경 빼기가 낫습니다.
← 이전 절15장 · 동영상 저장하기다음 절 →15장 · 배경 빼기