import numpy as np from scipy.spatial import distance as dist def euclidean_dist(p1, p2): return dist.euclidean(p1, p2) def extract_features(landmarks): """ Extracts geometric features from 68-point facial landmarks. Indices based on dlib/OpenCV LBF standard. Key Points: - Jaw: 0-16 (8 is chin) - Eyebrows: 17-21 (left), 22-26 (right) - Nose: 27-35 (27 is bridge top) - Eyes: 36-41 (left), 42-47 (right) """ landmarks = np.array(landmarks) # defined points jaw_left = landmarks[4] jaw_right = landmarks[12] chin = landmarks[8] temple_left = landmarks[0] temple_right = landmarks[16] brow_left = landmarks[19] brow_right = landmarks[24] # Measurements jaw_width = euclidean_dist(jaw_left, jaw_right) face_width = euclidean_dist(temple_left, temple_right) # Cheekbone/Temple width brow_mid = (brow_left + brow_right) / 2.0 face_length = euclidean_dist(chin, brow_mid) # Approximations forehead_width = face_width * 0.9 # Hard to measure with 68 points, assume slightly narrower than temples # Ratios lw_ratio = face_length / face_width if face_width > 0 else 0 jaw_ratio = jaw_width / face_width if face_width > 0 else 0 forehead_ratio = forehead_width / face_width if face_width > 0 else 0 # Will be constant-ish with this heuristic return { "lw_ratio": lw_ratio, "jaw_ratio": jaw_ratio, "forehead_ratio": forehead_ratio }