Pythonで顔検出/認識する方法はいくつかありますが、それぞれ個別の解説記事はあるものの、まとまったものが見つかりませんでした。
そこで、今回は整理する意味も込めてPythonで使える顔検出/認識ライブラリ OpenCV、InsightFace、Dlib、Face Recognition について一通り紹介していきたいと思います。
Pythonで使える顔認識ライブラリ
比較項目 | 用途 | OpenCV | InsightFace | Dlib | Face Recognition |
---|---|---|---|---|---|
顔検出 | 顔の検出 | ○ | ○ | ○ | ○ |
顔認識 | 人物の特定 | × | ○ | × | ○ |
顔解析 | 顔の構造、表情、特徴点 | × | ○ | × | ○ |
顔属性の推定 | 性別、年齢、人種、感情 | × | ○ | × | × |
顔特徴の抽出と比較 | 顔の特徴を他の顔と比較 | × | ○ | × | × |
顔のクラスタリング | 顔の類似性による分類 | × | ○ | × | × |
顔のランドマーク検出 | 顔のパーツの位置特定 | × | ○ | ○ | ○ |
3D顔形状推定 | 写真から顔の立体化 | × | ○ | × | × |
ライブラリ名 | 概要 |
---|---|
OpenCV | 汎用的な画像処理ライブラリであり、その中の1つの機能として顔検出が用意されています。 顔を検出する以外(顔認識、顔解析、顔属性の推定など)の機能はサポートされていません。 |
InsightFace | 顔認識と顔解析に特化したライブラリです。 顔検出、顔認識、顔解析、顔属性の推定、顔特徴の抽出と比較、顔のクラスタリングと識別、顔のランドマーク検出、3D顔形状推定をサポートしています。 |
Dlib | 顔検出と顔のランドマーク検出に特化したライブラリです。 それ以外(顔認識、顔解析、顔属性の推定など)の機能はサポートされていません。 |
Face Recognition | Dlibをベースとした顔検出と顔認識のライブラリです。 顔検出、顔認識、顔解析、顔のランドマーク検出をサポートしています。 |
OpenCVを使った顔認識
OpenCVを使った顔検出を行うために、最初にライブラリを pip でインストールしておきます。
pip install opencv-python
標準の顔検出器を使う方法
以下がOpenCV標準の顔検出器を使ったサンプルプログラムです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
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'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
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 を使った顔検出のサンプルプログラムです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
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 では顔検出と同時に顔のランドマーク検出も行っています。先ほどのサンプルプログラムのループ部分に、ランドマーク検出結果の取得と点の描画を付け加えてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
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() |
結果は以下の通りで、ランドマーク部分(目、鼻、口、輪郭)に点が描画されていることが分かります。
顔が小さすぎて良く分からなかったので、顔が大きく映っている写真を使ってみました。結果は以下の通りです。
dlibを使った顔認識
dlib を使う場合は、あらかじめ下記のインストールを実行して下さい。
pip install dlib
顔検出
下記が dlib を使った顔検出のサンプルプログラムです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
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を指定しました。結果は以下の通り全員の顔が検出されました。
顔のランドマーク検出
顔のパーツ検出を行う場合、あらかじめ下記のインストールを行ってください。
pip install imutils
顔のパーツを検出する場合、ランドマーク検出器の学習済みファイルをダウンロードして使う必要があります。下記のURLから、shape_predictor_68_face_landmarks.dat をダウンロードして下さい。
https://github.com/italojs/facial-landmarks-recognition
ダウンロードしたら、 dlib.shape_predictorの引数にフルパスを指定します。私の場合は Oドライブ直下にフォルダを作って、そこに格納しましたので、次のようになりました。
dlib.shape_predictor("O:/Python/facial-landmarks/shape_predictor_68_face_landmarks.dat")
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
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個の点が描画されているのですが、小さすぎて良く分かりませんね。
先ほどと同様、顔が大きく映っている写真を使ったところ、ちゃんと顔のパーツに沿って点が描かれていることが分かります。
face recognitionを使った顔認識
face recognition を使うには、次のインストールが必要となります。
pip install face_recognition
顔検出
以下は face recognition を使ったサンプルプログラムです。認識精度の指定は face_locations メソッドの第2引数で行います。
dlib をベースに使っているためか、こちらも1だと検出されない顔が出てしまったため、2を設定しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
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 と同等のようです。
顔のランドマーク検出
dlib をベースに改良されているだけ、face recognitionの方がランドマーク検出は簡単です。追加でファイルをダウンロードすることなく、簡単に検出できてしまいます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
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 の結果と見比べても違いが分かりませんでした。おそらく同じだと思われます。
まとめ
今回はPythonで使える顔検出/顔認識のライブラリについて、有名な4種類について一通り解説しました。
OpenCVだけを使った顔検出は処理時間は速いのですが、検出できないケースがあるので、他のライブラリより精度は劣るようです。
一方、insightFace は特に設定を調整することなしに満足な結果が得られました。dlib ,face recognition については、初期値だと検出できないケースがあったものの、設定を調整すれば満足いく結果が得られました。
一番精度が高くお手軽なのは insightFace ですが、処理速度は dlib ,face recognition の方が倍近く高速です。
機能の豊富さは insightFace が一番多いので、使いたい機能や処理速度に応じて、最適なものをお選び下さい。
今回の記事が皆さまのお役に立てば光栄です。
コメント