Face detection sits at the entry gate of most computer vision pipelines. Every video call, photo gallery, and security feed depends on spotting human faces before anything else can happen. Yet the choice of model usually forces an unhappy trade-off. Heavy networks offer accuracy but demand expensive GPUs and rack-mounted cooling. Smaller models run on modest hardware yet often choke on small faces or high-resolution feeds. The YuNet model from the OpenCV Zoo breaks that pattern. I spent time benchmarking it across different scales to see whether it earns a place in real projects or merely looks good on paper.
Why YuNet Deserves a Closer Look
YuNet is not a research curiosity. It lives inside the OpenCV Zoo, a collection of pre-trained models optimized for the OpenCV DNN module. The specific variant I tested uses INT8 quantization, which means its weights and activations compress down to 8-bit integers instead of the usual 32-bit floating-point numbers. That is not a minor technical footnote. INT8 slashes memory bandwidth, reduces cache pressure, and allows modern CPUs to chew through inference without breaking a sweat. For anyone building on a laptop, an edge device, or a server without a dedicated graphics card, this efficiency is the difference between a smooth pipeline and a slideshow.
The architecture itself is lightweight by design. It skips the baggage of enormous backbones and focuses on the single task of locating faces. That discipline pays off when you need to integrate detection into a larger application where CPU and battery budget are shared with tracking, recognition, or video encoding.
The Setup
All tests ran on a Mac Studio with an Apple M4 Max chip. The model file was the YuNet INT8 quantized ONNX build from the OpenCV Zoo repository. I measured inference speed on a 1280x720 image first, then compared detection counts across four different input resolutions to understand how scale affects results.
If you want to verify these numbers on your own machine, the process is fully reproducible. Run the following commands to pull the sparse repository and execute the benchmark:
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/08/yunet-face-detection
mise -C 2026/07/08/yunet-face-detection run
The sparse checkout keeps the download small, and the mise task runner handles dependencies behind the scenes. You do not need to wrestle with Python environments or manual package installations.
Speed That Stays Consistent
On a 1280x720 image, the INT8 YuNet model averaged 9.21 milliseconds per inference. The quickest pass clocked in at 8.03 ms, while the slowest touched 10.47 ms. That is a remarkably tight band. Less than two and a half milliseconds separate the best and worst times.
In practice, this consistency matters more than bragging rights. Real-time applications do not just need low average latency; they need predictable latency. A model that sometimes takes 50 ms creates visible stutter in a webcam feed. YuNet stays flat. You can rely on it to finish a frame before the next one arrives, which makes scheduling the rest of your pipeline far simpler.
Scale Variance Reveals the Real Story
Raw speed means little if the model misses half the faces in a scene. To test this, I fed the same source imagery through YuNet at four different resolutions. The counts tell a clear story:
- 320 x 180: 6 faces detected
- 640 x 360: 26 faces detected
- 1280 x 720: 38 faces detected
- 2560 x 1440: 52 faces detected
The jump is dramatic. At 320 x 180, only the largest, closest faces register. Bump up to 640 x 360, and the count quadruples. At full 1440p, YuNet finds more than eight times as many faces as it did at the lowest resolution.
This happens because downsampling destroys detail faster than intuition suggests. A face that covers a modest patch in a 1440p frame can shrink to a smudge of five by five pixels at 360p. Once facial features collapse below the model's receptive field, they become invisible noise. Eyes merge into eyebrows. Noses disappear. YuNet has nothing to grab onto.
The practical upshot is worth remembering. If your camera captures a wide-angle view of a classroom, a conference room, or a street corner, distant faces will not appear unless you give the model enough pixels. Resolution is not just about image quality here. It is a direct lever on recall.
The Resize Strategy You Actually Need
YuNetは十分に高速であるため、習慣的に入力を320 x 240まで無理に縮小する必要はありません。M4 Maxでは、専用のGPUがなくても2560 x 1440で動作します。これにより、パイプラインの設計方法が変わります。
すべてのフレームを小さな固定サイズに押し込めるのではなく、検出したい対象に基づいて入力解像度を選択してください。カメラの真正面にいる人物だけを対象とするなら、720pや640pで十分です。広いホールにいるすべての出席者をカタログ化する必要がある場合は、高解像度のクロップ画像やネイティブフレーム全体をモデルに供給してください。YuNetは軽量であるため、そうした選択をするための余裕があります。200ミリ秒の遅延を避けるために、単一のプリセットに縛られる必要はありません。
ただし、一つ注意点があります。モデルは依然として入力テンソルに対する顔のサイズに依存します。魔法のようなスケール不変性(scale invariance)はありません。小さな顔は、十分なピクセルを占有しない限り、検出されません。解決策は機械的なものです。遠くの被写体を探索する場合は、推論前にソース画像を拡大リサイズし、得られたバウンディングボックスを元の座標にマッピングします。YuNetなら、その工程を組み込むための速度的な余裕があります。
スタックにおける位置付け
YuNetは、考えうるすべての顔関連タスクに対する解決策ではありません。激しい遮蔽(オクルージョン)、極端な横顔の角度、あるいは3Dメッシュの抽出などは、その対象外です。しかし、写真やビデオストリームから顔の位置を特定するという主要な業務においては、非常に適したポジションを占めています。リアルタイムのウェブカメラアプリ、自動写真選別ツール、そして控えめな組み込みシステムなどは、標準的なCPU上で高速に動作する検出器の恩恵をすべて受けることができます。
INT8 ONNX形式により、デプロイも簡単です。ターゲットデバイスにPyTorchやTensorFlowをインストールする必要はありません。OpenCVのDNNモジュールがモデルを直接ロードするため、バイナリサイズを小さく抑え、依存関係を最小限に保つことができます。
結論
YuNetは、顔検出に産業用ハードウェアや肥大化したフレームワークは必要ないことを証明しています。数値は明白です。720pのフレームで10ミリ秒未満、解像度が上がるにつれて検出数は直接的かつ予測可能な形で増加します。中程度の解像度で最大限の速度を求めるか、より高いスケールでより広い範囲をカバーするかを選択でき、その選択によってモデルのパフォーマンスが損なわれることはありません。
実世界の画像を取り扱うものを作成している場合は、上記の再現手順をご自身のハードウェアで実行してください。実際の映像でテストしてください。そして、実際に検出する必要がある顔に合わせて、リサイズロジックを調整してください。速度は、それを制御できて初めて役に立ちます。YuNetは、その速度と制御力の両方を提供します。
