この記事では、Python版OpenCVでフレーム間差分法を実装し、移動物体を検出する方法をソースコード付きで解説します。
フレーム間差分法で不審者の検出
フレーム間差分法は、移動物体の検出方法の1つです。
連続する画像の差分から動体を検出することができます。
この方法の大きな特徴としては、背景差分法のように背景画像(モデル)を用意する必要がない点です。
【参考】フレーム差分法の原理・特徴・計算式
今回は、PythonとOpenCVでフレーム間差分法を実装し、不審者を検出する簡単な監視カメラを作成してみました。
ソースコード(Python3+OpenCV3)
サンプルプログラムのソースコードです。
# -*- coding: utf-8 -*-
import cv2
import numpy as np
# フレーム差分の計算
def frame_sub(img1, img2, img3, th):
# フレームの絶対差分
diff1 = cv2.absdiff(img1, img2)
diff2 = cv2.absdiff(img2, img3)
# 2つの差分画像の論理積
diff = cv2.bitwise_and(diff1, diff2)
# 二値化処理
diff[diff < th] = 0
diff[diff >= th] = 255
# メディアンフィルタ処理(ゴマ塩ノイズ除去)
mask = cv2.medianBlur(diff, 5)
return mask
def main():
# 不審物判定の閾値
min_moment = 1000
# カメラのキャプチャ
cap = cv2.VideoCapture(0)
# フレームを3枚取得してグレースケール変換
frame1 = cv2.cvtColor(cap.read()[1], cv2.COLOR_RGB2GRAY)
frame2 = cv2.cvtColor(cap.read()[1], cv2.COLOR_RGB2GRAY)
frame3 = cv2.cvtColor(cap.read()[1], cv2.COLOR_RGB2GRAY)
# カウント変数の初期化
cnt = 0
while(cap.isOpened()):
# フレーム間差分を計算
mask = frame_sub(frame1, frame2, frame3, th=10)
# 白色領域のピクセル数を算出
moment = cv2.countNonZero(mask)
# 白色領域のピクセル数が一定以上なら不審物有りと判定
if moment > min_moment:
print("不審物を検出しました:", cnt)
filename = "frame" + str(cnt) + ".jpg"
cv2.imwrite(filename, frame2)
cnt += 1
# 結果を表示
cv2.imshow("Frame2", frame2)
cv2.imshow("Mask", mask)
# 3枚のフレームを更新
frame1 = frame2
frame2 = frame3
frame3 = cv2.cvtColor(cap.read()[1], cv2.COLOR_RGB2GRAY)
# qキーが押されたら途中終了
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
実行結果
サンプルプログラムの実行結果です。
移動物体(不審物)を検知したら、その瞬間のフレームを自動的に保存します。

【PythonとOpenCVで画像処理超入門】使い方とサンプルコードを解説
Python版OpenCVで画像処理プログラミングを行う方法を入門者向けにソースコード付きで解説するページです。

【画像処理入門】アルゴリズム&プログラミング
画像処理における基本的なアルゴリズムとその実装例(プログラム)についてまとめました。
コメント
こんにちは.
現在,フレーム間差分して差分が大きかった時のフレームを保存するプロセスと,保存された画像をftpサーバへ送信するプロセスを並列で行いたいと考えています.並列で行う理由としてはftpサーバへの送信に時間がかかり,その間フレーム取得できなくなってしまうからです.
まだまだpython初心者で並列処理の書き方がわかりません.保存した画像ファイル名をリストに入れていき,ftpサーバのプロセスの方で先頭から順番に送っていきたいです.
教えてください.
※おでこ様
コメントありがとうございます。
並列処理については私もPythonで試したことがないのですが、
下記のサイト様を参考にされてはいかかがでしょうか。
Python並列処理(multiprocessingとJoblib)
https://qiita.com/yukiB/items/203a6248c2d466b80d38
def frame_sub(img1, img2, img3, th):
の
# メディアンフィルタ処理(ゴマ塩ノイズ除去)
mask = cv2.medianBlur(diff, 5)
の部分の
maskはローカルスコープのように見えます。意図が理解できません。
どこに効果が及ぶのでしょうか?
ご指摘ありがとうございます。誤記でしたので修正しました。
ありがとうございます。
腑に落とすことができました。