python

OpenCVとdlibを使って顔認識(face recognition)してみる【前編】

いきなりの実装に入る前に、簡単に理論のおさらいと基本的な実装方法をおさえておきます。

その後に、ウェブカメラを使って顔を検出し、似ている人を選択するアプリを作成します。

顔認識で検出するまでの流れ

  1. 画像もしくは動画を見て顔を見つける
  2. 顔に焦点を合わせ、顔が正面を向いていなくても人だと認識できる
  3. 目の大きさ、顔の長さなど他の人と区別するために固有の特徴量を選択
  4. 検出した顔の特徴を、他の人と比較して一番似ている人を決定

顔を見つける

顔かどうかを判定するためには、いくつか方法があります。

まず、ピクセルを明るさの差でグラデーションに置き換えることで、明るさの変化の方向だけを考えることができます。

そうすれば、画像の基本パターンを知ることができるので顔の特徴を抽出しやすくなります。

この手法はHOGと呼ばれものです。

顔の向きの不一致

正面を向いている顔は認識しやすいのですが、斜めや横を向いていると途端に難しくなります。

そこで、face landmarkと呼ばれるものを使用し、アフィン変換をすることで認識しやすくします。

3D変換まで下手にやると元の画像と別物になってしまうので注意が必要です。それに対して、アフィン変換は大幅に崩れることはないので安心です。

顔のエンコード

自分と似ている人物を探す方法として、web上に上がっている全ての人物の画像と比較するのが最も単純な方法です。

ただ、この方法では処理に時間がかかりすぎます。

そこで、それぞれの顔から基本的な測定値というものを抽出します。

例えば、鼻の長さ・目の間隔などです。1点注意が必要なのが人間が重要だと思っているものとコンピューターが重要と思っているものは違うという点です。

ディープラーニングは何を測定すればいいのかを人間よりも把握しています。そのため、DNNを利用して顔ごとに128個の測定値を生成するように学習します。

この訓練したデータは様々企業が公開してくれているので、今回は気にせず進めていきます。

つまり、自分で行う必要があるのは事前にトレーニングされたネットワークを用いて、顔の128個の測定値を取得することだけです。

実装フェーズ

最初に必要なライブラリをインストールしておきます。

機械学習のライブラリにはscikit-learnの場合が多いですが、今回は精度をあげるためにdlibを使っていきます。

重要なのが、cmakeをインストールすることです。dlibはC++のライブラリなのでcmakeが必要になってきます。

pip install cmake
pip install dlib
pip install face-recognition
pip install numpy
pip install opencv-python

まずは画像に対して、顔認識をしていきたいのでテスト用の画像を用意します。

google検索から引っ張ってきてもいいですし、下記の画像をダウンロードして使用しても大丈夫です。

イーロン・マスクとビル・ゲイツの画像を用意しました。

それでは、コードを実装していきます。先程ダウンロードした画像は任意のフォルダに保存しておいてください。

コード内のパスに関しては適宜変更してください。

ライブラリの使い方について詳しく知りたい方は、公式ドキュメントを参照ください。

https://face-recognition.readthedocs.io/en/latest/readme.html

import cv2
import face_recognition

# step1 画像読み込みとコンバート
img_elon = face_recognition.load_image_file('image/elon.png')
img_elon = cv2.cvtColor(img_elon, cv2.COLOR_BGR2RGB)
img_test = face_recognition.load_image_file('image/elon_test.jpeg')
img_test = cv2.cvtColor(img_test, cv2.COLOR_BGR2RGB)

# step2 顔認証
face_loc = face_recognition.face_locations(img_elon)[0]

# 128次元の顔エンコーディングのリスト
encode_elon = face_recognition.face_encodings(img_elon)[0]
cv2.rectangle(img_elon, (face_loc[3], face_loc[0]), (face_loc[1], face_loc[2]), (255, 0, 255), 2)

face_loc_test = face_recognition.face_locations(img_test)[0]
encode_elon_test = face_recognition.face_encodings(img_test)[0]

# print(encode_elon_test)
cv2.rectangle(img_test, (face_loc_test[3], face_loc_test[0]), (face_loc_test[1], face_loc_test[2]), (255, 0, 255), 2)

# 2つの画像が同一人物かの判定
results = face_recognition.compare_faces([encode_elon], encode_elon_test)
# 値が小さい程マッチしている
face_dis = face_recognition.face_distance([encode_elon], encode_elon_test)
print(results, face_dis)

# 8秒でwindowが閉じる設定
cv2.startWindowThread()
cv2.imshow('Elon Musk', img_elon)
cv2.imshow('Elon Test', img_test)

cv2.waitKey(8000)

cv2.waitKey(1)
cv2.destroyAllWindows()
cv2.waitKey(1)

この状態で実行してみましょう。下記のようにコンソールにTrueと表示されていれば同一人物として認識されています。

img_test = face_recognition.load_image_file(‘image/elon_test.jpeg’)

をビル・ゲイツの画像に変更してみるとコンソールにFalseと表示されるはずです。右側にある値が小さい程、同一人物である可能性が高くなります。

以上で画像から同一人物かそうでないかの判断するプログラムの実装は完了です。

次回は動画で自分の顔を試せるようにしていきます。