Face detection with YuNet and face recognition with SFace. Both models are built into OpenCV (cv2.FaceDetectorYN / cv2.FaceRecognizerSF). Faces are matched by the cosine similarity of their 128-d embeddings.
Armstrong and Aldrin were enrolled from one portrait each, then recognized in a different photo (cosine similarity 0.75 and 0.72). Collins was never enrolled, so he scores 0.22 and is labelled Unknown. Photos: NASA, public domain.
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python main.py download-models # fetches the two ONNX models into models/From photos: put one folder per person in dataset/, then run enroll:
dataset/
Alice/ 1.jpg 2.jpg 3.jpg
Bob/ a.png b.png
python main.py enroll --folder datasetRe-running this rebuilds each person found in the folder. Use 3–10 clear photos per person with varied angles and lighting. If a photo contains several faces, the largest one is used.
Each photo is quality-checked (face at least 60 px, a confident detection, not blurry). Weak photos are skipped with a reason. Every accepted face is stored twice, as-is and mirrored, to cover more head poses. Use --no-mirror to turn that off.
From the webcam:
python main.py enroll --webcam --name Alice --samples 20A sample is captured every 0.3 s while exactly one clear face is visible. The window shows why it's waiting ("move closer", "too blurry"). Padded crops are also saved to dataset/Alice/, so you can rebuild later with enroll --folder. Press q to stop early.
Manage the database (data/embeddings.npz):
python main.py list
python main.py remove --name Alicepython main.py recognize --webcam # q to quit
python main.py recognize --image photo.jpg [--output out.jpg]
python main.py recognize --video clip.mp4 [--output out.mp4]Options:
--threshold 0.363: the minimum cosine similarity for a match. Raise it (e.g. 0.45) if strangers get matched, or lower it if known people come out as "Unknown".--no-display: don't open a window (useful with--output).--camera N: pick a different webcam.--detect-width 640: frames are downscaled to this width for face detection only; recognition still uses the full-resolution face. Use0for full size, or raise it if faces far from the camera are missed.--reembed-every 10: faces are tracked between frames and re-recognized every N frames. Names are also smoothed over the last 5 results so they don't flicker. Use1to recognize on every frame.
python main.py benchmark [--image face.jpg] times each stage on a 1280×720 frame. On an 8-thread Mac with one face:
| Stage | Before | After |
|---|---|---|
| Face detection | 34 ms (full size) | 11 ms (640 wide) |
| Full pipeline per frame | 52 ms (19 FPS) | 12 ms (86 FPS) |
A live webcam is capped at the camera's frame rate (usually 30 FPS). The camera is read on a background thread, so the newest frame is always processed with no buffered lag.
pip install -r requirements-dev.txt
pytest -qThe first run downloads two sample images from the OpenCV repo into tests/.cache/.
- Camera permission: the first webcam run asks for camera access for your terminal app. If it was denied, enable it in System Settings → Privacy & Security → Camera and restart the terminal.
- Video formats: the pip OpenCV wheels on macOS use AVFoundation, not FFmpeg. Reading
.mp4/.mov(H.264/HEVC) works. Some.avicodecs (such as XVID) can't be read, so convert those first (e.g.ffmpeg -i in.avi out.mp4). Output files use H.264 for.mp4and MJPG for.avi.
main.py CLI
facerec/models.py model download
facerec/engine.py FaceEngine: detect / embed / match
facerec/database.py embeddings database
facerec/enroll.py folder + webcam enrollment
facerec/recognize.py image / video / webcam recognition (threaded webcam capture)
facerec/tracker.py IoU face tracking + label smoothing
facerec/benchmark.py stage timings
facerec/draw.py overlay drawing
tests/ pytest suite
