Atom's tech blog

OpenCVで顔認証をサンプルコードを参考に作ってみた(顔認証編)

顔認証の概要

  • OpenCVの顔推定器 アルゴリズムは「Local Binary Patterns Histogram(LBPH)」を使用
  • 「モデルファイル作成編」でモデルファイル作成時に人物毎に付与した番号が「 顔認証」で判定結果を出力する
  • 判定した結果と共に信頼度も判定してくれる。

顔認証方法(ソースコード説明)は以下の流れ

  • 予めで顔認証モデルファイルを作成した時の人物毎の番号毎に表示する名前をコードに埋め込みする
  • 顔認証モデルファイルのYAMLファイルを読み出し
  • カメラから顔をキャプチャー
  • 顔と目を識別
  • キャプチャーした顔画像を特徴量比較にかける
  • 比較結果をキャプチャーした画像上に名前を出力する
  • 合わせてキャプチャーした画像に顔を識別箇所と目を識別した箇所を四角線で描画し画面出力する
  • フレームレート(FPS)値と顔画像の比較にかかる時間、信頼度も出力する

コメント

  • 掲載したソースは「Mac」で動作確認済み *「ラズパイ」/「Tinkerboard」でも動作可能
  • USBカメラのVideoポート変更必要
  • 使った各種バージョンは以下
  • MacOS Mojave / python3.5.6 / Opencv3.4.2 / VS Code1.38.1
顔認証結果のイメージ画像

f:id:iAtom:20201008135648j:plain

ファイル構成

  • ./data_xml/ # カスケードファイルを格納しているフォルダ
  • ./image_data/ # キャプチャーした画像ファイルを保存するフォルダ
  • ./trainer/ # 最後に学習したYAMLファイルとして保存するフォルダ
  • face_recognition.py # 顔認証のPythonファイル

ソースコード

# -*- coding: UTF-8 -*-
import cv2
import numpy as np
import os
import time

# UserID変数
User_id = 0

# Local Binary Patterns Histogram(LBPH)アルゴリズム インスタンス
#recognizer = cv2.face.createLBPHFaceRecognizer()
recognizer=cv2.face_LBPHFaceRecognizer.create()
# 学習した顔認証ファイルを読み出しする
#recognizer.load('/Users/local/source/opencv/face_recognition/trainer/trainer.yml')
recognizer.read('/Users/local/source/opencv/face_recognition/trainer/trainer.yml')

# 顔認証で使用するxmlをパラメーターとして物体認識(顔認識)のインスタンス生成
cascadePath = '/Users/local/source/opencv/face_recognition/data_xml/haarcascade_frontalface_alt2.xml'
faceCascade = cv2.CascadeClassifier(cascadePath)

# 顔認証で使用するxmlをパラメーターとして物体認識(目認識)のインスタンス生成
eye_cascadePath = '/Users/local/source/opencv/face_recognition/data_xml/haarcascade_eye.xml'
eye_cascade = cv2.CascadeClassifier(eye_cascadePath)

# 学習した際のUserIDと人物の名前を変換するための配列(ここではUserID = 05まで USERIDを増やしたい人はここを増やす)
names = ['None', 'Jone', 'tommy', 'samansa', 'jonson', 'Naomi'] 

###############################
# VideoCapture用インスタンス生成
###############################
cap = cv2.VideoCapture(0)

###############################
# 画像サイズをVGAサイズに変更する
###############################
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) 
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

# 最小Windowサイズを定義
minW = 0.1*cap.get(cv2.CAP_PROP_FRAME_WIDTH)
minH = 0.1*cap.get(cv2.CAP_PROP_FRAME_HEIGHT)

while True:

    #FPS算出のため、事前に時間を取得
    tick = cv2.getTickCount()
    # カメラから画像データ取得
    ret, img =cap.read()
    # グレースケールに変換
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    # 顔検出
    faces = faceCascade.detectMultiScale( 
        gray,
        scaleFactor = 1.2,
        minNeighbors = 3,
        minSize = (int(minW), int(minH)),
       )
    # 顔検出した人物認証のためのループ
    for(x,y,w,h) in faces:

        # 顔箇所を四角で描画
        cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)
        # 顔の上半分を検出対象範囲とする
        eyes_gray = gray[y : y + int(h/2), x : x + w]
        ################
        # 目検出        #
        ################
        eyes = eye_cascade.detectMultiScale(
            eyes_gray, 
            scaleFactor=1.11, 
            minNeighbors=3, 
            minSize=(8, 8))

        # 目検出した箇所を四角で描画
        for ex, ey, ew, eh in eyes:
            cv2.rectangle(img, (x + ex, y + ey), (x + ex + ew, y + ey + eh), (255, 255, 255),2)

        ##########################################        
        # 推論時間にかかる時間が知りたいので時間を取得  #
        ##########################################
        t1 = time.time()
        #################################################
        # 学習した顔から推論をかける。戻値が認識した番号と信頼度 #
        #################################################
        id ,confidence = recognizer.predict(gray[y:y+h,x:x+w])
        # 推論時間取得のため
        t2 = time.time()
        # 検出時間を算出
        dt1 = t2 - t1

        ##################################################################
        # confidece(信頼度)を40%100%とする(ちょっと信頼度を低めからしている) #
        ##################################################################
        if confidence < 60 and confidence > 0:
            # USER IDから名前を取得
            id = names[id]
            confidence = "{0}%".format(round(100 - confidence))
        else:
            id = "unknown"
            confidence = "{0}%".format(round(100 - confidence))

        # 名前表示と、推論時間のテキスト文字を画像に貼り付け      
        cv2.putText(img, "confidence: " + str(confidence), (x+5, y + 20), cv2.FONT_HERSHEY_PLAIN, 1, (255,255,0), 2)         
        cv2.putText(img, str(id)+' Time'+str(round(dt1, 3))+ 'sec' , (x+5,y-5), cv2.FONT_HERSHEY_PLAIN, 1, (255,255,255), 2)
 
    # FPS算出と表示用テキスト作成
    fps = cv2.getTickFrequency() / (cv2.getTickCount() - tick)
    # FPSを左上に表示
    cv2.putText(img, "FPS:{} ".format(int(fps)), 
        (10, 50), cv2.FONT_HERSHEY_PLAIN, 3, (255, 255, 255), 2, cv2.LINE_AA)

    # 画像表示
    cv2.imshow('camera',img) 

    # ESCキーで終了
    k = cv2.waitKey(10) & 0xff 
    if k == 27:
        break

# Do a bit of cleanup
print("\n Exit Program")
cap.release()
cv2.destroyAllWindows()