mirror of
https://github.com/yakhyo/uniface.git
synced 2026-05-15 12:57:55 +00:00
* refactor: Split recognition models into separate files * feat: Add EdgeFace recognition model * release: Bump version to v3.4.0
263 lines
8.2 KiB
Python
263 lines
8.2 KiB
Python
# Copyright 2025-2026 Yakhyokhuja Valikhujaev
|
|
# Author: Yakhyokhuja Valikhujaev
|
|
# GitHub: https://github.com/yakhyo
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
import numpy as np
|
|
import pytest
|
|
|
|
from uniface import (
|
|
create_attribute_predictor,
|
|
create_detector,
|
|
create_landmarker,
|
|
create_recognizer,
|
|
list_available_detectors,
|
|
)
|
|
from uniface.attribute import AgeGender, FairFace
|
|
from uniface.constants import AgeGenderWeights, FairFaceWeights, RetinaFaceWeights, SCRFDWeights
|
|
from uniface.spoofing import MiniFASNet, create_spoofer
|
|
|
|
|
|
# create_detector tests
|
|
def test_create_detector_retinaface():
|
|
"""
|
|
Test creating a RetinaFace detector using factory function.
|
|
"""
|
|
detector = create_detector('retinaface')
|
|
assert detector is not None, 'Failed to create RetinaFace detector'
|
|
|
|
|
|
def test_create_detector_scrfd():
|
|
"""
|
|
Test creating a SCRFD detector using factory function.
|
|
"""
|
|
detector = create_detector('scrfd')
|
|
assert detector is not None, 'Failed to create SCRFD detector'
|
|
|
|
|
|
def test_create_detector_with_config():
|
|
"""
|
|
Test creating detector with custom configuration.
|
|
"""
|
|
detector = create_detector(
|
|
'retinaface',
|
|
model_name=RetinaFaceWeights.MNET_V2,
|
|
confidence_threshold=0.8,
|
|
nms_threshold=0.3,
|
|
)
|
|
assert detector is not None, 'Failed to create detector with custom config'
|
|
|
|
|
|
def test_create_detector_invalid_method():
|
|
"""
|
|
Test that invalid detector method raises an error.
|
|
"""
|
|
with pytest.raises((ValueError, KeyError)):
|
|
create_detector('invalid_method')
|
|
|
|
|
|
def test_create_detector_scrfd_with_model():
|
|
"""
|
|
Test creating SCRFD detector with specific model.
|
|
"""
|
|
detector = create_detector('scrfd', model_name=SCRFDWeights.SCRFD_10G_KPS, confidence_threshold=0.5)
|
|
assert detector is not None, 'Failed to create SCRFD with specific model'
|
|
|
|
|
|
# create_recognizer tests
|
|
def test_create_recognizer_arcface():
|
|
"""
|
|
Test creating an ArcFace recognizer using factory function.
|
|
"""
|
|
recognizer = create_recognizer('arcface')
|
|
assert recognizer is not None, 'Failed to create ArcFace recognizer'
|
|
|
|
|
|
def test_create_recognizer_mobileface():
|
|
"""
|
|
Test creating a MobileFace recognizer using factory function.
|
|
"""
|
|
recognizer = create_recognizer('mobileface')
|
|
assert recognizer is not None, 'Failed to create MobileFace recognizer'
|
|
|
|
|
|
def test_create_recognizer_sphereface():
|
|
"""
|
|
Test creating a SphereFace recognizer using factory function.
|
|
"""
|
|
recognizer = create_recognizer('sphereface')
|
|
assert recognizer is not None, 'Failed to create SphereFace recognizer'
|
|
|
|
|
|
def test_create_recognizer_edgeface():
|
|
"""Test creating an EdgeFace recognizer using factory function."""
|
|
recognizer = create_recognizer('edgeface')
|
|
assert recognizer is not None, 'Failed to create EdgeFace recognizer'
|
|
|
|
|
|
def test_create_recognizer_invalid_method():
|
|
"""
|
|
Test that invalid recognizer method raises an error.
|
|
"""
|
|
with pytest.raises((ValueError, KeyError)):
|
|
create_recognizer('invalid_method')
|
|
|
|
|
|
# create_landmarker tests
|
|
def test_create_landmarker():
|
|
"""
|
|
Test creating a Landmark106 detector using factory function.
|
|
"""
|
|
landmarker = create_landmarker('2d106det')
|
|
assert landmarker is not None, 'Failed to create Landmark106 detector'
|
|
|
|
|
|
def test_create_landmarker_default():
|
|
"""
|
|
Test creating landmarker with default parameters.
|
|
"""
|
|
landmarker = create_landmarker()
|
|
assert landmarker is not None, 'Failed to create default landmarker'
|
|
|
|
|
|
def test_create_landmarker_invalid_method():
|
|
"""
|
|
Test that invalid landmarker method raises an error.
|
|
"""
|
|
with pytest.raises((ValueError, KeyError)):
|
|
create_landmarker('invalid_method')
|
|
|
|
|
|
# list_available_detectors tests
|
|
def test_list_available_detectors():
|
|
"""
|
|
Test that list_available_detectors returns a dictionary.
|
|
"""
|
|
detectors = list_available_detectors()
|
|
|
|
assert isinstance(detectors, dict), 'Should return a dictionary of detectors'
|
|
assert len(detectors) > 0, 'Should have at least one detector available'
|
|
|
|
|
|
def test_list_available_detectors_contents():
|
|
"""
|
|
Test that list includes known detectors.
|
|
"""
|
|
detectors = list_available_detectors()
|
|
|
|
# Should include at least these detectors
|
|
assert 'retinaface' in detectors, "Should include 'retinaface'"
|
|
assert 'scrfd' in detectors, "Should include 'scrfd'"
|
|
|
|
|
|
# Integration tests
|
|
def test_detector_inference_from_factory():
|
|
"""
|
|
Test that detector created from factory can perform inference.
|
|
"""
|
|
detector = create_detector('retinaface')
|
|
mock_image = np.random.randint(0, 255, (640, 640, 3), dtype=np.uint8)
|
|
|
|
faces = detector.detect(mock_image)
|
|
assert isinstance(faces, list), 'Detector should return list of faces'
|
|
|
|
|
|
def test_recognizer_inference_from_factory():
|
|
"""
|
|
Test that recognizer created from factory can perform inference.
|
|
"""
|
|
recognizer = create_recognizer('arcface')
|
|
mock_image = np.random.randint(0, 255, (112, 112, 3), dtype=np.uint8)
|
|
|
|
embedding = recognizer.get_embedding(mock_image)
|
|
assert embedding is not None, 'Recognizer should return embedding'
|
|
assert embedding.shape == (1, 512), 'get_embedding should return (1, 512) with batch dimension'
|
|
|
|
|
|
def test_landmarker_inference_from_factory():
|
|
"""
|
|
Test that landmarker created from factory can perform inference.
|
|
"""
|
|
landmarker = create_landmarker('2d106det')
|
|
mock_image = np.random.randint(0, 255, (640, 640, 3), dtype=np.uint8)
|
|
mock_bbox = [100, 100, 300, 300]
|
|
|
|
landmarks = landmarker.get_landmarks(mock_image, mock_bbox)
|
|
assert landmarks is not None, 'Landmarker should return landmarks'
|
|
assert landmarks.shape == (106, 2), 'Should return 106 landmarks'
|
|
|
|
|
|
def test_multiple_detector_creation():
|
|
"""
|
|
Test that multiple detectors can be created independently.
|
|
"""
|
|
detector1 = create_detector('retinaface')
|
|
detector2 = create_detector('scrfd')
|
|
|
|
assert detector1 is not None
|
|
assert detector2 is not None
|
|
assert detector1 is not detector2, 'Should create separate instances'
|
|
|
|
|
|
def test_detector_with_different_configs():
|
|
"""
|
|
Test creating multiple detectors with different configurations.
|
|
"""
|
|
detector_high_thresh = create_detector('retinaface', confidence_threshold=0.9)
|
|
detector_low_thresh = create_detector('retinaface', confidence_threshold=0.3)
|
|
|
|
mock_image = np.random.randint(0, 255, (640, 640, 3), dtype=np.uint8)
|
|
|
|
faces_high = detector_high_thresh.detect(mock_image)
|
|
faces_low = detector_low_thresh.detect(mock_image)
|
|
|
|
# Both should work
|
|
assert isinstance(faces_high, list)
|
|
assert isinstance(faces_low, list)
|
|
|
|
|
|
def test_factory_returns_correct_types():
|
|
"""
|
|
Test that factory functions return instances of the correct types.
|
|
"""
|
|
from uniface import ArcFace, Landmark106, RetinaFace
|
|
|
|
detector = create_detector('retinaface')
|
|
recognizer = create_recognizer('arcface')
|
|
landmarker = create_landmarker('2d106det')
|
|
|
|
assert isinstance(detector, RetinaFace), 'Should return RetinaFace instance'
|
|
assert isinstance(recognizer, ArcFace), 'Should return ArcFace instance'
|
|
assert isinstance(landmarker, Landmark106), 'Should return Landmark106 instance'
|
|
|
|
|
|
# create_spoofer tests
|
|
def test_create_spoofer_default():
|
|
"""Test creating a spoofer with default parameters."""
|
|
spoofer = create_spoofer()
|
|
assert isinstance(spoofer, MiniFASNet), 'Should return MiniFASNet instance'
|
|
|
|
|
|
def test_create_spoofer_with_providers():
|
|
"""Test that create_spoofer forwards providers kwarg without TypeError."""
|
|
spoofer = create_spoofer(providers=['CPUExecutionProvider'])
|
|
assert isinstance(spoofer, MiniFASNet), 'Should return MiniFASNet instance'
|
|
|
|
|
|
# create_attribute_predictor tests
|
|
def test_create_attribute_predictor_age_gender():
|
|
predictor = create_attribute_predictor(AgeGenderWeights.DEFAULT)
|
|
assert isinstance(predictor, AgeGender), 'Should return AgeGender instance'
|
|
|
|
|
|
def test_create_attribute_predictor_fairface():
|
|
predictor = create_attribute_predictor(FairFaceWeights.DEFAULT)
|
|
assert isinstance(predictor, FairFace), 'Should return FairFace instance'
|
|
|
|
|
|
def test_create_attribute_predictor_invalid():
|
|
with pytest.raises(ValueError, match='Unsupported attribute model'):
|
|
create_attribute_predictor('invalid_model')
|