Spaces:
Running
Running
| import cv2 | |
| import numpy as np | |
| def draw_landmarks( | |
| image: np.ndarray, | |
| landmarks: np.ndarray, | |
| color: tuple = (0, 255, 0), | |
| radius: int = 1 | |
| ) -> np.ndarray: | |
| """Draw facial landmark points on a copy of the image.""" | |
| out = image.copy() | |
| if landmarks is None: | |
| return out | |
| for (x, y) in landmarks.astype(int): | |
| if 0 <= x < image.shape[1] and 0 <= y < image.shape[0]: | |
| cv2.circle(out, (x, y), radius, color, -1) | |
| return out | |
| def draw_bounding_boxes( | |
| image: np.ndarray, | |
| bboxes: list, | |
| color: tuple = (0, 255, 0), | |
| thickness: int = 2 | |
| ) -> np.ndarray: | |
| """Draw bounding boxes on a copy of the image. Accepts (x1,y1,x2,y2) tuples.""" | |
| out = image.copy() | |
| for bbox in bboxes: | |
| if hasattr(bbox, 'bbox'): | |
| # InsightFace face object | |
| x1, y1, x2, y2 = bbox.bbox.astype(int) | |
| else: | |
| x1, y1, x2, y2 = [int(v) for v in bbox] | |
| cv2.rectangle(out, (x1, y1), (x2, y2), color, thickness) | |
| return out | |
| def draw_mask_overlay( | |
| image: np.ndarray, | |
| mask: np.ndarray, | |
| color: tuple = (0, 120, 255), | |
| alpha: float = 0.35 | |
| ) -> np.ndarray: | |
| """Overlay a coloured semi-transparent mask on the image.""" | |
| out = image.copy().astype(np.float32) | |
| overlay = np.zeros_like(image, dtype=np.float32) | |
| m = mask.astype(np.float32) / 255.0 if mask.max() > 1 else mask.astype(np.float32) | |
| overlay[:] = color[::-1] # BGR | |
| mask_3 = np.stack([m] * 3, axis=-1) | |
| out = out * (1 - mask_3 * alpha) + overlay * mask_3 * alpha | |
| return np.clip(out, 0, 255).astype(np.uint8) | |
| def draw_quality_metrics( | |
| image: np.ndarray, | |
| metrics: dict | |
| ) -> np.ndarray: | |
| """Draw quality metric text overlay on the image.""" | |
| out = image.copy() | |
| lines = [ | |
| f"Align: {metrics.get('alignment', 0):.1f}/100", | |
| f"Blend: {metrics.get('blend', 0):.1f}/100", | |
| f"dE: {metrics.get('delta_e', 0):.2f}", | |
| f"Natural: {metrics.get('naturalness', 0):.1f}/100", | |
| ] | |
| y = 20 | |
| for line in lines: | |
| cv2.putText(out, line, (10, y), cv2.FONT_HERSHEY_SIMPLEX, | |
| 0.5, (0, 0, 0), 2, cv2.LINE_AA) | |
| cv2.putText(out, line, (10, y), cv2.FONT_HERSHEY_SIMPLEX, | |
| 0.5, (255, 255, 255), 1, cv2.LINE_AA) | |
| y += 20 | |
| return out | |