Detekcja twarzy stanowi punkt wejścia do większości potoków wizji komputerowej. Każda rozmowa wideo, galeria zdjęć i monitoring bezpieczeństwa zależą od wykrycia ludzkich twarzy, zanim cokolwiek innego może się wydarzyć. Jednak wybór modelu zazwyczaj wymusza niekorzystny kompromis. Ciężkie sieci oferują wysoką dokładność, ale wymagają drogich procesorów GPU i chłodzenia montowanego w szafach rackowych. Mniejsze modele działają na skromnym sprzęcie, ale często zawodzą przy małych twarzach lub obrazach o wysokiej rozdzielczości. Model YuNet z OpenCV Zoo przełamuje ten schemat. Poświęciłem czas na przeprowadzenie benchmarków w różnych skalach, aby sprawdzić, czy zasługuje on na miejsce w rzeczywistych projektach, czy jedynie dobrze wygląda na papierze.

Why YuNet Deserves a Closer Look

YuNet to nie jest jedynie badawcza ciekawostka. Jest częścią OpenCV Zoo – kolekcji wstępnie wytrenowanych modeli zoptymalizowanych pod moduł OpenCV DNN. Testowana przeze mnie wersja wykorzystuje kwantyzację INT8, co oznacza, że jej wagi i aktywacje są kompresowane do 8-bitowych liczb całkowitych zamiast standardowych 32-bitowych liczb zmiennoprzecinkowych. To nie jest tylko mało istotna uwaga techniczna. INT8 drastycznie zmniejsza zapotrzebowanie na przepustowość pamięci, redukuje obciążenie pamięci podręcznej i pozwala nowoczesnym procesorom CPU sprawnie przeprowadzać wnioskowanie (inference) bez większego wysiłku. Dla każdego, kto buduje rozwiązania na laptopie, urządzeniu typu edge lub serwerze bez dedykowanej karty graficznej, ta wydajność stanowi różnicę między płynnym działaniem a pokazem slajdów.

Sama architektura jest z założenia lekka. Rezygnuje z ciężaru ogromnych sieci typu backbone i skupia się na pojedynczym zadaniu, jakim jest lokalizacja twarzy. Ta dyscyplina przynosi owoce, gdy trzeba zintegrować detekcję z większą aplikacją, w której budżet procesora CPU i baterii musi być dzielony z zadaniami takimi jak śledzenie (tracking), rozpoznawanie czy kodowanie wideo.

The Setup

Wszystkie testy przeprowadzono na komputerze Mac Studio z procesorem Apple M4 Max. Plik modelu stanowiła wersja YuNet w formacie ONNX z kwantyzacją INT8, pobrana z repozytorium OpenCV Zoo. Najpierw zmierzyłem prędkość wnioskowania na obrazie 1280x720, a następnie porównałem liczbę wykrytych twarzy przy czterech różnych rozdzielczościach wejściowych, aby zrozumieć, jak skala wpływa na wyniki.

Jeśli chcesz zweryfikować te liczby na własnym sprzęcie, proces jest w pełni powtarzalny. Uruchom poniższe polecenia, aby pobrać repozytorium typu sparse i wykonać 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

Sparse checkout sprawia, że pobieranie jest szybkie i zajmuje mało miejsca, a task runner mise zarządza zależnościami w tle. Nie musisz walczyć ze środowiskami Python ani ręcznie instalować pakietów.

Speed That Stays Consistent

Na obrazie 1280x720 model YuNet INT8 osiągał średnio 9,21 milisekundy na jedno wnioskowanie. Najszybszy przebieg wyniósł 8,03 ms, podczas gdy najwolniejszy osiągnął 10,47 ms. To niezwykle wąski zakres. Między najlepszym a najgorszym wynikiem różnica wynosi mniej niż dwie i pół milisekundy.

W praktyce ta spójność jest ważniejsza niż chwalenie się wynikami. Aplikacje czasu rzeczywistego nie potrzebują jedynie niskiego średniego opóźnienia; potrzebują przewidywalnego opóźnienia. Model, który czasem potrzebuje 50 ms, powoduje widoczne szarpanie obrazu w transmisji z kamerki internetowej. YuNet utrzymuje stały poziom. Możesz na nim polegać, wiedząc, że przetworzy klatkę, zanim nadejdzie kolejna, co znacznie ułatwia planowanie reszty potoku przetwarzania.

Scale Variance Reveals the Real Story

Czysta prędkość niewiele znaczy, jeśli model pomija połowę twarzy w scenie. Aby to sprawdzić, przepuściłem te same obrazy źródłowe przez YuNet w czterech różnych rozdzielczościach. Wyniki mówią same za siebie:

  • 320 x 180: 6 twarzy wykrytych
  • 640 x 360: 26 twarzy wykrytych
  • 1280 x 720: 38 twarzy wykrytych
  • 2560 x 1440: 52 twarzy wykrytych

Skok jest dramatyczny. Przy 320 x 180 rejestrowane są tylko największe, najbliższe twarze. Zwiększ rozdzielczość do 640 x 360, a liczba ta wzrośnie czterokrotnie. Przy pełnym 1440p YuNet znajduje ponad ośmiokrotnie więcej twarzy niż przy najniższej rozdzielczości.

Dzieje się tak, ponieważ downsampling niszczy szczegóły szybciej, niż podpowiada intuicja. Twarz zajmująca niewielki obszar w klatce 1440p może skurczyć się do plamy o wymiarach pięciu na pięć pikseli przy 360p. Gdy cechy twarzy spadną poniżej pola recepcyjnego modelu, stają się niewidocznym szumem. Oczy zlewają się z brwiami. Nosy znikają. YuNet nie ma się czego „chwycić”.

Warto zapamiętać praktyczny wniosek. Jeśli Twoja kamera rejestruje szerokokątny widok sali lekcyjnej, sali konferencyjnej lub rogu ulicy, odległe twarze nie pojawią się, chyba że zapewnisz modelowi wystarczającą liczbę pikseli. Rozdzielczość nie dotyczy tu tylko jakości obrazu. Jest ona bezpośrednim narzędziem wpływającym na czułość (recall).

The Resize Strategy You Actually Need

YuNet is fast enough that you do not need to hammer your input down to 320 x 240 out of habit. On the M4 Max, even 2560 x 1440 runs without a dedicated GPU. That changes how you should architect a pipeline.

Instead of forcing every frame through a tiny fixed size, choose your input resolution based on what you are trying to find. If you only care about the person directly in front of the camera, 720p or even 640p is plenty. If you need to catalog every attendee in a large hall, feed the model a higher-resolution crop or the full native frame. Because YuNet is lightweight, you have headroom to make that choice. You are not locked into a single preset to avoid a 200 ms lag.

One caveat does remain. The model still depends on face size relative to the input tensor. There is no magic scale invariance here. Small faces stay invisible unless they occupy enough pixels. The fix is mechanical: resize your source image upward before inference when hunting for distant subjects, then map the resulting bounding boxes back to original coordinates. YuNet gives you the speed budget to afford that step.

Where This Fits in Your Stack

YuNet is not a solution for every conceivable face task. Heavy occlusion, extreme profile angles, or 3D mesh extraction are outside its scope. But for the bread-and-butter work of locating faces in photos and video streams, it occupies a sweet spot. Real-time webcam apps, automated photo culling tools, and modest embedded systems all benefit from a detector that runs fast on standard CPUs.

The INT8 ONNX format also makes deployment painless. You do not need to install PyTorch or TensorFlow on the target device. OpenCV's DNN module loads the model directly, which keeps your binary small and your dependency tree shallow.

The Bottom Line

YuNet proves that face detection does not require industrial hardware or bloated frameworks. The numbers speak plainly: under ten milliseconds for a 720p frame, and a direct, predictable boost in detection count as resolution rises. You get to choose whether you want maximum speed at moderate resolution or broader coverage at higher scale, and the model will not punish you for that choice.

If you are building anything that touches real-world imagery, run the reproduction steps above on your own hardware. Test it against your footage. Then tune your resize logic to match the faces you actually need to find. Speed is useful only when you can aim it. YuNet gives you both the velocity and the control.