귀퉁이 서재

OpenCV - 30. 배경 제거(Background Subtraction) 본문

OpenCV

OpenCV - 30. 배경 제거(Background Subtraction)

Baek Kyun Shin 2020. 11. 29. 22:06

이번 포스팅에서는 객체 추적 방법인 배경 제거에 대해 배워보겠습니다. 이번 포스팅 역시 '파이썬으로 만드는 OpenCV 프로젝트(이세우 저)'를 정리한 것임을 밝힙니다.

코드: github.com/BaekKyunShin/OpenCV_Project_Python/tree/master/08.match_track

객체 추적(Object Tracking)

동영상에서 지속적으로 움직이는 객체를 찾는 방법을 객체 추적이라고 합니다. 객체 추적 방법은 여러 가지가 있습니다. 몇 가지만 알아보겠습니다. 이번 포스팅에서는 배경 제거에 대해 알아보겠습니다.

배경 제거(Background Subtraction)

객체 추적을 위해 객체가 무엇인지, 어디 있는지부터 명확히 파악해야 합니다. 객체를 명확히 파악하기 위한 방법이 바로 배경 제거입니다. 배경 제거는 객체를 포함하는 영상에서 객체가 없는 배경 영상을 빼는 방법을 말합니다. 즉, 배경을 모두 제거해 객체만 남기는 방법입니다. 아래 그림을 보면 이해가 쉬울 겁니다.

출처: https://docs.opencv.org/3.4/d1/dc5/tutorial_background_subtraction.html

강 위에 배가 있는 영상에서 강만 있는 영상을 빼면 객체인 배만 남습니다.

배경 제거 함수

배경 제거를 구현하는 객체 생성 함수는 아래와 같습니다.

  • cv2.bgsegm.createBackgroundSubtractorMOG(history, nmixtures, backgroundRatio, noiseSigma)
    history=200: 히스토리 길이
    nmixtures=5: 가우시안 믹스처의 개수
    backgroundRatio=0.7: 배경 비율
    noiseSigma=0: 노이즈 강도 (0=자동)

이는 2001년 KadewTraKuPong과 Bowde의 논문(An improved adaptive background mixture model for real-time tracking with shadow detection)에 소개된 알고리즘을 구현한 함수입니다. 여러 가지 파라미터가 있지만 default 값으로 설정해도 됩니다. 추가 튜닝이 필요 없는 이상 아래의 apply() 함수 호출만으로 결과를 얻을 수 있습니다. 배경 제거 객체의 인터페이스 함수는 다음 두 가지가 있습니다.

  • foregroundmask = backgroundsubtractor.apply(img, foregroundmask, learningRate)
    img: 입력 영상
    foregroundmask: 전경 마스크
    learningRate=-1: 배경 훈련 속도(0~1, -1: 자동)
  • backgroundImage = backgroundsubtractor.getBackgroundImage(backgroundImage)
    backgroundImage: 훈련용 배경 이미지

cv2.bgsegm.createBackgroundSubtractorMOG() 함수를 활용하여 배경 제거 객체를 만들어, 실제 영상에서 배경을 제거해보겠습니다.

# BackgroundSubtractorMOG로 배경 제거 (track_bgsub_mog.py)

import numpy as np, cv2

cap = cv2.VideoCapture('../img/walking.avi')
fps = cap.get(cv2.CAP_PROP_FPS) # 프레임 수 구하기
delay = int(1000/fps)
# 배경 제거 객체 생성 --- ①
fgbg = cv2.bgsegm.createBackgroundSubtractorMOG()
while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break
    # 배경 제거 마스크 계산 --- ②
    fgmask = fgbg.apply(frame)
    cv2.imshow('frame',frame)
    cv2.imshow('bgsub',fgmask)
    if cv2.waitKey(1) & 0xff == 27:
        break
cap.release()
cv2.destroyAllWindows()

배경 제거 객체 생성시 파라미터 값은 모두 default 값으로 설정했습니다. 배경 제거 객체에 apply() 함수를 적용하여 배경이 제거된 전경 마스크를 얻었습니다. 

또 다른 배경 제거 객체 생성 함수는 다음과 같습니다.

  • cv2.createBackgroundSubtractorMOG2(history, varThreshold, detectShadows)
    history=500: 히스토리 개수
    varThreshold=16: 분산 임계 값
    detectShadows=True: 그림자 표시

이는 Z.Zivkovic의 2004년 논문(Improved adaptive Gausian mixture model for background subtraction)과 2006년 논문(Efficient Adaptive Density Estimation per Image Pixel for the Task of Background Subtraction)에 소개된 알고리즘을 구현한 함수입니다. 이 알고리즘은 영상의 각 픽셀에서 적절한 가우시안 분포 값을 선택합니다. 따라서 빛의 변화가 심한 영상에 적용하기 좋습니다. 또한, 그림자를 탐지할지 말지 선택할 수 있습니다. detectShadows=True로 설정하면 그림자를 표시하고 False로 설정하면 그림자를 표시하지 않습니다. 그림자는 회색으로 표시하고, 그림자를 표시하면 속도가 다소 느려집니다.

# BackgroundSubtractorMOG2 배경 제거 (track_bgsub_mog2.py)

import numpy as np, cv2

cap = cv2.VideoCapture('../img/walking.avi')
fps = cap.get(cv2.CAP_PROP_FPS) # 프레임 수 구하기
delay = int(1000/fps)
# 배경 제거 객체 생성 --- ①
fgbg = cv2.createBackgroundSubtractorMOG2()
while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break
    # 배경 제거 마스크 계산 --- ②
    fgmask = fgbg.apply(frame)
    cv2.imshow('frame',frame)
    cv2.imshow('bgsub',fgmask)
    if cv2.waitKey(delay) & 0xff == 27:
        break
cap.release()
cv2.destroyAllWindows()

배경 제거 객체 생성 함수만 다를 뿐 나머지 코드는 앞선 코드와 동일합니다. 실행 결과 그림자까지 표시되었습니다.

 

Comments