LoginSignup
71
90

More than 5 years have passed since last update.

OpenCVで動画の背景と動体を分離してみる

Last updated at Posted at 2016-08-01

はじめに

OpenCV(Open Source Computer Vision Library)はBSDライセンスの映像/画像処理ライブラリ集です。画像のフィルタ処理、テンプレートマッチング、物体認識、映像解析、機械学習などのアルゴリズムが多数用意されています。

OpenCVを使った動体追跡の例 (OpenCV Google Summer of Code 2015)
https://www.youtube.com/watch?v=OUbUFn71S4s

インストールと簡単な使い方はこちら
OpenCV 3(core + contrib)をPython 3の環境にインストール&OpenCV 2とOpenCV 3の違い&簡単な動作チェック

静止画像のフィルター処理についてはこちら
OpenCVでエッジ検出してみる

動画ファイルの処理についてはこちら
OpenCVで動画をリアルタイムに変換してみる
OpenCVでWebカメラ/ビデオカメラの動画をリアルタイムに変換してみる

今回は、定点カメラで撮影した動画を使って背景と動体を分離してみます。
監視カメラで通りがかりの人を追跡するときに、人を抽出する方法として利用することができます。

アルゴリズム

  • 背景の抽出方法

    フレームに重みづけをしながら重ねていくと、動かない部分が浮かび上がってきます。
    単純に足すのではなく、現在のフレームを足しこんだ分、背景のフレームから引き算します。
    OpenCVでは、cv2.absdiff()を使います。また、重みづけ計算の誤差を減らすため、浮動小数点(np.float32)を用いて計算します。
     

    1. ゼロ埋めした背景フレームを用意する
    2. 新しい背景 = 背景 × (1 - 重み) + 現在のフレーム × 重み
    3. ステップ2を繰り返す  
       
  • 動体の抽出方法
    差分の絶対値が動体フレームになります。
    OpenCVでは、sv2.absdiff()を使います。

      動体フレーム = |現在のフレーム - 背景|

プログラム

diff&accum.py
import cv2
import numpy as np

# 定数定義
ESC_KEY = 27     # Escキー
INTERVAL= 33     # インターバル
FRAME_RATE = 30  # fps

WINDOW_ORG = "org"
WINDOW_BACK = "back"
WINDOW_DIFF = "diff"

FILE_ORG = "org_768x576.avi"

# ウィンドウの準備
cv2.namedWindow(WINDOW_ORG)
cv2.namedWindow(WINDOW_BACK)
cv2.namedWindow(WINDOW_DIFF)

# 元ビデオファイル読み込み
mov_org = cv2.VideoCapture(FILE_ORG)

# 最初のフレーム読み込み
has_next, i_frame = mov_org.read()

# 背景フレーム
back_frame = np.zeros_like(i_frame, np.float32)

# 変換処理ループ
while has_next == True:
    # 入力画像を浮動小数点型に変換
    f_frame = i_frame.astype(np.float32)

    # 差分計算
    diff_frame = cv2.absdiff(f_frame, back_frame)

    # 背景の更新
    cv2.accumulateWeighted(f_frame, back_frame, 0.025)

    # フレーム表示
    cv2.imshow(WINDOW_ORG, i_frame)
    cv2.imshow(WINDOW_BACK, back_frame.astype(np.uint8))
    cv2.imshow(WINDOW_DIFF, diff_frame.astype(np.uint8))

    # Escキーで終了
    key = cv2.waitKey(INTERVAL)
    if key == ESC_KEY:
        break

    # 次のフレーム読み込み
    has_next, i_frame = mov_org.read()

# 終了処理
cv2.destroyAllWindows()
mov_org.release()

実行結果

org.png
                    元画像

diff.png
                    動体抽出画像

back.png
                    背景画像

歩いている人をうまく抽出することができました。

71
90
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
71
90