OpenCVを使って動画に映る人を検出

OpenCV
スポンサーリンク

今回は前回に引き続き、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としました。

 

完成した動画

今回の検出結果は以下のようになりました。

良かったら参考にしてください。

 

参考サイト

404 NOT FOUND | アルゴリズム速報

コメント

タイトルとURLをコピーしました