Warning: Undefined variable $position in /home/pystyles/pystyle.info/public_html/wp/wp-content/themes/lionblog/functions.php on line 4897

Python – 顔認識ライブラリ Face Recognition で顔認証を行う方法

Python – 顔認識ライブラリ Face Recognition で顔認証を行う方法

概要

dlib を使った Python の顔認識ライブラリ Face Recognition を使って、顔認証を行う方法について紹介します。 顔認証は、予め保存されている個人の顔のデータと認証中の顔の画像とを照合し、その人物が誰であるかを識別する技術です。 スマートフォンのロック解除や入退室管理など、セキュリティが求められる分野で広く使われています。

Advertisement

環境

コード全体は pystyle/perform-face-recognition-with-python にあります。

このコードは、以下の環境で実行しました。

Ubuntu 18.04

  • ライブラリ
    • Face Recognition: 1.2.3
  • GPU の実行環境
    • GPU: GeForce GTX 1080
    • CUDA: 9.0
    • CuDNN: 7
  • CPU の実行環境
    • CPU: Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz
    • メモリ: 16G

Windows 10

  • ライブラリ
    • Face Recognition: 1.2.3
  • CPU の実行環境
    • CPU: Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz
    • メモリ: 16G
検出に CNN を使う場合、CUDA 10.1/cudnn7 環境では、`CUDA Runtime API initialization failed.` というエラーが発生して動きませんでした。 CUDA 9/cudnn7 環境では動作したので、動作しない場合は CUDA のバージョンを確認してみてください。

インストール

Advertisement

Ubuntu 18.04 の場合

インストール時に Face Recognition が利用している dlib のビルドが必要になります。 インストール前に apt で GCC 及び CMake をインストールし、C++ のビルド環境を整えます。

apt install -y build-essential cmake

準備ができたら、pip で Face Recognition をインストールします。

pip install face_recognition

Windows 10 の場合

インストール前に Visual Studio 2019 CommunityCMake をインストールし、C++ のビルド環境を整えます。

準備ができたら、pip で Face Recognition をインストールします。

pip install face_recognition

顔認証の手順

以下の3人が予め保存されている人物の顔の画像とします。

known-face_01.jpg

known-face_02.jpg

known-face_03.jpg

以下を認証する人物の顔の画像とします。

face_to_check.jpg

顔画像を読み込む

load_image_file() で顔の画像を読み込みます。

In [1]:
import face_recognition
import matplotlib.pyplot as plt

# 保存されている人物の顔の画像を読み込む。
known_face_imgs = []
for path in ["known-face_01.jpg", "known-face_02.jpg", "known-face_03.jpg"]:
    img = face_recognition.load_image_file(path)
    known_face_imgs.append(img)

# 認証する人物の顔の画像を読み込む。
face_img_to_check = face_recognition.load_image_file("face_to_check.jpg")
Advertisement

顔の領域を検出する

face_locations() で読み込んだ顔の画像から、顔の領域を検出します。 返り値は顔の領域を表す (top, right, bottom, left) の tuple の list になっています。

model は検出に使用するモデルを指定します。 “hog” (デフォルト) を指定した場合、HOG 特徴量 ベースのモデルになります。 “cnn” を指定した場合、CNN ベースのモデルになります。

HOG CNN
計算量 少ない 多い
精度

CNN のほうが高精度ですが、計算量が多く、CPU で実行した場合は時間がかかってしまいます。GPU が使える PC ではこちらを選択するとよいでしょう。

GPU が利用可能な環境でないと、`model=”cnn”` はエラーとなる可能性があります。 その場合、`model=”hog”` に変更してください。
In [2]:
# 顔の画像から顔の領域を検出する。
known_face_locs = []
for img in known_face_imgs:
    loc = face_recognition.face_locations(img, model="cnn")
    assert len(loc) == 1, "画像から顔の検出に失敗したか、2人以上の顔が検出されました"
    known_face_locs.append(loc)

face_loc_to_check = face_recognition.face_locations(face_img_to_check, model="cnn")
assert len(face_loc_to_check) == 1, "画像から顔の検出に失敗したか、2人以上の顔が検出されました"

結果を確認するために、matplotlib で顔の領域を画像上に描画します。

In [3]:
def draw_face_locations(img, locations):
    fig, ax = plt.subplots()
    ax.imshow(img)
    ax.set_axis_off()
    for i, (top, right, bottom, left) in enumerate(locations):
        # 長方形を描画する。
        w, h = right - left, bottom - top
        ax.add_patch(plt.Rectangle((left, top), w, h, ec="r", lw=2, fill=None))
    plt.show()


for img, loc in zip(known_face_imgs, known_face_locs):
    draw_face_locations(img, loc)
    
draw_face_locations(face_img_to_check, face_loc_to_check)

画像から顔の領域が正しく検出できていることがわかりました。

顔の領域から特徴量を抽出する

face_encodings で顔の画像から識別に有用な特徴量を抽出します。

face_encodings(face_image, known_face_locations=None)
  • 引数
    • face_image: 画像
    • known_face_locations: face_locations() の返り値 locations を渡します。

返り値は、顔の特徴量を表す1次元の numpy 配列の list となっています。

In [4]:
# 顔の領域から特徴量を抽出する。
known_face_encodings = []
for img, loc in zip(known_face_imgs, known_face_locs):
    (encoding,) = face_recognition.face_encodings(img, loc)
    known_face_encodings.append(encoding)

(face_encoding_to_check,) = face_recognition.face_encodings(
    face_img_to_check, face_loc_to_check
)

マッチする人物がいるかどうかを調べる

登録されている人物の顔の特徴量 known_face_encodings と認証する人物の顔の特徴量 face_encoding_to_checkcompare_faces に渡すことで、登録されている人物の中にマッチする人物がいるかどうかを調べられます。 tolerance はマッチするかどうかを判定する閾値で、この値を低くするほど判定が厳しくなり、高くするほど判定が緩くなります。

In [5]:
matches = face_recognition.compare_faces(known_face_encodings, face_encoding_to_check)
print(matches)  # [True, False, False]
[True, False, False]

認証する人物は登録されている1人目の人物とマッチしていると判定されました。 登録されている1人目の人物はオバマ大統領なので、正解しています。

特徴量同士の距離を計算する

内部的には、似ているかどうかの判定は特徴量同士の距離で判定しています。 距離が近いほど似ていて、遠いほど似ていないといえます。 この距離は face_distance で計算できます。

In [6]:
dists = face_recognition.face_distance(known_face_encodings, face_encoding_to_check)
print(dists)
[0.32466209 0.8858496  0.88910518]

認証する人物は一人目のオバマ大統領との距離が最も近い結果となりました。