Spaces:
Sleeping
Sleeping
| import cv2 | |
| import numpy as np | |
| import os | |
| import urllib.request | |
| from huggingface_hub import hf_hub_download | |
| REPO_ID = "codernotme/kataria_optical" | |
| MODEL_FILE = "lbfmodel.yaml" | |
| _facemark = None | |
| _face_cascade = None | |
| def ensure_model(): | |
| global MODEL_FILE | |
| if not os.path.exists(MODEL_FILE): | |
| print(f"Attempting to download {MODEL_FILE} from HF Hub...") | |
| try: | |
| downloaded_path = hf_hub_download(repo_id=REPO_ID, filename=MODEL_FILE) | |
| MODEL_FILE = downloaded_path | |
| print("Download from HF Hub complete.") | |
| except Exception as e: | |
| print(f"HF Hub download failed ({e}), falling back to GitHub...") | |
| MODEL_URL = "https://raw.githubusercontent.com/kurnianggoro/GSOC2017/master/data/lbfmodel.yaml" | |
| try: | |
| urllib.request.urlretrieve(MODEL_URL, MODEL_FILE) | |
| print("Download from GitHub complete.") | |
| except Exception as e2: | |
| raise RuntimeError(f"Failed to download LBF model from all sources: {e2}") | |
| def _get_facemark(): | |
| global _facemark | |
| if _facemark is None: | |
| ensure_model() | |
| _facemark = cv2.face.createFacemarkLBF() | |
| try: | |
| _facemark.loadModel(MODEL_FILE) | |
| except Exception as e: | |
| raise RuntimeError(f"Could not load LBF model: {e}") | |
| return _facemark | |
| def _get_face_cascade(): | |
| global _face_cascade | |
| if _face_cascade is None: | |
| face_cascade_path = cv2.data.haarcascades + "haarcascade_frontalface_alt2.xml" | |
| _face_cascade = cv2.CascadeClassifier(face_cascade_path) | |
| if _face_cascade.empty(): | |
| _face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml") | |
| return _face_cascade | |
| def get_landmarks(image_input): | |
| """ | |
| Extracts 68 face landmarks using OpenCV FacemarkLBF. | |
| Returns a list/array of (x, y) coordinates. | |
| """ | |
| facemark = _get_facemark() | |
| if isinstance(image_input, str): | |
| image = cv2.imread(image_input) | |
| if image is None: | |
| raise ValueError(f"Could not read image: {image_input}") | |
| else: | |
| if hasattr(image_input, "mode"): | |
| image = cv2.cvtColor(np.array(image_input), cv2.COLOR_RGB2BGR) | |
| else: | |
| image = np.array(image_input) | |
| if image.ndim == 3 and image.shape[2] == 3: | |
| image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) | |
| if image is None or image.size == 0: | |
| raise ValueError("Could not read image data.") | |
| gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) | |
| # Detect faces using Haar Cascade (included in cv2) | |
| face_cascade = _get_face_cascade() | |
| faces = face_cascade.detectMultiScale(gray, 1.3, 5) | |
| if len(faces) == 0: | |
| raise ValueError("No face detected.") | |
| # Find landmarks | |
| ok, landmarks = facemark.fit(gray, faces) | |
| if not ok: | |
| raise ValueError("Could not detect landmarks.") | |
| # landmarks comes as a list of numpy arrays, we extract the first face's landmarks | |
| # landmarks[0] is shape (1, 68, 2) | |
| return landmarks[0][0] | |