| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- # Copyright 2025 Yakhyokhuja Valikhujaev
- # Author: Yakhyokhuja Valikhujaev
- # GitHub: https://github.com/yakhyo
- from typing import Any, Dict, List, Union
- import numpy as np
- from uniface.attribute.age_gender import AgeGender
- from uniface.attribute.base import Attribute
- from uniface.constants import AgeGenderWeights, DDAMFNWeights
- # Emotion requires PyTorch - make it optional
- try:
- from uniface.attribute.emotion import Emotion
- _EMOTION_AVAILABLE = True
- except ImportError:
- Emotion = None
- _EMOTION_AVAILABLE = False
- # Public API for the attribute module
- __all__ = ['AgeGender', 'Emotion', 'create_attribute_predictor', 'predict_attributes']
- # A mapping from model enums to their corresponding attribute classes
- _ATTRIBUTE_MODELS = {
- **{model: AgeGender for model in AgeGenderWeights},
- }
- # Add Emotion models only if PyTorch is available
- if _EMOTION_AVAILABLE:
- _ATTRIBUTE_MODELS.update({model: Emotion for model in DDAMFNWeights})
- def create_attribute_predictor(model_name: Union[AgeGenderWeights, DDAMFNWeights], **kwargs: Any) -> Attribute:
- """
- Factory function to create an attribute predictor instance.
- This high-level API simplifies the creation of attribute models by
- dynamically selecting the correct class based on the provided model enum.
- Args:
- model_name: The enum corresponding to the desired attribute model
- (e.g., AgeGenderWeights.DEFAULT or DDAMFNWeights.AFFECNET7).
- **kwargs: Additional keyword arguments to pass to the model's constructor.
- Returns:
- An initialized instance of an Attribute predictor class (e.g., AgeGender).
- Raises:
- ValueError: If the provided model_name is not a supported enum.
- """
- model_class = _ATTRIBUTE_MODELS.get(model_name)
- if model_class is None:
- raise ValueError(
- f'Unsupported attribute model: {model_name}. Please choose from AgeGenderWeights or DDAMFNWeights.'
- )
- # Pass model_name to the constructor, as some classes might need it
- return model_class(model_name=model_name, **kwargs)
- def predict_attributes(
- image: np.ndarray, detections: List[Dict[str, np.ndarray]], predictor: Attribute
- ) -> List[Dict[str, Any]]:
- """
- High-level API to predict attributes for multiple detected faces.
- This function iterates through a list of face detections, runs the
- specified attribute predictor on each one, and appends the results back
- into the detection dictionary.
- Args:
- image (np.ndarray): The full input image in BGR format.
- detections (List[Dict]): A list of detection results, where each dict
- must contain a 'bbox' and optionally 'landmark'.
- predictor (Attribute): An initialized attribute predictor instance,
- created by `create_attribute_predictor`.
- Returns:
- The list of detections, where each dictionary is updated with a new
- 'attributes' key containing the prediction result.
- """
- for face in detections:
- # Initialize attributes dict if it doesn't exist
- if 'attributes' not in face:
- face['attributes'] = {}
- if isinstance(predictor, AgeGender):
- gender_id, age = predictor(image, face['bbox'])
- face['attributes']['gender_id'] = gender_id
- face['attributes']['age'] = age
- elif isinstance(predictor, Emotion):
- emotion, confidence = predictor(image, face['landmark'])
- face['attributes']['emotion'] = emotion
- face['attributes']['confidence'] = confidence
- return detections
|