今回は前回に引き続き、OpenCVを使用して動画に現れる人を検出していきましょう。
利用する手法は、フレーム間差分法を使用していきます。
1.環境・使用材料
言語:python
ライブラリ:OpenCV
エディタ:spyder
使用した素材:
素材元:https://github.com/opencv/opencv/blob/master/samples/data/vtest.avi
2.ソースコード
import cv2
import numpy as np
def frame_fin(img1, img2, img3, th):
#絶対値差分
dif1 = cv2.absdiff(img1, img2)
dif2 = cv2.absdiff(img2, img3)
#論理積画像の算出
dif = cv2.bitwise_and(dif1, dif2)
#二値化
dif[dif < th] = 0
dif[dif >= th] = 255
#ノイズ除去(ゴマ塩ノイズを除去するため中央値フィルタ)
dif = cv2.medianBlur(dif,5)
return dif
def main():
#キャプチャ開始
cap = cv2.VideoCapture(r'C:\Users\ディレクトリ名\vtest.avi')
#video readerを作成
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)
#video Writerを作成
fourcc = cv2.VideoWriter_fourcc(*'DIVX')
writer = cv2.VideoWriter('output.avi', fourcc, fps, (width, height))
while cap.isOpened():
ret, f = cap.read()
#フレーム3枚分を取得
gframe1 = cv2.cvtColor(cap.read()[1],cv2.COLOR_RGB2GRAY)
gframe2 = cv2.cvtColor(cap.read()[1],cv2.COLOR_RGB2GRAY)
gframe3 = cv2.cvtColor(cap.read()[1],cv2.COLOR_RGB2GRAY)
#フレーム間差分を算出
frame = frame_fin(gframe1, gframe2, gframe3, th=10)
#閾値設定
R, thresh = cv2.threshold(frame, 20, 255, cv2.THRESH_BINARY)
#輪郭抽出
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#面積でフィルタリング
contours = list(filter(lambda cnt: cv2.contourArea(cnt) > 100, contours))
#輪郭を囲む長方形に変換
rects = [cv2.boundingRect(cnt) for cnt in contours]
#x,y,w,h = cv2.boundingRect(cnt)
#長方形を描画する
bgr = f.copy()
for x, y, width, height in rects:
cv2.rectangle(bgr, (x,y), (x+width, y+height), (0,255,0),2)
#cv2.rectangle(bgr, (xmin,ymin), (xmax,ymax), (0,0,255),2)
cv2.imshow("bgr",bgr)
gframe1 = gframe2
gframe2 = gframe3
gframe3 = cv2.cvtColor(cap.read()[1],cv2.COLOR_RGB2GRAY)
#qキーが押されたら途中で終了
k = cv2.waitKey(1)
if k == ord("q"):
break
writer.write(bgr)
writer.release()
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
3.ソースコード詳細
import cv2 import numpy as np
まずはライブラリのインポートをしましょう。
使用するライブラリはopencvライブラリとnumpyをインポートしてください。
def frame_fin(img1, img2, img3, th):
#絶対値差分
dif1 = cv2.absdiff(img1, img2)
dif2 = cv2.absdiff(img2, img3)
#論理積画像の算出
dif = cv2.bitwise_and(dif1, dif2)
#二値化
dif[dif < th] = 0
dif[dif >= th] = 255
#ノイズ除去(ゴマ塩ノイズを除去するため中央値フィルタ)
dif = cv2.medianBlur(dif,5)
return dif
次に、フレーム間差分の一連の流れをframe_finという関数を定義していきます。
今回定義する関数は、以下の処理を実行する関数として定義していきます。
①取得したフレームの絶対値化差分を計算
②論理積画像の算出
③二値化
④ゴマ塩ノイズ除去
frame_fin(img1, img2, img3, th)について説明します。
img1: 取得したフレームの1枚目
img2: 取得したフレームの2枚目
img3: 取得したフレームの3枚目
th : 二値化に必要な閾値の設定
def main():
#キャプチャ開始
cap = cv2.VideoCapture(r'C:\Users\ディレクトリ名\vtest.avi')
#video readerを作成
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)
#video Writerを作成
fourcc = cv2.VideoWriter_fourcc(*'DIVX')
writer = cv2.VideoWriter('output.avi', fourcc, fps, (width, height))
まず動画を読み込むため、cv2.VideoCapture()関数を使用します。使い方は以下の通りです。
cv2.VideoCapture(r’動画を保存されている相対パス/絶対パス’)
次に、算出した結果(動画)を記録するための保存用のvideo readerを作成します。
まず動画キャプチャの幅・高さ・動画のフレームレートを定義していきます。それぞれ読み込んだ動画と同じ条件としていきます。
取得する方法は、cap.get()関数で取得します。
動画キャプチャの幅:width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
動画キャプチャの高さ: height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
動画のフレームレート:fps = cap.get(cv2.CAP_PROP_FPS)
そして条件を設定したら動画の書き込み設定を行います。
動画の書き込みは、cv2.VideoWriter()関数を使用します。使い方は以下の通りです。
cv2.VideoWriter(第1引数:保存する動画名(例: output.avi),第2引数-第4引数:FourCC コード)
cv2.VideoWriter_fourcc(*’DIVX’)
FourCCコードとは動画のコーデックを指定するための4バイトのコードです。
今回はFourCCコードをDIVXを使用するため、fourccコードを定義する関数 cv2.VideoWriter_fourcc(*’DIVX’)として定義しました。
参照HP:動画を扱う・FourCC.org
while cap.isOpened():
ret, f = cap.read()
#フレーム3枚分を取得
gframe1 = cv2.cvtColor(cap.read()[1],cv2.COLOR_RGB2GRAY)
gframe2 = cv2.cvtColor(cap.read()[1],cv2.COLOR_RGB2GRAY)
gframe3 = cv2.cvtColor(cap.read()[1],cv2.COLOR_RGB2GRAY)
#フレーム間差分を算出
frame = frame_fin(gframe1, gframe2, gframe3, th=10)
#閾値設定
R, thresh = cv2.threshold(frame, 20, 255, cv2.THRESH_BINARY)
#輪郭抽出
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#面積でフィルタリング
contours = list(filter(lambda cnt: cv2.contourArea(cnt) > 100, contours))
#輪郭を囲む長方形に変換
rects = [cv2.boundingRect(cnt) for cnt in contours]
#x,y,w,h = cv2.boundingRect(cnt)
#長方形を描画する
bgr = f.copy()
for x, y, width, height in rects:
cv2.rectangle(bgr, (x,y), (x+width, y+height), (0,255,0),2)
#cv2.rectangle(bgr, (xmin,ymin), (xmax,ymax), (0,0,255),2)
cv2.imshow("bgr",bgr)
gframe1 = gframe2
gframe2 = gframe3
gframe3 = cv2.cvtColor(cap.read()[1],cv2.COLOR_RGB2GRAY)
#qキーが押されたら途中で終了
k = cv2.waitKey(1)
if k == ord("q"):
break
次にwhile文を使用して、qキーが押されるまで繰り返し処理するとします。
while文の使い方
while 条件式:
条件式が真(true)の時に実行する処理1
条件式が真(true)の時に実行する処理2
次にcap.read()関数で、今回使用する動画の読み込みを行います。
cap.read()読み込んだ結果は以下の通りです。
cap.read()[0]: bool型の結果が返されます。True/Falseのどちらかです。
cap.read()[1]: 読み込んだ動画(RGB動画で返されます)
cv2.cvtColor()関数を使用して、読み込んだ動画からフレームを1枚指定しグレースケールに変換します。
cv2.cvtColor()関数の使い方は以下の通りです。
cv2.cvtColor(input_image, flag)
input_image : 入力画像
flag : 色変換の種類(今回はcv2.COLOR_RGB2GRAYを使用しグレースケール画像に変換)
frame_fin関数は、先ほど定義した関数になります。
今回はグレースケールを変換したフレーム3枚を入力画像とし、閾値を10としました。
完成した動画
今回の検出結果は以下のようになりました。
良かったら参考にしてください。



コメント