Spaces:
Configuration error
Configuration error
| 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 |