UniFace: A Comprehensive Library for Face Detection, Recognition, Landmark Analysis, Face Parsing, Gaze Estimation, Age, and Gender Detection
Project description
UniFace: All-in-One Face Analysis Library
UniFace is a lightweight, production-ready face analysis library built on ONNX Runtime. It provides high-performance face detection, recognition, landmark detection, face parsing, gaze estimation, and attribute analysis with hardware acceleration support across platforms.
Features
- High-Speed Face Detection: ONNX-optimized RetinaFace, SCRFD, and YOLOv5-Face models
- Facial Landmark Detection: Accurate 106-point landmark localization
- Face Recognition: ArcFace, MobileFace, and SphereFace embeddings
- Face Parsing: BiSeNet-based semantic segmentation with 19 facial component classes
- Gaze Estimation: Real-time gaze direction prediction with MobileGaze
- Attribute Analysis: Age, gender, and emotion detection
- Face Alignment: Precise alignment for downstream tasks
- Hardware Acceleration: ARM64 optimizations (Apple Silicon), CUDA (NVIDIA), CPU fallback
- Simple API: Intuitive factory functions and clean interfaces
- Production-Ready: Type hints, comprehensive logging, PEP8 compliant
Installation
Quick Install (All Platforms)
pip install uniface
Platform-Specific Installation
macOS (Apple Silicon - M1/M2/M3/M4)
For Apple Silicon Macs, the standard installation automatically includes optimized ARM64 support:
pip install uniface
The base onnxruntime package (included with uniface) has native Apple Silicon support with ARM64 optimizations built-in since version 1.13+.
Linux/Windows with NVIDIA GPU
For CUDA acceleration on NVIDIA GPUs:
pip install uniface[gpu]
Requirements:
- CUDA 11.x or 12.x
- cuDNN 8.x
- See ONNX Runtime GPU requirements
CPU-Only (All Platforms)
pip install uniface
Install from Source
git clone https://github.com/yakhyo/uniface.git
cd uniface
pip install -e .
Quick Start
Face Detection
import cv2
from uniface import RetinaFace
# Initialize detector
detector = RetinaFace()
# Load image
image = cv2.imread("image.jpg")
# Detect faces
faces = detector.detect(image)
# Process results
for face in faces:
bbox = face['bbox'] # [x1, y1, x2, y2]
confidence = face['confidence']
landmarks = face['landmarks'] # 5-point landmarks
print(f"Face detected with confidence: {confidence:.2f}")
Face Recognition
from uniface import ArcFace, RetinaFace
from uniface import compute_similarity
# Initialize models
detector = RetinaFace()
recognizer = ArcFace()
# Detect and extract embeddings
faces1 = detector.detect(image1)
faces2 = detector.detect(image2)
embedding1 = recognizer.get_normalized_embedding(image1, faces1[0]['landmarks'])
embedding2 = recognizer.get_normalized_embedding(image2, faces2[0]['landmarks'])
# Compare faces
similarity = compute_similarity(embedding1, embedding2)
print(f"Similarity: {similarity:.4f}")
Facial Landmarks
from uniface import RetinaFace, Landmark106
detector = RetinaFace()
landmarker = Landmark106()
faces = detector.detect(image)
landmarks = landmarker.get_landmarks(image, faces[0]['bbox'])
# Returns 106 (x, y) landmark points
Age & Gender Detection
from uniface import RetinaFace, AgeGender
detector = RetinaFace()
age_gender = AgeGender()
faces = detector.detect(image)
gender, age = age_gender.predict(image, faces[0]['bbox'])
gender_str = 'Female' if gender == 0 else 'Male'
print(f"{gender_str}, {age} years old")
Gaze Estimation
from uniface import RetinaFace, MobileGaze
from uniface.visualization import draw_gaze
import numpy as np
detector = RetinaFace()
gaze_estimator = MobileGaze()
faces = detector.detect(image)
for face in faces:
bbox = face['bbox']
x1, y1, x2, y2 = map(int, bbox[:4])
face_crop = image[y1:y2, x1:x2]
pitch, yaw = gaze_estimator.estimate(face_crop)
print(f"Gaze: pitch={np.degrees(pitch):.1f}°, yaw={np.degrees(yaw):.1f}°")
# Visualize
draw_gaze(image, bbox, pitch, yaw)
Face Parsing
from uniface.parsing import BiSeNet
from uniface.visualization import vis_parsing_maps
# Initialize parser
parser = BiSeNet() # Uses ResNet18 by default
# Parse face image (already cropped)
mask = parser.parse(face_image)
# Visualize with overlay
import cv2
face_rgb = cv2.cvtColor(face_image, cv2.COLOR_BGR2RGB)
vis_result = vis_parsing_maps(face_rgb, mask, save_image=False)
# mask contains 19 classes: skin, eyes, nose, mouth, hair, etc.
print(f"Unique classes: {len(np.unique(mask))}")
Documentation
- QUICKSTART.md - 5-minute getting started guide
- MODELS.md - Model zoo, benchmarks, and selection guide
- Examples - Jupyter notebooks with detailed examples
API Overview
Factory Functions (Recommended)
from uniface.detection import RetinaFace, SCRFD
from uniface.recognition import ArcFace
from uniface.landmark import Landmark106
from uniface.constants import SCRFDWeights
# Create detector with default settings
detector = RetinaFace()
# Create with custom config
detector = SCRFD(
model_name=SCRFDWeights.SCRFD_10G_KPS, # SCRFDWeights.SCRFD_500M_KPS
conf_thresh=0.4,
input_size=(640, 640)
)
# Or with defaults settings: detector = SCRFD()
# Recognition and landmarks
recognizer = ArcFace()
landmarker = Landmark106()
Direct Model Instantiation
from uniface import RetinaFace, SCRFD, YOLOv5Face, ArcFace, MobileFace, SphereFace
from uniface.constants import RetinaFaceWeights, YOLOv5FaceWeights
# Detection
detector = RetinaFace(
model_name=RetinaFaceWeights.MNET_V2,
conf_thresh=0.5,
nms_thresh=0.4
)
# Or detector = RetinaFace()
# YOLOv5-Face detection
detector = YOLOv5Face(
model_name=YOLOv5FaceWeights.YOLOV5S,
conf_thresh=0.6,
nms_thresh=0.5
)
# Or detector = YOLOv5Face
# Recognition
recognizer = ArcFace() # Uses default weights
recognizer = MobileFace() # Lightweight alternative
recognizer = SphereFace() # Angular softmax alternative
High-Level Detection API
from uniface import detect_faces
# One-line face detection
faces = detect_faces(image, method='retinaface', conf_thresh=0.8) # methods: retinaface, scrfd, yolov5face
Key Parameters (quick reference)
Detection
| Class | Key params (defaults) | Notes |
|---|---|---|
RetinaFace |
model_name=RetinaFaceWeights.MNET_V2, conf_thresh=0.5, nms_thresh=0.4, input_size=(640, 640), dynamic_size=False |
Supports 5-point landmarks |
SCRFD |
model_name=SCRFDWeights.SCRFD_10G_KPS, conf_thresh=0.5, nms_thresh=0.4, input_size=(640, 640) |
Supports 5-point landmarks |
YOLOv5Face |
model_name=YOLOv5FaceWeights.YOLOV5S, conf_thresh=0.6, nms_thresh=0.5, input_size=640 (fixed) |
Supports 5-point landmarks; models: YOLOV5N/S/M; input_size must be 640 |
Recognition
| Class | Key params (defaults) | Notes |
|---|---|---|
ArcFace |
model_name=ArcFaceWeights.MNET |
Returns 512-dim normalized embeddings |
MobileFace |
model_name=MobileFaceWeights.MNET_V2 |
Lightweight embeddings |
SphereFace |
model_name=SphereFaceWeights.SPHERE20 |
Angular softmax variant |
Landmark & Attributes
| Class | Key params (defaults) | Notes |
|---|---|---|
Landmark106 |
No required params | 106-point landmarks |
AgeGender |
model_name=AgeGenderWeights.DEFAULT; input_size auto-detected |
Requires bbox; ONNXRuntime |
Emotion |
model_weights=DDAMFNWeights.AFFECNET7, input_size=(112, 112) |
Requires 5-point landmarks; TorchScript |
Gaze Estimation
| Class | Key params (defaults) | Notes |
|---|---|---|
MobileGaze |
model_name=GazeWeights.RESNET34 |
Returns (pitch, yaw) angles in radians; trained on Gaze360 |
Face Parsing
| Class | Key params (defaults) | Notes |
|---|---|---|
BiSeNet |
model_name=ParsingWeights.RESNET18, input_size=(512, 512) |
19 facial component classes; BiSeNet architecture with ResNet backbone |
Model Performance
Face Detection (WIDER FACE Dataset)
| Model | Easy | Medium | Hard | Use Case |
|---|---|---|---|---|
| retinaface_mnet025 | 88.48% | 87.02% | 80.61% | Mobile/Edge devices |
| retinaface_mnet_v2 | 91.70% | 91.03% | 86.60% | Balanced (recommended) |
| retinaface_r34 | 94.16% | 93.12% | 88.90% | High accuracy |
| scrfd_500m | 90.57% | 88.12% | 68.51% | Real-time applications |
| scrfd_10g | 95.16% | 93.87% | 83.05% | Best accuracy/speed |
| yolov5n_face | 93.61% | 91.52% | 80.53% | Lightweight/Mobile |
| yolov5s_face | 94.33% | 92.61% | 83.15% | Real-time + accuracy |
| yolov5m_face | 95.30% | 93.76% | 85.28% | High accuracy |
Accuracy values from original papers: RetinaFace, SCRFD, YOLOv5-Face
Benchmark on your hardware:
python scripts/run_detection.py --image assets/test.jpg --iterations 100
See MODELS.md for detailed model information and selection guide.
Examples
Jupyter Notebooks
Interactive examples covering common face analysis tasks:
| Example | Description | Notebook |
|---|---|---|
| Face Detection | Detect faces and facial landmarks | face_detection.ipynb |
| Face Alignment | Align and crop faces for recognition | face_alignment.ipynb |
| Face Recognition | Extract face embeddings and compare faces | face_analyzer.ipynb |
| Face Verification | Compare two faces to verify identity | face_verification.ipynb |
| Face Search | Find a person in a group photo | face_search.ipynb |
| Face Parsing | Segment face into semantic components | face_parsing.ipynb |
| Gaze Estimation | Estimate gaze direction from face images | gaze_estimation.ipynb |
Webcam Face Detection
import cv2
from uniface import RetinaFace
from uniface.visualization import draw_detections
detector = RetinaFace()
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
faces = detector.detect(frame)
# Extract data for visualization
bboxes = [f['bbox'] for f in faces]
scores = [f['confidence'] for f in faces]
landmarks = [f['landmarks'] for f in faces]
draw_detections(
image=frame,
bboxes=bboxes,
scores=scores,
landmarks=landmarks,
vis_threshold=0.6,
)
cv2.imshow("Face Detection", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Face Search System
import numpy as np
from uniface import RetinaFace, ArcFace
detector = RetinaFace()
recognizer = ArcFace()
# Build face database
database = {}
for person_id, image_path in person_images.items():
image = cv2.imread(image_path)
faces = detector.detect(image)
if faces:
embedding = recognizer.get_normalized_embedding(
image, faces[0]['landmarks']
)
database[person_id] = embedding
# Search for a face
query_image = cv2.imread("query.jpg")
query_faces = detector.detect(query_image)
if query_faces:
query_embedding = recognizer.get_normalized_embedding(
query_image, query_faces[0]['landmarks']
)
# Find best match
best_match = None
best_similarity = -1
for person_id, db_embedding in database.items():
similarity = np.dot(query_embedding, db_embedding.T)[0][0]
if similarity > best_similarity:
best_similarity = similarity
best_match = person_id
print(f"Best match: {best_match} (similarity: {best_similarity:.4f})")
More examples in the examples/ directory.
Advanced Configuration
Custom ONNX Runtime Providers
from uniface.onnx_utils import get_available_providers, create_onnx_session
# Check available providers
providers = get_available_providers()
print(f"Available: {providers}")
# Force CPU-only execution
from uniface import RetinaFace
detector = RetinaFace()
# Internally uses create_onnx_session() which auto-selects best provider
Model Download and Caching
Models are automatically downloaded on first use and cached in ~/.uniface/models/.
from uniface.model_store import verify_model_weights
from uniface.constants import RetinaFaceWeights
# Manually download and verify a model
model_path = verify_model_weights(
RetinaFaceWeights.MNET_V2,
root='./custom_models' # Custom cache directory
)
Logging Configuration
from uniface import Logger
import logging
# Set logging level
Logger.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR
# Disable logging
Logger.setLevel(logging.CRITICAL)
Testing
# Run all tests
pytest
# Run with coverage
pytest --cov=uniface --cov-report=html
# Run specific test file
pytest tests/test_retinaface.py -v
Development
Setup Development Environment
git clone https://github.com/yakhyo/uniface.git
cd uniface
# Install in editable mode with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
Code Formatting
This project uses Ruff for linting and formatting.
# Format code
ruff format .
# Check for linting errors
ruff check .
# Auto-fix linting errors
ruff check . --fix
Ruff configuration is in pyproject.toml. Key settings:
- Line length: 120
- Python target: 3.10+
- Import sorting:
unifaceas first-party
Project Structure
uniface/
├── uniface/
│ ├── detection/ # Face detection models
│ ├── recognition/ # Face recognition models
│ ├── landmark/ # Landmark detection
│ ├── parsing/ # Face parsing
│ ├── gaze/ # Gaze estimation
│ ├── attribute/ # Age, gender, emotion
│ ├── onnx_utils.py # ONNX Runtime utilities
│ ├── model_store.py # Model download & caching
│ └── visualization.py # Drawing utilities
├── tests/ # Unit tests
├── examples/ # Example notebooks
└── scripts/ # Utility scripts
References
- RetinaFace Training: yakhyo/retinaface-pytorch - PyTorch implementation and training code
- YOLOv5-Face ONNX: yakhyo/yolov5-face-onnx-inference - ONNX inference implementation
- Face Recognition Training: yakhyo/face-recognition - ArcFace, MobileFace, SphereFace training code
- Face Parsing Training: yakhyo/face-parsing - BiSeNet face parsing training code and pretrained weights
- Gaze Estimation Training: yakhyo/gaze-estimation - MobileGaze training code and pretrained weights
- InsightFace: deepinsight/insightface - Model architectures and pretrained weights
Contributing
Contributions are welcome! Please open an issue or submit a pull request on GitHub.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file uniface-1.5.0.tar.gz.
File metadata
- Download URL: uniface-1.5.0.tar.gz
- Upload date:
- Size: 63.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cb0d3383c1ba41310832b502e0992eaaa2f01b19a438938a258fcb7a1131c4d4
|
|
| MD5 |
3a74ecaedbd414ebbcd104536c40a49f
|
|
| BLAKE2b-256 |
e909980023a2ee6707ff8f19d4fad86776c95d9751fb4d07ac49bace7f1b25eb
|
File details
Details for the file uniface-1.5.0-py3-none-any.whl.
File metadata
- Download URL: uniface-1.5.0-py3-none-any.whl
- Upload date:
- Size: 69.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ecf4f5c1f47453ebc7b8937dae0884e4daae7ccf8c4db0de3b8cf920fb157835
|
|
| MD5 |
c1c8f90434d03232ea3c105ae7be326e
|
|
| BLAKE2b-256 |
8bfb9d4ffa5650d81108da5bc9bca71fe469c1d3c36d28f7b05cd610b5d12108
|