2025-12-30 00:20:34 +09:00
|
|
|
# Copyright 2025 Yakhyokhuja Valikhujaev
|
|
|
|
|
# Author: Yakhyokhuja Valikhujaev
|
|
|
|
|
# GitHub: https://github.com/yakhyo
|
|
|
|
|
|
|
|
|
|
"""Tests for RetinaFace detector."""
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
2024-11-20 08:43:25 +00:00
|
|
|
import numpy as np
|
2025-11-08 01:02:14 +09:00
|
|
|
import pytest
|
|
|
|
|
|
2025-03-26 11:55:56 +09:00
|
|
|
from uniface.constants import RetinaFaceWeights
|
2025-11-08 01:02:14 +09:00
|
|
|
from uniface.detection import RetinaFace
|
2024-11-20 08:43:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
|
def retinaface_model():
|
|
|
|
|
return RetinaFace(
|
2025-03-26 11:55:56 +09:00
|
|
|
model_name=RetinaFaceWeights.MNET_V2,
|
2025-12-30 00:20:34 +09:00
|
|
|
confidence_threshold=0.5,
|
2024-11-20 08:43:25 +00:00
|
|
|
pre_nms_topk=5000,
|
2025-12-30 00:20:34 +09:00
|
|
|
nms_threshold=0.4,
|
2024-11-20 08:43:25 +00:00
|
|
|
post_nms_topk=750,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_model_initialization(retinaface_model):
|
2025-11-30 20:32:07 +09:00
|
|
|
assert retinaface_model is not None, 'Model initialization failed.'
|
2024-11-20 08:43:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_inference_on_640x640_image(retinaface_model):
|
|
|
|
|
mock_image = np.random.randint(0, 255, (640, 640, 3), dtype=np.uint8)
|
2025-11-08 01:02:14 +09:00
|
|
|
faces = retinaface_model.detect(mock_image)
|
|
|
|
|
|
2025-11-30 20:32:07 +09:00
|
|
|
assert isinstance(faces, list), 'Detections should be a list.'
|
2024-11-20 08:43:25 +00:00
|
|
|
|
2025-11-08 01:02:14 +09:00
|
|
|
for face in faces:
|
2025-12-30 00:20:34 +09:00
|
|
|
# Face is a dataclass, check attributes exist
|
|
|
|
|
assert hasattr(face, 'bbox'), "Each detection should have a 'bbox' attribute."
|
|
|
|
|
assert hasattr(face, 'confidence'), "Each detection should have a 'confidence' attribute."
|
|
|
|
|
assert hasattr(face, 'landmarks'), "Each detection should have a 'landmarks' attribute."
|
2024-11-20 08:43:25 +00:00
|
|
|
|
2025-12-30 00:20:34 +09:00
|
|
|
bbox = face.bbox
|
2025-11-30 20:32:07 +09:00
|
|
|
assert len(bbox) == 4, 'BBox should have 4 values (x1, y1, x2, y2).'
|
2024-11-20 08:43:25 +00:00
|
|
|
|
2025-12-30 00:20:34 +09:00
|
|
|
landmarks = face.landmarks
|
2025-11-30 20:32:07 +09:00
|
|
|
assert len(landmarks) == 5, 'Should have 5 landmark points.'
|
|
|
|
|
assert all(len(pt) == 2 for pt in landmarks), 'Each landmark should be (x, y).'
|
2024-11-20 08:43:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_confidence_threshold(retinaface_model):
|
|
|
|
|
mock_image = np.random.randint(0, 255, (640, 640, 3), dtype=np.uint8)
|
2025-11-08 01:02:14 +09:00
|
|
|
faces = retinaface_model.detect(mock_image)
|
2024-11-20 08:43:25 +00:00
|
|
|
|
2025-11-08 01:02:14 +09:00
|
|
|
for face in faces:
|
2025-12-30 00:20:34 +09:00
|
|
|
confidence = face.confidence
|
2025-11-30 20:32:07 +09:00
|
|
|
assert confidence >= 0.5, f'Detection has confidence {confidence} below threshold 0.5'
|
2024-11-20 08:43:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_no_faces_detected(retinaface_model):
|
|
|
|
|
empty_image = np.zeros((640, 640, 3), dtype=np.uint8)
|
2025-11-08 01:02:14 +09:00
|
|
|
faces = retinaface_model.detect(empty_image)
|
2025-11-30 20:32:07 +09:00
|
|
|
assert len(faces) == 0, 'Should detect no faces in a blank image.'
|