👩‍👩‍👧‍👧

InsightFaceで顔認証(特徴量抽出、比較)してみた

2021/08/03に公開

目次

初めに

前回、前々回と、InsightFaceを使った顔検出の例を紹介しました。
今回は、InsightFaceを使って顔認証(Face Recognition)を試してみたいと思います。

顔認証とは

顔認証とは:

  • 提示された画像に含まれている顔が、事前に登録されているどの顔に一番近いか?
  • 2つの顔画像、顔Aと顔Bはどれだけ類似しているか?

みたいなことを調べるタスクです。

今回は「2つの画像に含まれている顔は、それぞれどれくらい類似しているか」を出力するウェブアプリを作ってみました。

実行例

今回も実行例からご覧ください。

なお、画像はぱくたそから以下の2枚をお借りしました。

画像1に含まれる顔が行、画像2に含まれる顔が列として表示され、その交点に類似度が表示されます。
横を向いていたり、しかめっ面をしていたりと難易度が高めの画像ですが、同じモデルさんの場合は高い類似度が出力されているのが分かります。

環境

環境は先の記事と同様です。

ソースコード

ソースコード一式はGitHubの以下のリポジトリに置いています。
本記事執筆時のタグは20210803aです。

https://github.com/nayutaya/202107-face-detector

ビルド&実行

タグが異なる以外は、ビルド方法は先の記事と同様です。例を以下に示します。

# リポジトリを取得
git clone https://github.com/nayutaya/202107-face-detector.git
cd 202107-face-detector
# タグをチェックアウト
git checkout 20210803a
# Dockerイメージをビルドする
docker-compose build
# Dockerコンテナをバックグラウンドで起動する
docker-compose up -d

# ウェブアプリを開く
open http://localhost:8001/compare

# (試したあとに)Dockerコンテナを停止する
docker-compose down

InsightFaceを使った顔認証

ウェブアプリを実装する前に、まずは単純なコードで顔認証してみましょう。

以下のcompare.pyは、2つの画像(a.jpgb.jpg)に含まれる1番目の顔の類似度を求める例です。大まかな処理の内容は以下の通りです。

  1. InsightFaceを初期化する。
  2. a.jpgを読み込み、前処理を実施する。(画像1)
  3. 画像1に対して顔検出を行い、1番目の顔の特徴量を取得する。(特徴量1)
  4. b.jpgを読み込み、前処理を実施する。(画像2)
  5. 画像2に対して顔検出を行い、1番目の顔の特徴量を取得する。(特徴量2)
  6. 特徴量1と特徴量2の類似度(大きいほど似ている)を出力する。
compare.py
#!/usr/bin/env python3

import insightface
import numpy as np
import PIL.Image


def read_image(file_path):
    image = PIL.Image.open(file_path).convert("RGB")
    image = np.array(image)
    image = image[:, :, [2, 1, 0]]  # RGB to BGR
    return image


# REF: https://github.com/deepinsight/insightface/blob/f474870cc5b124749d482cf175818413a9fe12cd/python-package/insightface/model_zoo/arcface_onnx.py#L70
def compute_sim(feat1, feat2):
    return np.dot(feat1, feat2) / (np.linalg.norm(feat1) * np.linalg.norm(feat2))


face_analysis = insightface.app.FaceAnalysis()
face_analysis.prepare(ctx_id=0, det_size=(640, 640))

image1 = read_image("a.jpg")
faces1 = face_analysis.get(image1)
embedding1 = faces1[0].embedding

image2 = read_image("b.jpg")
faces2 = face_analysis.get(image2)
embedding2 = faces2[0].embedding

print(compute_sim(embedding1, embedding2))

とても簡単ですね。

顔認証ウェブアプリ

続いて、前回までと同様、FastAPIとNext.jsを使ってバックエンド、フロントエンドを実装しました。

バックエンド

バックエンドでは2つの処理を行います。「顔検出」と「特徴量の比較」です。

  • 顔検出はPOST /detectにて行います。以前の実装に、顔特徴量の出力処理を追加しました。
  • 特徴量の比較はPOST /compareにて行います。複数の特徴量を同時に比較することができます。

詳しくはdetector-insightface/src/main.pyをご覧ください。

顔特徴量は512次元の浮動小数点数なので、JSONに変換すると容量が大きく、無駄が多いです。
そのため、NumPy形式でダンプしたデータをBase64形式に変換して扱っています。

特徴量の比較については、サンプルデータをembeddings.jsonとして用意しています。
サンプルデータをcurlコマンドを使って送信することで、動作を確認することができます。

curl -X POST \
  --header "Content-Type: application/json" \
  --data-binary @embeddings.json \
  http://localhost:8000/compare

フロントエンド

顔認証用のページ/compareを追加しました。顔検出用のページ(/から/detectに移動しました)と同様、ドラッグ&ドロップ、またはダイアログボックスからの選択で画像をアップロードすることができます。

詳しくはbrowser/app/pages/compare.jsをご覧ください。

結果の表(マトリクス)を生成する処理が少々ややこしい(と言うか醜い)ですが、それ以外はシンプルです。

終わりに

InsightFaceを使うことで、顔検出、顔認証を簡単に行うことができました。

今後は動画の処理に挑戦したいと思っています。

InsightFaceをGPUで動かしてみた』に続く。

Discussion