Python
 Computer >> コンピューター >  >> プログラミング >> Python

PythonでWebカメラの動体検知プログラムを作成する方法

本記事では、Webカメラから取得した映像を解析して動き(モーション)を自動的に検出し、その検出された時間帯をCSVファイルに記録するPythonプログラムを作成します。監視カメラやセキュリティシステムの基礎となる技術であり、OpenCVの画像処理機能を活用した実践的な例です。

必要なライブラリ

このプログラムではOpenCVpandasを使用します。まだインストールされていない場合は、pipコマンドでインストールできます。

$ pip install opencv-python pandas

サンプルコード

# 必要なライブラリをインポート
import cv2
import pandas as pd
from datetime import datetime

# 変数の初期化
stillImage = None
motionImage = [None, None]
time = []

# 開始時刻と終了時刻を格納するDataFrameを初期化
df = pd.DataFrame(columns=["Start", "End"])

# Webカメラからの映像キャプチャを開始
video = cv2.VideoCapture(0)

while True:
    # カメラからフレームを読み込む
    check, frame = video.read()
    motion = 0

    # カラー画像をグレースケールに変換
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (21, 21), 0)

    # 最初のフレームを基準画像として保持
    if stillImage is None:
        stillImage = gray
        continue

    # 基準画像と現在の画像の差分を計算
    diff_frame = cv2.absdiff(stillImage, gray)

    # 差分の輝度が25より大きいピクセルを白にする(二値化)
    thresh_frame = cv2.threshold(diff_frame, 25, 255, cv2.THRESH_BINARY)[1]
    thresh_frame = cv2.dilate(thresh_frame, None, iterations=2)

    # 動いている物体の輪郭を検出
    contours, hierarchy = cv2.findContours(thresh_frame.copy(),
        cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for contour in contours:
        if cv2.contourArea(contour) < 10000:
            continue
        motion = 1
        (x, y, w, h) = cv2.boundingRect(contour)
        cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 3)

    # 現在のモーション状態を履歴として保持
    motionImage.append(motion)
    motionImage = motionImage[-2:]

    # モーション開始時刻を記録
    if motionImage[-1] == 1 and motionImage[-2] == 0:
        time.append(datetime.now())

    # モーション終了時刻を記録
    if motionImage[-1] == 0 and motionImage[-2] == 1:
        time.append(datetime.now())

    # 各種ウィンドウに画像を表示
    cv2.imshow("Gray_Frame", gray)
    cv2.imshow("Threshold Frame", thresh_frame)
    cv2.imshow("Colored_Frame", frame)

    key = cv2.waitKey(1)
    # qキーで処理を終了
    if key == ord('q'):
        if motion == 1:
            time.append(datetime.now())
        break

# 検出されたモーションの時間をDataFrameに追加
for i in range(0, len(time), 2):
    df = df.append({"Start": time[i], "End": time[i + 1]}, ignore_index=True)

# 動きの記録をCSVファイルとして保存
df.to_csv("FrameInMotion_time.csv")

# カメラデバイスを解放
video.release()

# 表示中のウィンドウをすべて閉じる
cv2.destroyAllWindows()

注意:pandas 2.0以降をご利用の場合

DataFrame.append()メソッドはpandas 2.0で廃止されました。新しいバージョンでは、該当箇所を以下のようにpd.concat()に置き換えてください。

new_row = pd.DataFrame([{"Start": time[i], "End": time[i + 1]}])
df = pd.concat([df, new_row], ignore_index=True)

プログラムの仕組み

  • 背景との差分計算: 最初に取得したフレームを基準画像として保持し、以降のフレームとの絶対差分(cv2.absdiff)を計算します。
  • 二値化処理: 差分が閾値(25)を超えたピクセルを白、それ以外を黒に変換し、動いた領域だけを抽出します。
  • 膨張処理(dilate): 白い領域を膨張させることで小さなノイズを消し、検出領域をつなげて認識精度を高めます。
  • 輪郭検出: findContoursで動体の輪郭を検出し、面積が10000以上ある輪郭に対してのみ緑色の矩形を描画します。これにより、微小な変化を無視できます。
  • 時間の記録: 動きが始まった瞬間と終わった瞬間にdatetime.now()で時刻を記録し、最後にまとめてCSVに出力します。

実行結果

プログラムを実行すると、3つのウィンドウが表示されます。それぞれグレースケールカラー(検出枠付き)白黒(二値化)の3つのモードで、Webカメラの映像と動きの検出状況をリアルタイムに確認できます。

同時に、動きが検出された日時がCSVファイルにも記録されます。出力されるCSVファイルの中身は以下のようになります。

FrameInMotion_time.csv(出力例)

   Start                      End
0  2019-02-21 18:08:35.791487  2019-02-21 18:10:59.718005

このように、動きが検出された開始時刻と終了時刻が1行ずつ記録されていきます。応用としては、閾値や最小面積の調整、特定時間帯のみ記録する機能の追加などを行うことで、簡易的な防犯カメラシステムとして拡張することも可能です。

  1. OpenCV×Pythonで画像をぼかす方法|ガウシアンフィルタの基本と実装例

    OpenCVは、画像処理に最も優れたPythonパッケージの一つです。信号にノイズが混入するのと同じように、画像にもさまざまな種類のノイズが含まれており、その主な発生源はカメラセンサーなど画像取得元そのものです。PythonのOpenCVパッケージには、画像を滑らかにする「スムージング(平滑化)」、いわゆる「ぼかし(ブラー)」処理を行うための機能が用意されています。 本記事では、その中でも特に一般的な手法であるガウシアンフィルタ(Gaussian Filter)を使った画像のぼかし方を解説します。ガウシアンフィルタを使用すると、画像内のシャープなエッジ(輪郭)を滑らかにしながら、過度なぼかしを

  2. OpenCVを使って画像・動画のエッジを検出するPythonプログラムの書き方

    この記事では、Pythonを使って画像や動画ファイルからエッジ(輪郭)を検出する方法を解説します。エッジ検出には、コンピュータビジョン向けに設計されたオープンソースライブラリ「OpenCV」を使用します。OpenCVはもともとIntelによって開発されたライブラリで、BSDライセンスのもとで無料で利用できます。OpenCVの機能を使うには、pipでインストールを行います。インストール時にNumPyモジュールも自動的にダウンロードされるため、別途用意する必要はありません。sudo pip3 install opencv-python今回の入力には動画ファイルを使用しますが、Webカメラを接続すれ