しんさんのブログ

科学や技術のこと読書のことなど

Python + OpenCV3で顔認識

先日, Python + OpenCV3の環境を構築しましたので, この環境でWeb camからの映像を使用して顔認識してみました.

初めにanacondaでopnecvの仮想環境をactivate して jupyter notebookを立ち上げます.
以下jupyter notebookのコードと解説を書きます.

顔認識用の特徴量ファイルの読み込み
まずは顔認識用特徴量ファイルを読み込み, opencvにセットします。
今回は、正面顔と目の位置を認識させたいと思いますので2種類の特徴量ファイルをセットします。
ファイルのパスは私のWindows Anaconda環境では以下のようになっていました。
("someone"の部分は自分のユーザーネームに置き換える)

import cv2 # OpenCV libraryのインポート
import numpy as np
# 特徴量ファイルのパスを指定する. 
FACE_CASCADE_FILE = "c:/Users/someone/Anaconda3/pkgs/opencv3-3.1.0-py35_0/Library/etc/haarcascades/haarcascade_frontalface_default.xml"
EYE_CASCADE_FILE = "c:/Users/someone/Anaconda3/pkgs/opencv3-3.1.0-py35_0/Library/etc/haarcascades/haarcascade_eye.xml"
# cascade classifierをセット
face_cascadeClassifier = cv2.CascadeClassifier(FACE_CASCADE_FILE)
eye_cascadeClassifier = cv2.CascadeClassifier(EYE_CASCADE_FILE)

Web cameraの準備と書き込みファイルの設定
Web から読み込んだ画像を認識させますので、Web camをオープンしておきます。
(1行目のcap = cv2.VideoCapture("moviefile/hoge.mp4")を使えばhoge.mp4を入力にすることもできます)
さらに、顔と目の部分を長方形で囲ってその結果の画像を動画でセーブするために書き込みの設定も行います。
書き込む動画のfpsは適当に10.0にしておきました。この値を30.0とするとセーブ後の動画が早送りになってしまいます。
おそらくメインループの回転速度が30.0fpsより遅いのが原因だと思われます。

# Web camera の準備
#cap = cv2.VideoCapture("moviefile/hoge.mp4")
cap = cv2.VideoCapture(0)
#cap.set(cv2.CAP_PROP_FPS, 30)
#fps = cap.get(cv2.CAP_PROP_FPS)
#print(fps)
fps = 10.0 #顔認識に時間がかかるので記録画像のframe rateは遅めにしておく
ret, frame = cap.read()
h, w, ch = frame.shape
# 動画の書き込みの設定を行う
fourcc = cv2.VideoWriter_fourcc(*"XVID") # codec はXVIDを使用
writeFrameDst = cv2.VideoWriter("output/faceDetect.avi", fourcc, fps, (w,h)) # codecはfourcc
  1. メインループ

メインループではループごとに動画から1フレーム抜き出して、その画像をグレー画像に変換後、顔と目を認識させます。
認識した顔と目の場所に赤と緑で枠を書いて、その結果を画面に表示するとともにファイルにセーブします。

while True:
    ret, frame = cap.read()
    if ret == False: # カメラからの映像がないとき
        break
    img = frame.astype(np.uint8) # 顔認識用に現在のフレームの画像をキャプチャ
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # グレー画像に変換
    faceArea = face_cascadeClassifier.detectMultiScale(img_gray) # 顔認識 faceArea = [x座標, y座標, xサイズ, yサイズ]
    #cv2.imshow("img", frame.astype(np.uint8)) # astype(np.uint8)は必要ないが念のため
    
    # 顔の領域に赤い四角を描く
    for x, y, w, h in faceArea:
        cv2.rectangle(img, (x, y), (x+w, y+h), (0,0, 255), 2)
    eyesArea = eye_cascadeClassifier.detectMultiScale(img_gray) # 目認識 eyesArea = [x座標, y座標, xサイズ, yサイズ]
    
    # 目の領域に緑色の四角を描く
    for (ex,ey,ew,eh) in eyesArea:
        cv2.rectangle(img, (ex,ey), (ex+ew,ey+eh), (0,255,0), 2)
    
    cv2.imshow("img", img) # 入力画像と顔エリアをマージした画像を表示
    writeFrameDst.write(img) # 動画1コマ書き込み
    
    if cv2.waitKey(1) == 27:
        break

終了処理
メインループでESCキーが押されたら、書き込みファイルとWeb cameraの終了処理を行い、開いているwindowを閉じます.

cap.release()
writeFrameDst.release()
cv2.destroyAllWindows()

目の認識の精度があまり高くないようで、いろんな場所を誤認識してしまいます.
コードの途中でエラーが出て、修正後再実行するときにはjupyter notebookのカーネルをリスタートしないとWeb cameraがオープンされたままになっているので再びプログラムを起動したときにエラーがでますのでご注意ください。
顔認識に関しては以下のブログを参考にしました。
qiita.com