1.はじめに
前回記事の続きを行う。
今回は参考サイトのソースコードをベースに映像に動きがない時に赤枠を出す「静体検知」を実装する。
2.ソースコード
まずは最終コードから。
参考サイトでコメントが付いている部分は省いている。
# モジュールインポート
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.namedWindow
とcv2.resizeWindow
cv2.namedWindow
の引数にcv2.WINDOW_NORMAL
を入れるとウインドウサイズをマウスで変更できるようになる。ウインドウサイズを固定しておきたい時は引数を消せば良い。
cv2.resizeWindow
は既存のウィンドウのサイズを指定する。cv2.namedWindow() で cv2.WINDOW_NORMAL を指定している場合のみ動作することに注意が必要。
4.動作確認
2節のソースコードを適当なディレクトリに保存して、実行する。
ホーム画面で操作をしていないとき。
左下数値がMOTHON_FACTOR_THの設定以下で赤枠が出ており、正常に動作していることがわかる。
また表示ウインドウサイズも小さくできている。
5.おわりに
「静体検知」を実装した。
ウインドウサイズが小さくなったことが要因か不明だが、CPU使用率が大幅に下がった。
・「動体検知」では15~25%程度
・「静体検知」では2~5%程度
次回は一定時間停止していた場合に静止判定を取り、ラズパイの外側にアウトプットを出せるようにする。