#実行環境
Ubuntu 16.04
Python 3.7
opencv-python 4.1.0.25
#概要
OpenCVに実装されている顔認識ライブラリを利用し、顔のランドマークを検出する。
#ランドマークとは
ランドマークは、地理学上では「目印や象徴となる特徴物」とされるが、
顔認識においては顔の**キーポイント(特徴点)**を指す。
ランドマークを用いることで、表情の認識や人物の識別などの応用ができる。
顔に対してランドマークを検出すると、目、鼻、口、眉、輪郭部分が検出される。※学習データにより異なる
例えば、顔の特徴を68点で表した学習データで検出すると、
下図のように検出されたランドマークに番号がデータ(配列の要素番号)として割り振られる。
#準備
-
カスケードファイルの用意
まず、顔領域を検出するためにカスケードファイルが必要。
カスケードファイルには物体を分類するための情報が記載されており、
顔のカスケードファイルはOpenCVが公式配布している。
今回使用するファイルは**「haarcascade_frontalface_default.xml」**という正面の顔用の分類器。
これをhaarcascades/
下に置く。
-
学習済みデータの用意
検出時は、顔検出のAPIであるFacemark APIを用いる。
Facemark APIでは、ランドマーク検出のために学習済みのデータを利用する。
ランドマークのデータとして、dlibの学習済みデータをlearned-models/
に解凍。 -
パスを指定
1 , 2 を読み込むためのパスを指定しておく。
# OpenCVのカスケードファイルと学習済みモデルのパスを指定
CASCADE_PATH = "./haarcascades/"
CASCADE = cv2.CascadeClassifier(CASCADE_PATH + 'haarcascade_frontalface_default.xml')
LEARNED_MODEL_PATH ="./learned-models/"
PREDICTOR = dlib.shape_predictor(LEARNED_MODEL_PATH + 'shape_predictor_68_face_landmarks.dat')
後は関数内で呼び出すだけで検出できる。
ランドマークを検出する関数の実装は以下の通り。
検出された全ての顔に対してランドマークを検出する。
# 顔の位置を検出 返却値は位置を表すリスト(x,y,w,h)
def face_position(gray_img):
faces = CASCADE.detectMultiScale(gray_img, minSize=(100, 100))
return faces
# ランドマーク検出
def facemark(gray_img):
faces_roi = face_position(gray_img)
landmarks = []
for face in faces_roi:
detector = dlib.get_frontal_face_detector()
rects = detector(gray_img, 1)
landmarks = []
for rect in rects:
landmarks.append(
numpy.array([[p.x, p.y] for p in PREDICTOR(gray_img, rect).parts()]) )
return landmarks
今回はやっていないが、CASCADE.detectMultiScale()
の返却値を使うことで、顔領域を矩形で囲ったりもできる。
準備を終えた段階のディレクトリ階層は以下の通り。
- haarcascades/
| - haarcascade_frontialface_default.xml
- learned-models/
| - shape_predictor_68_face_landmarks.dat
- img/
| - input.jpg
- result/
| - output.jpg(※)
- main.py
※「output.jpg」は出力時に生成される
#ソースコード
#-*- coding: utf-8 -*-
import cv2
import dlib
import numpy
#OpenCVのカスケードファイルと学習済みモデルのパスを指定
CASCADE_PATH = "./haarcascades/"
CASCADE = cv2.CascadeClassifier(CASCADE_PATH + 'haarcascade_frontalface_default.xml')
LEARNED_MODEL_PATH ="./learned-models/"
PREDICTOR = dlib.shape_predictor(LEARNED_MODEL_PATH + 'shape_predictor_68_face_landmarks.dat')
# 顔の位置を検出 返却値は位置を表すリスト(x,y,w,h)
def face_position(gray_img):
faces = CASCADE.detectMultiScale(gray_img, minSize=(100, 100))
return faces
# ランドマーク検出
def facemark(gray_img):
faces_roi = face_position(gray_img)
landmarks = []
for face in faces_roi:
detector = dlib.get_frontal_face_detector()
rects = detector(gray_img, 1)
landmarks = []
for rect in rects:
landmarks.append(
numpy.array([[p.x, p.y] for p in PREDICTOR(gray_img, rect).parts()]))
return landmarks
def main():
img = cv2.imread("./img/input.jpg")#自分の画像に置き換え
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#処理を早くするためグレースケールに変換
landmarks = facemark(gray)#ランドマーク検出
# ランドマークの描画
for landmark in landmarks:
for points in landmark:
cv2.drawMarker(img, (points[0], points[1]), (21, 255, 12))
# 表示
cv2.imshow("video frame", img)
cv2.waitKey(0)
# 保存
cv2.imwrite("./result/output.jpg", img)
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
#検出
以上で検出の準備ができたので、入力画像を用意してmain.py
を実行。
ランドマークが検出できた。
各点の座標情報を元に、表情の推定などができる。
#参考文献