今回は前回に引き続き、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としました。
完成した動画
今回の検出結果は以下のようになりました。
良かったら参考にしてください。
コメント