0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Raspberry Pi Zero 2 WでOpenCVを使った静体検知テスト

Last updated at Posted at 2025-02-02

1.はじめに

前回記事の続きを行う。
今回は参考サイトのソースコードをベースに映像に動きがない時に赤枠を出す「静体検知」を実装する。

2.ソースコード

まずは最終コードから。
参考サイトでコメントが付いている部分は省いている。

MotionStop.py
# モジュールインポート
import datetime
import cv2

# カメラ入力の解像度設定値(任意設定)
WIDTH = 640
HEIGHT = 480

# 表示するウィンドウのサイズ設定値(任意設定)
WIN_WIDTH = 400
WIN_HEIGHT = 300

motion_factor = 0       # motion_factor
max_motion_factor = 0   # motion_factor の最大値
DOT_TH = 10             # 各ドットの変化を検知する感度(小:感度高、大:感度低)
MOTHON_FACTOR_TH = 0.05 # 静動の閾値(値以下で静と判断)

DELTA_MAX = 255
avg = None

# カメラ入力先設定
cap = cv2.VideoCapture(0, CAP_V4L2)
# カメラ入力の解像度設定
cap.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT)

# ウィンドウ作成 サイズ指定を変更可能に設定
cv2.namedWindow('camera', cv2.WINDOW_NORMAL)
cv2.resizeWindow('camera', WIN_WIDTH, WIN_HEIGHT)

while True:
    ret, frame = cap.read()
    dt_now = datetime.datetime.now()
    dt_format_string = dt_now.strftime('%Y-%m-%d %H:%M:%S')
    
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    if avg is None:
        avg = gray.copy().astype("float")
        continue

    cv2.accumulateWeighted(gray, avg, 0.6)
    frameDelta = cv2.absdiff(gray, cv2.convertScaleAbs(avg))
    thresh = cv2.threshold(frameDelta, DOT_TH, DELTA_MAX, cv2.THRESH_BINARY)[1]

    motion_factor = thresh.sum() * 1.0 / thresh.size / DELTA_MAX 
    motion_factor_str = '{:.08f}'.format(motion_factor)

    # motion_factor の最大値を更新
    if motion_factor > max_motion_factor:
        max_motion_factor = motion_factor

    cv2.putText(frame, dt_format_string, (25,50), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0,0,255), 2)
    cv2.putText(frame, motion_factor_str, (25,470), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0,0,255), 2)

    # カメラ入力の映像に変化がない時の動作
    if motion_factor <= MOTHON_FACTOR_TH:
        # 映像の外枠に赤枠を付ける
        frame = cv2.rectangle(frame, (0, 0), (frame.shape[1] - 1, frame.shape[0] - 1), (0, 0, 255), 5)

    cv2.imshow('camera', frame)

    k = cv2.waitKey(1000)

    if k == ord('r'):  # 「r」キーを押したら max_motion_factor をリセット
        print("Max motion_factor reset!")
        max_motion_factor = 0

    if k == 27:  # ESCキーが押されたら終了
        break

# 終了時に motion_factor の最大値を表示
print(f"Final motion_factor: {motion_factor:.08f}")
print(f"Max motion_factor: {max_motion_factor:.08f}")

print("Bye!\n")
cap.release()
cv2.destroyAllWindows()

追加した機能(メイン)
・motion_factorがMOTHON_FACTOR_TH以下となった時、画面に赤枠を出す

追加した機能(サブ)
・スタート時のウインドウサイズを小さくする
・ウインドウサイズをマウスで変更可能
・motion_factorの最大値を取得(デバック用 DOT_TH調整のため)
・上記を動作終了時にターミナルに出力

3.ソースコード解説(備忘)

1.import time削除

ソースコード上で使用されていないため。datetimeのモジュールで取得できる値しか使われていない。

2.cv2.VideoCapture(0, CAP_V4L2)のCAP_V4L2

cv2.VideoCapture(0)で実行したとき以下の警告が出る。

[ WARN: @4.510] global ./modules/videoio/src/cap_gstreamer.cpp (1405) open OpenC
V | GStreamer warning: Cannot query video position: status=0, value=-1, duration=-1

この警告は、GStreamerを使用してビデオ入力を取得しようとした時、ビデオの現在の位置情報(再生時間やフレーム位置)を取得できなかった場合に出るらしい。
これに対しCAP_V4L2を追加すると、上記を解決できる。
V4L2 (Video for Linux 2) は、Linux カーネルに組み込まれているビデオキャプチャAPIで、USBカメラやWebカメラ、キャプチャカードなどのデバイスを扱うための標準的なフレームワークとのこと。

3.cv2.namedWindowcv2.resizeWindow

cv2.namedWindowの引数にcv2.WINDOW_NORMALを入れるとウインドウサイズをマウスで変更できるようになる。ウインドウサイズを固定しておきたい時は引数を消せば良い。
cv2.resizeWindowは既存のウィンドウのサイズを指定する。cv2.namedWindow() で cv2.WINDOW_NORMAL を指定している場合のみ動作することに注意が必要。

4.動作確認

2節のソースコードを適当なディレクトリに保存して、実行する。
ホーム画面で操作をしていないとき。
20250202_110159488_iOS.jpg

操作をしたとき。
20250202_110206759_iOS.jpg

左下数値がMOTHON_FACTOR_THの設定以下で赤枠が出ており、正常に動作していることがわかる。
また表示ウインドウサイズも小さくできている。

5.おわりに

「静体検知」を実装した。
ウインドウサイズが小さくなったことが要因か不明だが、CPU使用率が大幅に下がった。
・「動体検知」では15~25%程度
・「静体検知」では2~5%程度

次回は一定時間停止していた場合に静止判定を取り、ラズパイの外側にアウトプットを出せるようにする。

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?