29
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PythonでOpenCVの顔認識を試してみた

Last updated at Posted at 2019-09-12

#実行環境
Ubuntu 16.04
Python 3.7
opencv-python 4.1.0.25
#概要
OpenCVに実装されている顔認識ライブラリを利用し、顔のランドマークを検出する。

#ランドマークとは
ランドマークは、地理学上では「目印や象徴となる特徴物」とされるが、
顔認識においては顔の**キーポイント(特徴点)**を指す。
ランドマークを用いることで、表情の認識や人物の識別などの応用ができる。

顔に対してランドマークを検出すると、目、鼻、口、眉、輪郭部分が検出される。※学習データにより異なる
例えば、顔の特徴を68点で表した学習データで検出すると、
下図のように検出されたランドマークに番号がデータ(配列の要素番号)として割り振られる。

#準備

  1. カスケードファイルの用意
    まず、顔領域を検出するためにカスケードファイルが必要。
    カスケードファイルには物体を分類するための情報が記載されており、
    顔のカスケードファイルはOpenCVが公式配布している。
    今回使用するファイルは**「haarcascade_frontalface_default.xml」**という正面の顔用の分類器。
    これをhaarcascades/下に置く。
     

  2. 学習済みデータの用意
    検出時は、顔検出のAPIであるFacemark APIを用いる。
    Facemark APIでは、ランドマーク検出のために学習済みのデータを利用する。
    ランドマークのデータとして、dlibの学習済みデータlearned-models/に解凍。

  3. パスを指定
    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」は出力時に生成される

#ソースコード

main.py
#-*- 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を実行。

ランドマークが検出できた。
各点の座標情報を元に、表情の推定などができる。

#参考文献

29
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?