【サンプル満載】Pythonで顔の検出/認識をするには?主なライブラリ4選

当ページのリンクには広告が含まれています。

Pythonで顔検出/認識する方法はいくつかありますが、それぞれ個別の解説記事はあるものの、まとまったものが見つかりませんでした。

そこで、今回は整理する意味も込めてPythonで使える顔検出/認識ライブラリ OpenCV、InsightFace、Dlib、Face Recognition について一通り紹介していきたいと思います。

目次

Pythonで使える顔認識ライブラリ

比較項目用途OpenCVInsightFaceDlibFace
Recognition
顔検出顔の検出
顔認識人物の特定××
顔解析顔の構造、表情、特徴点××
顔属性の推定性別、年齢、人種、感情×××
顔特徴の抽出と比較顔の特徴を他の顔と比較×××
顔のクラスタリング顔の類似性による分類×××
顔のランドマーク検出顔のパーツの位置特定×
3D顔形状推定写真から顔の立体化×××
ライブラリ名概要
OpenCV汎用的な画像処理ライブラリであり、その中の1つの機能として顔検出が用意されています。
顔を検出する以外(顔認識、顔解析、顔属性の推定など)の機能はサポートされていません。
InsightFace顔認識と顔解析に特化したライブラリです。
顔検出、顔認識、顔解析、顔属性の推定、顔特徴の抽出と比較、顔のクラスタリングと識別、顔のランドマーク検出、3D顔形状推定をサポートしています。
Dlib顔検出と顔のランドマーク検出に特化したライブラリです。
それ以外(顔認識、顔解析、顔属性の推定など)の機能はサポートされていません。
Face RecognitionDlibをベースとした顔検出と顔認識のライブラリです。
顔検出、顔認識、顔解析、顔のランドマーク検出をサポートしています。

OpenCVを使った顔認識

OpenCVを使った顔検出を行うために、最初にライブラリを pip でインストールしておきます。

pip install opencv-python

標準の顔検出器を使う方法

以下がOpenCV標準の顔検出器を使ったサンプルプログラムです。

import cv2

# 画像の読み込み
image = cv2.imread('O:/Python/img/23337234_s.jpg')

# グレースケールに変換
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 顔検出器の読み込み
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

# 顔の検出
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(20, 20))

# 顔の境界ボックスを描画
for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 3)

# 結果の表示
cv2.imshow('Face Detection', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

detectMultiScalemメソッドの minSize で認識可能な最小のサイズを指定できるのですが、1にしても真ん中の女の子の顔だけ認識できませんでした。30にすると子供と右端の女性の顔が認識できなくなったため、20に設定しています。

標準の顔検出器を使った検出結果

学習済みファイルを使った顔検出

もう1つ 、カスケード識別器の学習済みファイルを使う方法があるので、これを使ったところ5人とも検出できるようになりました。

学習済みファイルは下記URLからダウンロード可能で、今回はhaarcascade_frontalface_alt2.xmlを使いました。

 https://github.com/opencv/opencv/tree/master/data/haarcascades

ダウンロードサイトのキャプチャ画像

以下がサンプルプログラムになります。

ダウンロードしたファイルのパスを、7行名の cascade_path に記述して下さい。私の環境ではOドライブ直下にサブフォルダを作って格納したので、次の様になっています。

  cascade_path = 'O:/Python/data/haarcascades/haarcascade_frontalface_alt2.xml'

import cv2

# 画像の読み込み
image = cv2.imread('O:/Python/img/23337234_s.jpg')
 
# 学習済みモデル読み込み
cascade_path = 'O:/Python/data/haarcascades/haarcascade_frontalface_alt2.xml'
cascade_face = cv2.CascadeClassifier(cascade_path,scaleFactor=1.03)

# 顔の検出
faces = cascade_face.detectMultiScale(image)

# 顔の境界ボックスを描画
for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 3)

# 結果の表示
cv2.imshow('Face Detection', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

cv2.CascadeClassifierメソッドの引数でscaleFactor=1.03としていますが、この値が1に近づくほど検出精度が下がり(誤認識が増える)、値が大きくなるほど検出精度が上がり(誤認識が減る)ます。

初期値(1.1)の状態だと中央の女の子の顔が検出されなかったので、1.03に設定したところ、見事に全員の顔が検出できました。

学習済みファイルを使った検出結果

InsightFaceを使った顔認識

InsightFaceを使うには、あらかじめ下記の2つをインストールしておく必要があります。

#CPUだけで処理する場合
pip install onnxruntime
pip install insightfac

#GPUを使って処理する場合
pip install onnxruntime-gpu
pip install insightface

顔検出

以下が insightFace を使った顔検出のサンプルプログラムです。

import cv2
import numpy as np
from insightface.app import FaceAnalysis
from insightface.data import get_image as ins_get_image

# 画像の読み込み
image = cv2.imread('O:/Python/img/23337234_s.jpg')

#モデルの読み込み
app = FaceAnalysis(providers=['CUDAExecutionProvider', 'CPUExecutionProvider'])
app.prepare(ctx_id=0, det_size=(640, 640))

# 顔の検出
faces = app.get(image)

# 顔の境界ボックスを描画
for face in faces:
    if face.bbox is not None:
        bbox = face.bbox.astype(int)
        cv2.rectangle(image, (bbox[0], bbox[1]), (bbox[2], bbox[3]), (0, 255, 0), 2)

# 結果の表示
cv2.imshow('Face Detection', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

特にパラメータを調整せずとも、初期状態で5人の顔が検出できました。

InsightFaceを使った検出結果

顔のランドマーク検出

insightFace では顔検出と同時に顔のランドマーク検出も行っています。先ほどのサンプルプログラムのループ部分に、ランドマーク検出結果の取得と点の描画を付け加えてみました。

import cv2
import numpy as np
from insightface.app import FaceAnalysis
from insightface.data import get_image as ins_get_image

# 画像の読み込み
image = cv2.imread('O:/Python/img/23337234_s.jpg')

#モデルの読み込み
app = FaceAnalysis(providers=['CUDAExecutionProvider', 'CPUExecutionProvider'])
app.prepare(ctx_id=0, det_size=(640, 640))

# 顔の検出
faces = app.get(image)

# 顔の境界ボックスとランドマークを描画
for face in faces:

    # 顔の境界ボックスを描画
    if face.bbox is not None:
        bbox = face.bbox.astype(int)
        cv2.rectangle(image, (bbox[0], bbox[1]), (bbox[2], bbox[3]), (0, 255, 0), 2)

    # ランドマークを描画
    if face.landmark_2d_106 is not None:
        for landmark in face.landmark_2d_106.astype(int):
            cv2.circle(image, tuple(landmark), 1, (0, 0, 255), -1)


# 結果の表示
cv2.imshow('Face Detection', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

結果は以下の通りで、ランドマーク部分(目、鼻、口、輪郭)に点が描画されていることが分かります。

InsightFaceを使った顔のランドマーク検出結果

顔が小さすぎて良く分からなかったので、顔が大きく映っている写真を使ってみました。結果は以下の通りです。

InsightFaceを使った顔のランドマーク検出結果(拡大図)

dlibを使った顔認識

dlib を使う場合は、あらかじめ下記のインストールを実行して下さい。

pip install dlib

顔検出

下記が dlib を使った顔検出のサンプルプログラムです。

import cv2
import dlib


# 入力画像の読み込み
image = cv2.imread('O:/Python/img/23337234_s.jpg')


# 顔検出器の初期化
detector = dlib.get_frontal_face_detector()

# 顔の検出
faces = detector(image,2)

# 顔の境界ボックスを描画
for face in faces:
    x, y, w, h = face.left(), face.top(), face.width(), face.height()
    cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)

# 結果の表示
cv2.imshow('Face Detection', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

detectorメソッドの第2引数で認識精度を指定します。1だと検出されない顔があったので、2を指定しました。結果は以下の通り全員の顔が検出されました。

dlibを使った検出結果

顔のランドマーク検出

顔のパーツ検出を行う場合、あらかじめ下記のインストールを行ってください。

pip install imutils

顔のパーツを検出する場合、ランドマーク検出器の学習済みファイルをダウンロードして使う必要があります。下記のURLから、shape_predictor_68_face_landmarks.dat をダウンロードして下さい。

https://github.com/italojs/facial-landmarks-recognition

dlibを使った顔のランドマーク検出用データのダウンロードキャプチャ画像

ダウンロードしたら、 dlib.shape_predictorの引数にフルパスを指定します。私の場合は Oドライブ直下にフォルダを作って、そこに格納しましたので、次のようになりました。

dlib.shape_predictor("O:/Python/facial-landmarks/shape_predictor_68_face_landmarks.dat")

import cv2
import dlib
import imutils
from imutils import face_utils

# 入力画像の読み込み
image = cv2.imread('O:/Python/img/23337234_s.jpg')

# 顔検出器の初期化
detector = dlib.get_frontal_face_detector()

# ランドマーク検出器の読み込み
predictor = dlib.shape_predictor("O:/Python/facial-landmarks/shape_predictor_68_face_landmarks.dat") 

# 顔の検出
faces = detector(image,2)

# 顔の境界ボックスとランドマークを描画
for face in faces:
    # 顔の境界ボックスを描画
    x, y, w, h = face.left(), face.top(), face.width(), face.height()
    cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
    
    # ランドマークを描画
    face_parts_dets = predictor(image, face)
    face_parts = face_utils.shape_to_np(face_parts_dets)
    for (x, y) in face_parts:
        cv2.circle(image, (x,y),2, (0,0,255), thickness= -1)

# 結果の表示
cv2.imshow('Face Detection', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

結果は以下の通りです。顔のパーツに68個の点が描画されているのですが、小さすぎて良く分かりませんね。

dlibを使った顔のランドマーク検出結果

先ほどと同様、顔が大きく映っている写真を使ったところ、ちゃんと顔のパーツに沿って点が描かれていることが分かります。

dlibを使った顔のランドマーク検出結果の拡大図

face recognitionを使った顔認識

face recognition を使うには、次のインストールが必要となります。

pip install face_recognition

顔検出

以下は face recognition を使ったサンプルプログラムです。認識精度の指定は face_locations メソッドの第2引数で行います。

dlib をベースに使っているためか、こちらも1だと検出されない顔が出てしまったため、2を設定しました。

import cv2
import face_recognition

# 画像の読み込み
image = cv2.imread('O:/Python/img/23337234_s.jpg')

# 顔の検出
face_locations = face_recognition.face_locations(image,2)

# 顔の境界ボックスを描画
for face_location in face_locations:
    top, right, bottom, left = face_location
    cv2.rectangle(image, (left, top), (right, bottom), (0, 255, 0), 2)

# 結果の表示
cv2.imshow('Face Detection', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

検出精度は dlib と同等のようです。

face recognitionを使った顔の検出結果

顔のランドマーク検出

dlib をベースに改良されているだけ、face recognitionの方がランドマーク検出は簡単です。追加でファイルをダウンロードすることなく、簡単に検出できてしまいます。

import cv2
import face_recognition

# 画像の読み込み
image = cv2.imread('O:/Python/img/23337234_s.jpg')

# 顔の検出
face_locations = face_recognition.face_locations(image, 2)
face_landmarks_list = face_recognition.face_landmarks(image, face_locations)

# 顔の境界ボックスとランドマークを描画
for face_location, face_landmarks in zip(face_locations, face_landmarks_list):

    # 顔の境界ボックスを描画
    top, right, bottom, left = face_location
    cv2.rectangle(image, (left, top), (right, bottom), (0, 255, 0), 2)

    # 顔のランドマークを描画
    for landmark in face_landmarks.values():
        for point in landmark:
            cv2.circle(image, point, 2, (0, 0, 255), -1)

# 結果の表示
cv2.imshow('Face Detection', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

結果は以下の通りですが、dlib の結果と見比べても違いが分かりませんでした。おそらく同じだと思われます。

face recognitionを使った顔のランドマーク検出結果
face recognitionを使った顔のランドマーク検出結果(拡大図)

まとめ

今回はPythonで使える顔検出/顔認識のライブラリについて、有名な4種類について一通り解説しました。

OpenCVだけを使った顔検出は処理時間は速いのですが、検出できないケースがあるので、他のライブラリより精度は劣るようです。

一方、insightFace は特に設定を調整することなしに満足な結果が得られました。dlib ,face recognition については、初期値だと検出できないケースがあったものの、設定を調整すれば満足いく結果が得られました。

一番精度が高くお手軽なのは insightFace ですが、処理速度は dlib ,face recognition の方が倍近く高速です。

機能の豊富さは insightFace が一番多いので、使いたい機能や処理速度に応じて、最適なものをお選び下さい。

今回の記事が皆さまのお役に立てば光栄です。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次