Spaces:
Paused
Paused
| import cv2 | |
| import numpy as np | |
| from PIL import Image | |
| import mediapipe as mp | |
| mp_face_mesh = mp.solutions.face_mesh | |
| def preprocess_image(image_path: str) -> np.ndarray: | |
| """Crop face region using MediaPipe, return normalized array for ONNX.""" | |
| img = cv2.imread(image_path) | |
| img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) | |
| with mp_face_mesh.FaceMesh(static_image_mode=True, max_num_faces=1) as face_mesh: | |
| results = face_mesh.process(img_rgb) | |
| if results.multi_face_landmarks: | |
| h, w = img.shape[:2] | |
| landmarks = results.multi_face_landmarks[0].landmark | |
| xs = [int(l.x * w) for l in landmarks] | |
| ys = [int(l.y * h) for l in landmarks] | |
| x1, x2 = max(min(xs)-20, 0), min(max(xs)+20, w) | |
| y1, y2 = max(min(ys)-20, 0), min(max(ys)+20, h) | |
| face_crop = img_rgb[y1:y2, x1:x2] | |
| else: | |
| face_crop = img_rgb # fallback: use full image | |
| # Resize and normalize for MobileNetV2 / ResNet50 | |
| resized = cv2.resize(face_crop, (224, 224)) | |
| arr = resized.astype(np.float32) / 255.0 | |
| arr = (arr - [0.485, 0.456, 0.406]) / [0.229, 0.224, 0.225] # ImageNet norm | |
| return arr.transpose(2, 0, 1)[np.newaxis, :] # (1, 3, 224, 224) | |
| def delete_image(image_path: str): | |
| """DPDP compliance: delete raw image after inference.""" | |
| import os | |
| if os.path.exists(image_path): | |
| os.remove(image_path) | |