import cv2
cap = cv2.VideoCapture(0)
img_last = None # 前回の画像を記憶する変数 --- (*1)
green = (0, 255, 0)
while True:
# 画像を取得
_, frame = cap.read()
frame = cv2.resize(frame, (500, 300))
# 白黒画像に変換 --- (*2)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (9, 9), 0)
img_b = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)[1]
# 差分を確認する
if img_last is None:
img_last = img_b
continue
frame_diff = cv2.absdiff(img_last, img_b) # --- (*3)
cnts = cv2.findContours(frame_diff,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[1]
# 差分があった点を画面に描く --- (*4)
for pt in cnts:
x, y, w, h = cv2.boundingRect(pt)
if w < 30: continue # 小さな変更点は無視
cv2.rectangle(frame, (x, y), (x+w, y+h), green, 2)
# 今回のフレームを保存 --- (*5)
img_last = img_b
# 画面に表示
cv2.imshow("Diff Camera", frame)
cv2.imshow("diff data", frame_diff)
if cv2.waitKey(1) == 13: break
cap.release()
cv2.destroyAllWindows()
実行結果(左から右に動いた時の出力結果)
以下、cv2.absdiff()関数の結果
画像の取得
_, frame = cap.read()
frame = cv2.resize(frame, (500, 300))
白黒画像に変換
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (9, 9), 0)
img_b = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)[1]
グレースケールに変換。
cv2.GaussianBlur()でぼかし処理。
cv2.threshold()で二値化。
前の画像と差分を確認
if img_last is None:
img_last = img_b
continue
frame_diff = cv2.absdiff(img_last, img_b) # --- (*3)
cnts = cv2.findContours(frame_diff,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[1]
if img_last is None:について
pythonの演算子には同値性と同一性という概念がある。
値がNoneかを判定するには == 演算子ではなく、is演算子もしくはis not演算子を利用する。is演算子はisの左右が同一のオブジェクトであるかを比較する演算子である。
同値性は ==
これは同じ値とみなしてよければTrueとするという考え方
このみなして良いかの部分はカスタマイズできるので何を同じ値と判定するかはオブジェクトによって異なる。
同一性は is , is not
これは完全に同じものだったらTrueにするという考え方
==とisで同じ出力結果得られることもあるがバグを減らしたりする意味でもNoneの判定はis,is notを使用する。
img_last = img_bで前の画像を記憶する変数に今の画像を格納。
cv2.absDiffについて
cv2.absdiff()関数は画像ごとの差分を抽出する。
cv2.absdiff(変化前の画像, 変化後の画像)
上記の結果の画像を見ると動きがあった部分が濃い白い線で表示されている。
この輪郭のデータをcv2.findContours()関数で取得する。
今回第二引数で指定しているcv2.RETR_EXTERNALは一番外側の輪郭を取得するオプション。RETR_LISTだと内側の輪郭も取得してしまうためこちらを指定。第三引数のcv2.CHAIN_APPROX_SIMPLEは省略できる点は省略するオプション。
差分があった点を画面に描く
for pt in cnts:
x, y, w, h = cv2.boundingRect(pt)
if w < 30: continue # 小さな変更点は無視
cv2.rectangle(frame, (x, y), (x+w, y+h), green, 2)
cv2.boundingRect()で輪郭に外接する長方形のデータを取得し変数に格納。
cv2.rectangle()で描画。
あとはcv2.imshow()で表示してcv2.waitKey()で繰り返し処理終了の記述。
release()でカメラ終了。
cv2.destoryAllWindows()で全てのウィンドウを閉じておしまい。