__init__.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. # Copyright 2025 Yakhyokhuja Valikhujaev
  2. # Author: Yakhyokhuja Valikhujaev
  3. # GitHub: https://github.com/yakhyo
  4. from typing import Any, Dict, List, Union
  5. import numpy as np
  6. from uniface.attribute.age_gender import AgeGender
  7. from uniface.attribute.base import Attribute
  8. from uniface.constants import AgeGenderWeights, DDAMFNWeights
  9. # Emotion requires PyTorch - make it optional
  10. try:
  11. from uniface.attribute.emotion import Emotion
  12. _EMOTION_AVAILABLE = True
  13. except ImportError:
  14. Emotion = None
  15. _EMOTION_AVAILABLE = False
  16. # Public API for the attribute module
  17. __all__ = ['AgeGender', 'Emotion', 'create_attribute_predictor', 'predict_attributes']
  18. # A mapping from model enums to their corresponding attribute classes
  19. _ATTRIBUTE_MODELS = {
  20. **{model: AgeGender for model in AgeGenderWeights},
  21. }
  22. # Add Emotion models only if PyTorch is available
  23. if _EMOTION_AVAILABLE:
  24. _ATTRIBUTE_MODELS.update({model: Emotion for model in DDAMFNWeights})
  25. def create_attribute_predictor(model_name: Union[AgeGenderWeights, DDAMFNWeights], **kwargs: Any) -> Attribute:
  26. """
  27. Factory function to create an attribute predictor instance.
  28. This high-level API simplifies the creation of attribute models by
  29. dynamically selecting the correct class based on the provided model enum.
  30. Args:
  31. model_name: The enum corresponding to the desired attribute model
  32. (e.g., AgeGenderWeights.DEFAULT or DDAMFNWeights.AFFECNET7).
  33. **kwargs: Additional keyword arguments to pass to the model's constructor.
  34. Returns:
  35. An initialized instance of an Attribute predictor class (e.g., AgeGender).
  36. Raises:
  37. ValueError: If the provided model_name is not a supported enum.
  38. """
  39. model_class = _ATTRIBUTE_MODELS.get(model_name)
  40. if model_class is None:
  41. raise ValueError(
  42. f'Unsupported attribute model: {model_name}. Please choose from AgeGenderWeights or DDAMFNWeights.'
  43. )
  44. # Pass model_name to the constructor, as some classes might need it
  45. return model_class(model_name=model_name, **kwargs)
  46. def predict_attributes(
  47. image: np.ndarray, detections: List[Dict[str, np.ndarray]], predictor: Attribute
  48. ) -> List[Dict[str, Any]]:
  49. """
  50. High-level API to predict attributes for multiple detected faces.
  51. This function iterates through a list of face detections, runs the
  52. specified attribute predictor on each one, and appends the results back
  53. into the detection dictionary.
  54. Args:
  55. image (np.ndarray): The full input image in BGR format.
  56. detections (List[Dict]): A list of detection results, where each dict
  57. must contain a 'bbox' and optionally 'landmark'.
  58. predictor (Attribute): An initialized attribute predictor instance,
  59. created by `create_attribute_predictor`.
  60. Returns:
  61. The list of detections, where each dictionary is updated with a new
  62. 'attributes' key containing the prediction result.
  63. """
  64. for face in detections:
  65. # Initialize attributes dict if it doesn't exist
  66. if 'attributes' not in face:
  67. face['attributes'] = {}
  68. if isinstance(predictor, AgeGender):
  69. gender_id, age = predictor(image, face['bbox'])
  70. face['attributes']['gender_id'] = gender_id
  71. face['attributes']['age'] = age
  72. elif isinstance(predictor, Emotion):
  73. emotion, confidence = predictor(image, face['landmark'])
  74. face['attributes']['emotion'] = emotion
  75. face['attributes']['confidence'] = confidence
  76. return detections