【Python】お手軽に顔認証を実装する①

## はじめに

Pythonのライブラリを使う事で、お手軽に顔認証を実装する事ができます。まだ、顔認証を実装した事がない、顔認証を使ったアプリを作りたいといった方に、ぜひ読んでいただきたいです。

次回の記事はこちら --> [【Python】お手軽に顔認証を実装する②](https://qiita.com/f-paico/items/6f215f8bd467906806b5)

## 動作環境

- M1 Mac
- Python 3.9.6

## ライブラリのインストール

今回は、無料で使えるPythonのライブラリとして[face-recognition](https://pypi.org/project/face-recognition/)を使用します。face-recognitionは、dlibという機械学習・画像処理関連のオープンソースのライブラリによって作られたPythonのライブラリです。Labeled Faces in the Wild というデータセットを用いて、99.38%の精度が出ているようです。以下のコマンドでライブラリをインストールします。また、顔認証に必要な顔検出についても説明しますので、matplotlibも一緒にインストールしておきましょう。

```bash
pip3 install face-recognition 
pip3 install matplotlib
```

## 実装の準備

まず、Pythonのプログラムを記述するtest.pyを作成します。そして、学習データとして用いる画像train.jpgとテストデータとして用いるtest.jpgを準備して、test.pyと同じ階層に置きます。私は、オバマさんの顔画像を2種類用意して、train.jpg、test.jpgとしています。

```bash
Sample
├── test.py
├── train.png
└── test.png
```

### 顔検出の実装

画像から顔認証を行うには、まず画像から顔を検出し、その上で顔認証を行う必要があります。そのため、まずは顔検出から実装していきます。test.pyを以下のとおり記述します。

```python
# ライブラリの読み込み
import face_recognition
import matplotlib.pyplot as plt

# 学習させたい（登録したい）顔画像のファイル名をリストに格納
train_img_names = ["train.jpg", ]
# 学習させた画像に対して、認証できるかテストに使う顔画像のファイル名をリストに格納
test_img_name = "test.jpg"

# 学習データの顔画像を読み込む
train_imgs = []
for name in train_img_names:
    train_img = face_recognition.load_image_file(name)
    train_imgs.append(train_img)

# テストデータ（認証する人の顔画像）を読み込む
test_img = face_recognition.load_image_file(test_img_name)

# 学習データの顔画像から顔の領域のみを検出する
train_img_locations = []
for img in train_imgs:
    # modelはhogとcnnを指定でき、cnnは重いが精度良い、hogは軽量だが精度は普通
    train_img_location = face_recognition.face_locations(img, model="hog")
    # 顔検出に失敗するとtrain_img_locationの長さは1となる
    # 顔検出に成功すると顔を検出し四角形で囲んだ四隅の座標を取得できる
    assert len(train_img_location) == 1, "画像から顔の検出に失敗したか、2人以上の顔が検出されました"
    train_img_locations.append(train_img_location)

# テストデータの顔画像から顔の領域のみを検出する
test_img_location = face_recognition.face_locations(test_img, model="hog")
assert len(test_img_location) == 1, "画像から顔の検出に失敗したか、2人以上の顔が検出されました"

# 顔検出の結果を可視化する関数を定義
def draw_img_locations(imgs, locations):
    fig, ax = plt.subplots()
    ax.imshow(imgs)
    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, location in zip(train_imgs, train_img_locations):
    draw_img_locations(img, location)

# テストデータで顔検出した結果を可視化する
draw_img_locations(test_img, test_img_location)
```

上記のプログラムを実行すると、以下のように顔検出ができていることが確認できます。顔検出を行う事ができたか動作確認しておきましょう。

学習データ

![Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674933/61166bde-32ec-3c84-2b3b-76692c202aee.png)

テストデータ

![Figure_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674933/53b3ad71-13c8-6129-63c9-c1aaa6df5652.png)

### 顔認証を実装

先ほどのtest.pyの続きから、以下のとおり顔認証のプログラムを記述します。

```python
# 学習データの特徴量を抽出する
train_img_encodings = []
for img, location in zip(train_imgs, train_img_locations):
    (encoding, ) = face_recognition.face_encodings(img, location)
    train_img_encodings.append(encoding)

# テストデータの特徴量を抽出する
(test_img_encoding, ) = face_recognition.face_encodings(test_img, test_img_location)

# 学習データとテストデータの特徴量を比較し、ユークリッド距離を取得する
# 距離を見ることで顔がどれだけ似ているかわかる
dists = face_recognition.face_distance(train_img_encodings, test_img_encoding)

# 学習データとテストデータの距離が0.40以下のとき、顔が一致と判定
answer = False
for dist in dists:
    if dist < 0.40:
        answer = True

# 顔認証の結果を出力する
print(answer)
```

以上のプログラムを実行する事で、顔認証が実現できます。実際に動作確認しておきましょう。

## おわりに

Pythonのライブラリとしてface-recognitionを使って、お手軽に顔認証を実装してみました。こちらのプログラムを拡張して、様々なアプリに活用いただけると嬉しいです。次回は、クライアントからサーバに顔画像をアップロードして、アップロードした顔画像を使って顔認証を行ってみようかと思います。

次回の記事が完成しました！ --> [【Python】お手軽に顔認証を実装する②](https://qiita.com/f-paico/items/6f215f8bd467906806b5)

## 参考文献

- https://github.com/ageitgey/face_recognition/blob/master/README_Japanese.md