uniface is a lightweight face detection library designed for high-performance face localization, landmark detection and face alignment. The library supports ONNX models and provides utilities for bounding box visualization and landmark plotting. To train RetinaFace model, see https://github.com/yakhyo/retinaface-pytorch.
Date | Feature Description |
---|---|
Planned | π Age and Gender Detection: Planned feature for predicting age and gender from facial images. |
Planned | 𧩠Face Recognition: Upcoming capability to identify and verify faces. |
2024-11-21 | π Face Alignment: Added precise face alignment for better downstream tasks. |
2024-11-20 | β‘ High-Speed Face Detection: ONNX model integration for faster and efficient face detection. |
2024-11-20 | π― Facial Landmark Localization: Accurate detection of key facial features like eyes, nose, and mouth. |
2024-11-20 | π API for Inference and Visualization: Simplified API for seamless inference and visual results generation. |
The easiest way to install UniFace is via PyPI. This will automatically install the library along with its prerequisites.
pip install uniface
To work with the latest version of UniFace, which may not yet be released on PyPI, you can install it directly from the repository:
git clone https://github.com/yakhyo/uniface.git
cd uniface
pip install .
To get started with face detection using UniFace, check out the example notebook. It demonstrates how to initialize the model, run inference, and visualize the results.
Explore the following example notebooks to learn how to use UniFace effectively:
- Face Detection: Demonstrates how to perform face detection, draw bounding boxes, and landmarks on an image.
- Face Alignment: Shows how to align faces using detected landmarks.
- Age and Gender Detection: Example for detecting age and gender from faces. (underdevelopment)
To use the RetinaFace model for face detection, initialize it with either custom or default configuration parameters.
from uniface import RetinaFace
from uniface.constants import RetinaFaceWeights
# Initialize RetinaFace with custom configuration
uniface_inference = RetinaFace(
model_name=RetinaFaceWeights.MNET_V2, # Model name from enum
conf_thresh=0.5, # Confidence threshold for detections
pre_nms_topk=5000, # Number of top detections before NMS
nms_thresh=0.4, # IoU threshold for NMS
post_nms_topk=750, # Number of top detections after NMS
dynamic_size=False, # Whether to allow arbitrary input sizes
input_size=(640, 640) # Input image size (HxW)
)
from uniface import RetinaFace
# Initialize with default settings
uniface_inference = RetinaFace()
Default Parameters:
model_name = RetinaFaceWeights.MNET_V2
conf_thresh = 0.5
pre_nms_topk = 5000
nms_thresh = 0.4
post_nms_topk = 750
dynamic_size = False
input_size = (640, 640)
Inference on image:
import cv2
from uniface.visualization import draw_detections
# Load an image
image_path = "assets/test.jpg"
original_image = cv2.imread(image_path)
# Perform inference
boxes, landmarks = uniface_inference.detect(original_image)
# boxes: [x_min, y_min, x_max, y_max, confidence]
# Visualize results
draw_detections(original_image, (boxes, landmarks), vis_threshold=0.6)
# Save the output image
output_path = "output.jpg"
cv2.imwrite(output_path, original_image)
print(f"Saved output image to {output_path}")
Inference on video:
import cv2
from uniface.visualization import draw_detections
# Initialize the webcam
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("Error: Unable to access the webcam.")
exit()
while True:
# Capture a frame from the webcam
ret, frame = cap.read()
if not ret:
print("Error: Failed to read frame.")
break
# Perform inference
boxes, landmarks = uniface_inference.detect(frame)
# 'boxes' contains bounding box coordinates and confidence scores:
# Format: [x_min, y_min, x_max, y_max, confidence]
# Draw detections on the frame
draw_detections(frame, (boxes, landmarks), vis_threshold=0.6)
# Display the output
cv2.imshow("Webcam Inference", frame)
# Exit if 'q' is pressed
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# Release the webcam and close all OpenCV windows
cap.release()
cv2.destroyAllWindows()
RetinaFace Models | Easy | Medium | Hard |
---|---|---|---|
retinaface_mnet025 | 88.48% | 87.02% | 80.61% |
retinaface_mnet050 | 89.42% | 87.97% | 82.40% |
retinaface_mnet_v1 | 90.59% | 89.14% | 84.13% |
retinaface_mnet_v2 | 91.70% | 91.03% | 86.60% |
retinaface_r18 | 92.50% | 91.02% | 86.63% |
retinaface_r34 | 94.16% | 93.12% | 88.90% |
from typings import Tuple
from uniface import RetinaFace
from uniface.constants import RetinaFaceWeights
RetinaFace(
model_name: RetinaFaceWeights,
conf_thresh: float = 0.5,
pre_nms_topk: int = 5000,
nms_thresh: float = 0.4,
post_nms_topk: int = 750,
dynamic_size: bool = False,
input_size: Tuple[int, int] = (640, 640)
)
Parameters:
model_name
(RetinaFaceWeights): Enum value for model to use. Supported values:MNET_025
,MNET_050
,MNET_V1
,MNET_V2
,RESNET18
,RESNET34
conf_thresh
(float, default=0.5): Minimum confidence score for detections.pre_nms_topk
(int, default=5000): Max detections to keep before NMS.nms_thresh
(float, default=0.4): IoU threshold for Non-Maximum Suppression.post_nms_topk
(int, default=750): Max detections to keep after NMS.dynamic_size
(Optional[bool], default=False): Use dynamic input size.input_size
(Optional[Tuple[int, int]], default=(640, 640)): Static input size for the model (width, height).
detect(
image: np.ndarray,
max_num: int = 0,
metric: str = "default",
center_weight: float = 2.0
) -> Tuple[np.ndarray, np.ndarray]
Description: Detects faces in the given image and returns bounding boxes and landmarks.
Parameters:
image
(np.ndarray): Input image in BGR format.max_num
(int, default=0): Maximum number of faces to return.0
means return all.metric
(str, default="default"): Metric for prioritizing detections:"default"
: Prioritize detections closer to the image center."max"
: Prioritize larger bounding box areas.
center_weight
(float, default=2.0): Weight for prioritizing center-aligned faces.
Returns:
bounding_boxes
(np.ndarray): Array of detections as[x_min, y_min, x_max, y_max, confidence]
.landmarks
(np.ndarray): Array of landmarks as[(x1, y1), ..., (x5, y5)]
.
draw_detections(
image: np.ndarray,
detections: Tuple[np.ndarray, np.ndarray],
vis_threshold: float = 0.6
) -> None
Description: Draws bounding boxes and landmarks on the given image.
Parameters:
image
(np.ndarray): The input image in BGR format.detections
(Tuple[np.ndarray, np.ndarray]): A tuple of bounding boxes and landmarks.vis_threshold
(float, default=0.6): Minimum confidence score for visualization.
We welcome contributions to enhance the library! Feel free to:
- Submit bug reports or feature requests.
- Fork the repository and create a pull request.
This project is licensed under the MIT License. See the LICENSE file for details.
- Based on the RetinaFace model for face detection (https://github.com/yakhyo/retinaface-pytorch).
- Inspired by InsightFace and other face detection projects.