【実測】Cortex-A76(Raspberry Pi 5)でOpenCVの顔検出はどこまで動くか

なりすまし判定・ライブネス検知
📌 準備: OpenCV の環境構築がまだの方はこちら → C++ 環境構築ガイドC#(OpenCvSharp)セットアップ

【実測】Cortex-A76(Raspberry Pi 5)でOpenCVの顔検出はどこまで動くか

顔認証を「クラウドに送らず端末内で完結させたい」現場では、前回論じたとおり CPU 推論で実用速度が出るかが導入の分かれ目になります。では、GPU のない低スペックCPUで OpenCV の顔検出・顔照合は実際どこまで動くのか。本記事では Cortex-A76(Raspberry Pi 5 搭載) で実測します。

Cortex-A76 を選んだ理由は、①エッジ・組込で広く使われる汎用 Arm コア ②Raspberry Pi 5(BCM2712・Cortex-A76 ×4)で安価に再現できる ③Raspberry Pi OS / Arm64 は当社なりすまし判定SDKの正式対応環境——の3点です。

結論を先に書くと、640×480 なら検出+照合で 74 ms(13.5 fps)、1280×720 のまま検出すると 204 ms(4.9 fps)。用途を選べば十分に実用域です。


1. 計測環境

項目 内容
CPU Arm Cortex-A76 ×4(Raspberry Pi 5 / BCM2712・最大 2.4GHz)
メモリ 8 GB
ストレージ microSD
OS Raspberry Pi OS Bookworm 64bit(Debian 12 / kernel 6.6.62)
OpenCV 4.10.0(core,imgproc,dnn,objdetect,imgcodecs,videoio・NEON / FP16 / DOTPROD 有効)
モデル YuNet(face_detection_yunet 系 ONNX)/ SFace(face_recognition_sface 系 ONNX)
入力 同一の実写画像を 640×480 と 1280×720 にリサイズ
計測 各 100 回の median(min / mean / max も取得)

計測にあたって条件を2つ固定しています。

  • CPU ガバナを performance に固定。Raspberry Pi OS の既定は ondemand で、そのまま測ると 1.6〜1.9GHz で走ってしまい、公称 2.4GHz の実力より遅い数字が出ます。
  • vcgencmd get_throttled を計測の前後で確認し、全区間で 0x0(電圧・温度による絞りが一度も発生していない)であることを確認しています。最高温度は 61.5℃ でした。

この2つを書かないベンチマークは、熱で目減りした数字なのかどうかが読み手に判断できません。


2. 計測コード

OpenCV の公開 API だけを使っています。

#include <opencv2/opencv.hpp>
#include <opencv2/objdetect/face.hpp>
#include <chrono>
#include <iostream>

int main()
{
    const std::string yunetPath = "face_detection_yunet_2023mar.onnx";
    const std::string sfacePath = "face_recognition_sface_2021dec.onnx";

    cv::Mat img = cv::imread("input.jpg");
    if (img.empty()) { std::cerr << "画像が読めません\n"; return 1; }

    // 検出器・照合器の生成(入力サイズは detect 前に合わせておく)
    auto detector   = cv::FaceDetectorYN::create(yunetPath, "", img.size(), 0.9f, 0.3f, 5000);
    auto recognizer = cv::FaceRecognizerSF::create(sfacePath, "");

    // ① YuNet 顔検出
    cv::Mat faces;
    const auto t0 = std::chrono::steady_clock::now();
    detector->detect(img, faces);
    const auto t1 = std::chrono::steady_clock::now();
    std::cout << "detect : "
              << std::chrono::duration<double, std::milli>(t1 - t0).count() << " ms\n";
    if (faces.rows == 0) { std::cout << "顔が検出できませんでした\n"; return 0; }

    // ② SFace 特徴抽出(alignCrop → feature)
    cv::Mat aligned, feature;
    const auto t2 = std::chrono::steady_clock::now();
    recognizer->alignCrop(img, faces.row(0), aligned);
    recognizer->feature(aligned, feature);
    feature = feature.clone();   // ★ feature() の戻りは内部バッファの参照。clone 必須
    const auto t3 = std::chrono::steady_clock::now();
    std::cout << "feature: "
              << std::chrono::duration<double, std::milli>(t3 - t2).count() << " ms\n";

    // ③ 1:1 照合(同じ特徴量どうしなので 1.0 に近い値が返る)
    const double score =
        recognizer->match(feature, feature, cv::FaceRecognizerSF::DisType::FR_COSINE);
    std::cout << "cosine : " << score << "\n";

    return 0;
}

feature() の戻り値を clone() せずに保持すると、次の feature() 呼び出しで内容が上書きされます。1:N 照合で特徴量を配列に貯める実装では必ず踏むので注意してください。

YuNet と SFace の使い方そのものはこちらの記事で詳しく扱っています。


3. 実測結果 — Cortex-A76(4コア)

処理 640×480 1280×720
① YuNet 顔検出 50.79 ms 179.25 ms
② SFace 特徴抽出(alignCrop + feature) 23.44 ms 24.28 ms
③ SFace 照合(1:1 match) 0.00 ms 0.00 ms
検出+照合の合計 74.23 ms(13.5 fps) 203.54 ms(4.9 fps)
ピークメモリ(RSS) 約 163 MB 約 163 MB

数値は 100 回の median。

ここから読み取れることが3つあります。

① 支配的なのは顔検出。しかも入力解像度に強く依存する。
YuNet は画像全体を走査するので、640×480 → 1280×720(画素数 3.0 倍)で処理時間が 50.79 ms → 179.25 ms と 3.5 倍になります。ほぼ画素数に比例します。

② SFace は解像度に依存しない。
23.44 ms → 24.28 ms とほぼ変わりません。alignCrop が顔を 112×112 に正規化してから推論するため、入力画像がどれだけ大きくても特徴抽出のコストは一定です。

③ 1:1 照合は事実上ゼロコスト。
match() は 128次元 float の距離計算なので、median は 0.00 ms(最大でも 0.03 ms)。1:N 照合でも N が数千程度なら、検出時間に比べれば誤差です。 「照合が重いのでは」という心配は、少なくとも SFace では当たりません。

設計上の要点は「検出をどの解像度で回すか」に集約されます。


4. 1コアに絞るとどうなるか

組込機器では、SDK に割り当てられるコアが1つだけということも珍しくありません。taskset -c 0 で1コアに固定した場合:

処理 640×480 1280×720
① YuNet 顔検出 67.74 ms 219.70 ms
② SFace 特徴抽出 58.04 ms 58.75 ms
合計 125.78 ms(8.0 fps) 278.45 ms(3.6 fps)

4コアとの比を取ると、YuNet は 1.33 倍しか速くならないのに対し、SFace は 2.48 倍速くなっています。同じ OpenCV DNN でも、モデルによって並列化の効き方がここまで違います。

コア数を増やしても、支配項である顔検出はあまり速くならない——これが低スペック環境での一番効く事実です。マルチコア化よりも、入力解像度を下げるか、検出頻度を落とすかのほうが効きます。


5. x86_64 との比較

同じ OpenCV ビルド・同じモデル・同じ画像で、デスクトップ CPU(Core i7-13700K / 16コア24スレッド / Ubuntu 22.04)でも測りました。

処理 A76 4コア A76 1コア i7-13700K 全コア i7-13700K 1コア
YuNet 顔検出(640×480) 50.79 ms 67.74 ms 3.29 ms 8.76 ms
YuNet 顔検出(1280×720) 179.25 ms 219.70 ms 10.96 ms 30.12 ms
SFace 特徴抽出 23.44 ms 58.04 ms 4.16 ms 13.34 ms
合計(640×480) 74.23 ms 125.78 ms 7.44 ms 22.10 ms
ピークメモリ 163 MB 165 MB 163 MB

1コアどうしで比べると A76 は i7-13700K の約 5.7〜6.4 倍の時間がかかります。デスクトップ級の CPU が相手なので当然ではありますが、倍率が「一桁未満」に収まっている点は押さえておく価値があります。GPU 必須のモデルなら「動かない」ですが、CPU 向けの軽量モデルは遅くなるだけで動くということです。

そしてもう1つ、メモリはどの CPU でも約 163 MB でほぼ同じでした。処理時間は機種で大きく変わりますが、メモリ要件は機種にほとんど依らないので、組込機器の選定では先にメモリの当たりを付けられます。


6. なりすまし判定を足すとどうなるか

ここまでは OpenCV 標準の顔検出・顔照合です。実運用では印刷写真やディスプレイ再生による突破を防ぐため、なりすまし判定(ライブネス検知)を挟むことになります。

参考値として、当社のなりすまし判定SDK(単一フレーム・CPU 推論・GPU 不要)を同じ Raspberry Pi 5 で測った結果は次のとおりです。

項目 Cortex-A76 4コア Cortex-A76 1コア
1フレームあたりの処理時間(1280×720 の実写画像) 約 105〜115 ms 約 185〜200 ms
初期化(モデル読込を含む) 約 80 ms
常駐メモリ(ピーク) 約 300 MB 約 300 MB

自社計測値です。入力画像・顔の写り方・搭載機能の構成によって変動します。同じ構成でも実行ごとに 3〜10% 程度のばらつきがあったため、単一の値ではなくレンジで記載しています。

初期化 80 ms は microSD 起動の Raspberry Pi 5 での値で、常駐プロセスなら起動時の1回だけです。毎フレームのコストではありません。


7. 用途別の現実解

実測値から、用途ごとの成立可否を整理します。

用途 必要な速度 Cortex-A76 での判定
入退室・打刻(1〜2秒以内に1回判定) 数百 ms/回 余裕がある。640×480 なら検出+照合 74 ms、なりすまし判定を足しても 200 ms 前後
本人確認フロー(撮影 → 判定 → 結果表示) 1秒以内 成立する。ユーザーが静止している前提なので高フレームレートは不要
常時プレビューでの追従(15〜30 fps) 33〜66 ms/frame ⚠️ そのままでは足りない(640×480 で 13.5 fps)。検出を数フレームに1回に間引き、間はトラッキングで補う設計が要る
1280×720 のまま毎フレーム検出 4.9 fps で非現実的。検出は縮小画像で行い、照合だけ元解像度の顔領域から取るのが定石

つまり 「顔認証をリアルタイム動画として処理する」のは低スペックCPUでは厳しいが、「1回の認証イベントを1秒以内に返す」のは十分に成立する、というのが実測から出る線引きです。そして実際の入退室・本人確認の要件はほぼ後者です。

メモリ制約については、OpenCV の顔検出+照合だけなら 約 163 MB、なりすまし判定まで含めて 約 300 MB。512MB クラスの機器では厳しく、1GB 以上あれば現実的という目安になります。


8. まとめ

  • Cortex-A76(Raspberry Pi 5)で、OpenCV の YuNet 顔検出 + SFace 照合は 640×480 で 74 ms(13.5 fps)。1280×720 では 204 ms(4.9 fps)
  • ボトルネックは常に顔検出。SFace の特徴抽出は解像度非依存、1:1 照合は事実上ゼロコスト
  • コア数を増やしても検出はあまり速くならない(1コア→4コアで 1.33 倍)。効くのは入力解像度と検出頻度
  • 1コアどうしの比較で A76 はデスクトップ Core i7 の約 6 倍の時間。「動かない」のではなく「遅くなるだけ」
  • メモリは機種にほぼ依らず、OpenCV 単体で約 163 MB / なりすまし判定込みで約 300 MB
  • 入退室・本人確認といったイベント単位の認証なら低スペックCPUで十分成立する

GPU 前提のモデルが組込で詰まるのに対し、軽量 CPU モデルは現実的なエッジの選択肢です。数字を持っておけば、機器選定の議論が「動くのか動かないのか」から「どの解像度で何 fps 必要か」に進みます。

🛡 エッジ・組込で動くなりすまし判定をお探しの方へ

本ブログを運営するスワローインキュベートのなりすまし判定SDKは、Raspberry Pi OS(Arm64)を含む CPU 環境で動作します(単一フレーム・オフライン)。エッジ端末での顔認証+なりすまし対策をご検討の方はご相談ください。

→ なりすまし判定SDK/APIの詳細を見る

タイトルとURLをコピーしました