0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

OpenCV SFace で顔 embedding の近傍検索を試す

0
Last updated at Posted at 2026-07-10

OpenCV SFace で顔 embedding の近傍検索を試す

こんにちは、皆さん。

顔認識というと少し大げさに聞こえますが、技術的には「顔画像を数字のベクトルに変換し、近いものを探す」処理として扱えます。

さて、今日は OpenCV Zoo の SFace を使い、顔画像から embedding を作り、同一人物の別画像を近傍検索で見つけられるかを検証しました。

今回検証する内容

SFace は、顔認識向けのモデルです。顔画像を 128 次元の embedding に変換します。embedding は、画像の特徴を数値の並びで表したものです。近い顔ほど、この数値の並びも近くなることを期待します。

今回は 2 種類の顔画像データセットを使い、次の点を確認します。

  • SFace の ONNX モデルから 128 次元 embedding を生成できるか
  • 同一人物の別画像が、1-nearest-neighbor(いちばん近い画像)として見つかるか
  • 同一人物ペアと別人物ペアで cosine similarity に差が出るか
  • grayscale の小さな顔 crop と、カラーの整列済み顔 crop で結果がどう変わるか

cosine similarity は、2 つのベクトルの向きがどれくらい近いかを表す値です。今回は embedding を L2 normalize(長さを 1 にそろえる処理)してから比較しました。

対象の lab: kiarina/labs/2026/07/10/sface-face-embedding

検証環境の再現

以下のコマンドで、検証環境を構築して手元で実行できます。miseuv が必要です。初回実行時には SFace の ONNX モデル、Olivetti Faces、LFW をダウンロードするため、インターネット接続も必要です。

git clone --depth 1 --filter=blob:none --sparse \
  https://github.com/kiarina/labs.git
cd labs
git sparse-checkout set .gitignore .mise/tasks Makefile mise.toml 2026/07/10/sface-face-embedding
mise -C 2026/07/10/sface-face-embedding run

LFW は展開後に約 395 MB 使用します。Python 環境やモデルも含め、500 MB 程度の空き容量を見ておくと安心です。

使用したモデルとライセンス

使用したモデルは、OpenCV Zoo の face_recognition_sface_2021dec.onnx です。

  • モデル: face_recognition_sface_2021dec.onnx
  • モデル URL: https://media.githubusercontent.com/media/opencv/opencv_zoo/47534e27c9851bb1128ccc0102f1145e27f23f98/models/face_recognition_sface/face_recognition_sface_2021dec.onnx
  • SHA-256: 0ba9fbfa01b5270c96627c4ef784da859931e02f04419c829e83484087c34e79
  • 入力: 112x112 の aligned BGR face crop
  • 出力: 128 次元 embedding
  • ライセンス: Apache-2.0

OpenCV Zoo の SFace ディレクトリでは、同ディレクトリ内のファイルは Apache-2.0 License と明記されています。

使用したデータセット

比較には 2 つのデータセットを使いました。

Olivetti Faces

Olivetti Faces は、40 人 x 10 枚、合計 400 枚の 64x64 grayscale 顔画像です。grayscale は白黒画像のことです。

images: 400
resolution: 64x64 grayscale
people: 40
images per person: 10
dataset SHA-256: b612fb967f2dc77c9c62d3e1266e0c73d5fca46a4b8906c18e454d41af987794

LFW people, funneled color crop

Labeled Faces in the Wild は、実環境に近い顔画像データセットです。今回は sklearn.datasets.fetch_lfw_people で funneled 版を取得し、20 枚以上ある人物のうち固定順で 40 人を選び、各人物の先頭 10 枚だけを使いました。funneled は、顔の向きや位置がある程度そろうように前処理された版です。

selected images: 400
selected resolution: 125x94 RGB
selected people: 40
selected images per person: 10
archive SHA-256: b47c8422c8cded889dc5a13418c4bc2abbda121092b3533a83306f90d900100a

検証方法

各データセットで、40 人 x 10 枚の画像を使いました。各人物の前半 5 枚を参照集合、後半 5 枚を query(検索したい画像)にします。

流れは次のとおりです。

  1. 顔画像を 112x112 にリサイズする
  2. grayscale または RGB 画像を OpenCV 用の BGR にそろえる
  3. cv2.FaceRecognizerSF.feature で embedding を作る
  4. embedding を L2 normalize する
  5. query と参照集合の cosine similarity を計算する
  6. top-1 accuracy と top-5 accuracy を確認する

top-1 accuracy は、いちばん近い画像が同一人物だった割合です。top-5 accuracy は、近い順の 5 件の中に同一人物が含まれた割合です。

本検証では、顔検出や追加の landmark alignment は行っていません。landmark alignment は、目や鼻などの位置を使って顔の向きをそろえる前処理です。今回はデータセットの crop をそのまま 112x112 にリサイズしています。

検証結果

Mac Studio (Apple M4 Max) で実行した結果は以下のとおりです。

Dataset                         | Top-1 | Top-5 | Pos cosine | Neg cosine | sec/image
-------------------------------------------------------------------------------------
Olivetti Faces                  | 0.800 | 0.920 |      0.722 |      0.577 |    0.0057
LFW people, funneled color crop | 0.820 | 0.945 |      0.463 |      0.228 |    0.0058

実行環境は次のとおりです。

machine: Mac Studio (Apple M4 Max)
OS: macOS 26.5.1, arm64
Python: 3.12.10
OpenCV: 5.0.0
NumPy: 2.5.1
SciPy: 1.18.0
scikit-learn: 1.9.0
Pillow: 12.3.0

より細かい結果は lab の output/olivetti_report.jsonoutput/lfw_report.jsonoutput/summary.json に保存されます。

結果の考察

専門的なデータは上に載せたとおりですが、簡単に見ると次のようになります。

  1. SFace embedding で同一人物をある程度近くに集められた
    Olivetti Faces では top-1 accuracy が 80.0%、top-5 accuracy が 92.0% でした。64x64 の小さな白黒顔画像でも、同一人物の画像が近くに集まることは確認できました。

  2. LFW のほうが少し良い結果だった
    LFW の funneled color crop では top-1 accuracy が 82.0%、top-5 accuracy が 94.5% でした。SFace が想定する「カラーで、ある程度整列した顔 crop」に近い条件のほうが、わずかに良い結果になりました。

  3. 同一人物と別人物の距離差は LFW のほうが大きい
    Olivetti Faces では、同一人物ペアの平均 cosine similarity が 0.722、別人物ペアが 0.577 でした。差は 0.145 です。LFW では同一人物ペアが 0.463、別人物ペアが 0.228 で、差は 0.235 でした。絶対値は LFW のほうが低いですが、同一人物と別人物の分離は LFW のほうが明確でした。

  4. 完全な識別には届いていない
    LFW でも 18% の query は、top-1 で別人物を最近傍としていました。今回は学習なしの最近傍検索であり、分類器を学習したわけではありません。また、顔検出や landmark alignment も追加していません。一般的な顔認識性能を示す結果ではなく、この条件での技術検証として見るのがよさそうです。

  5. embedding 生成は軽い
    400 枚の embedding 生成は、どちらのデータセットでも約 2.3 秒でした。1 枚あたり約 0.0058 秒です。今回の規模なら、CPU でもかなり扱いやすい速度でした。

検証後の感想

SFace は、顔画像を「比較しやすい数値」に変換する部品としてかなり使いやすい印象でした。OpenCV の FaceRecognizerSF からそのまま呼べて、ONNX モデルの取得と SHA-256 検証まで lab に入れておけば、再現もしやすいです。

人間も、顔だけではなく、声、喋り方、服装、その場の文脈などを合わせて「この人かも」と思い出しているはずです。そう考えると、今回の結果を顔だけで完全に識別するためのものではなく、参考値のひとつとして利用するのであれば、LLM エージェントへの組み込みも現実的に感じました。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?