| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- # Copyright 2025 Yakhyokhuja Valikhujaev
- # Author: Yakhyokhuja Valikhujaev
- # GitHub: https://github.com/yakhyo
- from typing import List, Optional
- import numpy as np
- from uniface.attribute.age_gender import AgeGender
- from uniface.detection.base import BaseDetector
- from uniface.face import Face
- from uniface.log import Logger
- from uniface.recognition.base import BaseRecognizer
- __all__ = ['FaceAnalyzer']
- class FaceAnalyzer:
- """Unified face analyzer combining detection, recognition, and attributes."""
- def __init__(
- self,
- detector: BaseDetector,
- recognizer: Optional[BaseRecognizer] = None,
- age_gender: Optional[AgeGender] = None,
- ) -> None:
- self.detector = detector
- self.recognizer = recognizer
- self.age_gender = age_gender
- Logger.info(f'Initialized FaceAnalyzer with detector={detector.__class__.__name__}')
- if recognizer:
- Logger.info(f' - Recognition enabled: {recognizer.__class__.__name__}')
- if age_gender:
- Logger.info(f' - Age/Gender enabled: {age_gender.__class__.__name__}')
- def analyze(self, image: np.ndarray) -> List[Face]:
- """Analyze faces in an image."""
- detections = self.detector.detect(image)
- Logger.debug(f'Detected {len(detections)} face(s)')
- faces = []
- for idx, detection in enumerate(detections):
- bbox = detection['bbox']
- confidence = detection['confidence']
- landmarks = detection['landmarks']
- embedding = None
- if self.recognizer is not None:
- try:
- embedding = self.recognizer.get_normalized_embedding(image, landmarks)
- Logger.debug(f' Face {idx + 1}: Extracted embedding with shape {embedding.shape}')
- except Exception as e:
- Logger.warning(f' Face {idx + 1}: Failed to extract embedding: {e}')
- age, gender_id = None, None
- if self.age_gender is not None:
- try:
- gender_id, age = self.age_gender.predict(image, bbox)
- gender_str = 'Female' if gender_id == 0 else 'Male'
- Logger.debug(f' Face {idx + 1}: Age={age}, Gender={gender_str}')
- except Exception as e:
- Logger.warning(f' Face {idx + 1}: Failed to predict age/gender: {e}')
- face = Face(
- bbox=bbox,
- confidence=confidence,
- landmarks=landmarks,
- embedding=embedding,
- age=age,
- gender_id=gender_id,
- )
- faces.append(face)
- Logger.info(f'Analysis complete: {len(faces)} face(s) processed')
- return faces
- def __repr__(self) -> str:
- parts = [f'FaceAnalyzer(detector={self.detector.__class__.__name__}']
- if self.recognizer:
- parts.append(f'recognizer={self.recognizer.__class__.__name__}')
- if self.age_gender:
- parts.append(f'age_gender={self.age_gender.__class__.__name__}')
- return ', '.join(parts) + ')'
|