App / utils.py
RICHERGIRL's picture
Update utils.py
cbf5ccd verified
import cv2
import mediapipe as mp
import numpy as np
from typing import Tuple, Optional
# Initialize MediaPipe face detection
mp_face_detection = mp.solutions.face_detection
mp_face_mesh = mp.solutions.face_mesh # For detailed landmarks
def classify_face_shape(landmarks) -> str:
"""Determine face shape using geometric ratios."""
# Example: Calculate jaw-to-forehead ratio
jaw_width = landmarks[234].x - landmarks[454].x # Left/right jaw points
forehead_height = landmarks[10].y - landmarks[152].y # Forehead to chin
ratio = jaw_width / forehead_height
if ratio > 1.1: return "Square"
elif ratio > 0.9: return "Round"
else: return "Oval"
def estimate_skin_tone(image, face_roi) -> str:
"""Analyze skin tone in the cheek region."""
x, y, w, h = face_roi
cheek_region = image[y:y+h//2, x:x+w//2] # Get left cheek area
# Convert to LAB color space for skin tone analysis
lab = cv2.cvtColor(cheek_region, cv2.COLOR_BGR2LAB)
l, a, b = np.mean(lab, axis=(0,1))
if l > 160: return "Fair"
elif l > 120: return "Medium"
else: return "Dark"
def extract_features(image_path: str) -> Tuple[Optional[str], Optional[str], Optional[str]]:
"""Extract face attributes from an image."""
# Read and convert image
image = cv2.imread(image_path)
if image is None:
return None, None, None
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
height, width = image.shape[:2]
# Face detection
with mp_face_detection.FaceDetection(min_detection_confidence=0.5) as detector:
results = detector.process(image_rgb)
if not results.detections:
return None, None, None
# Get face bounding box
bbox = results.detections[0].location_data.relative_bounding_box
x, y = int(bbox.xmin * width), int(bbox.ymin * height)
w, h = int(bbox.width * width), int(bbox.height * height)
# Face size classification
face_size = "Large" if w > 300 else "Medium" if w > 200 else "Small"
# Face mesh for detailed landmarks
with mp_face_mesh.FaceMesh(static_image_mode=True) as mesh:
mesh_results = mesh.process(image_rgb)
if mesh_results.multi_face_landmarks:
landmarks = mesh_results.multi_face_landmarks[0].landmark
face_shape = classify_face_shape(landmarks)
skin_tone = estimate_skin_tone(image, (x, y, w, h))
return face_shape, skin_tone, face_size
return None, None, None # Fallback if mesh detection fails