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)