face-intel / cores /vision /geometry.py
Marwan
Restructure + add reverse face search (PimEyes-style)
f5eeb1c
Raw
History Blame Contribute Delete
2.13 kB
"""Geometry — bounding boxes, cropping, resizing."""
from __future__ import annotations
from dataclasses import dataclass
from typing import Tuple
import cv2
import numpy as np
@dataclass
class BBox:
"""Axis-aligned bounding box."""
x: int
y: int
w: int
h: int
def to_dict(self) -> dict:
return {"x": self.x, "y": self.y, "w": self.w, "h": self.h}
@property
def area(self) -> int:
return self.w * self.h
def to_face_recognition_tuple(self) -> Tuple[int, int, int, int]:
"""Convert to (top, right, bottom, left) tuple used by face_recognition."""
return (self.y, self.x + self.w, self.y + self.h, self.x)
def crop_region(img: np.ndarray, bbox: BBox, margin: float = 0.0) -> np.ndarray:
"""Crop a region with optional fractional margin. Clamps to image bounds."""
dx = int(bbox.w * margin)
dy = int(bbox.h * margin)
x0 = max(0, bbox.x - dx)
y0 = max(0, bbox.y - dy)
x1 = min(img.shape[1], bbox.x + bbox.w + dx)
y1 = min(img.shape[0], bbox.y + bbox.h + dy)
return img[y0:y1, x0:x1]
def resize_with_aspect(img: np.ndarray, max_dim: int = 1024) -> np.ndarray:
"""Resize so the longest side is at most max_dim, preserving aspect."""
h, w = img.shape[:2]
if max(h, w) <= max_dim:
return img
scale = max_dim / max(h, w)
return cv2.resize(img, (int(w * scale), int(h * scale)), interpolation=cv2.INTER_AREA)
def clamp_box(bbox: BBox, width: int, height: int) -> BBox:
"""Clamp a bounding box to image bounds."""
x = max(0, min(bbox.x, width - 1))
y = max(0, min(bbox.y, height - 1))
x2 = max(0, min(bbox.x + bbox.w, width))
y2 = max(0, min(bbox.y + bbox.h, height))
return BBox(x, y, max(0, x2 - x), max(0, y2 - y))
def boxes_iou(a: BBox, b: BBox) -> float:
"""Intersection-over-Union between two bounding boxes."""
x1 = max(a.x, b.x)
y1 = max(a.y, b.y)
x2 = min(a.x + a.w, b.x + b.w)
y2 = min(a.y + a.h, b.y + b.h)
inter = max(0, x2 - x1) * max(0, y2 - y1)
union = a.area + b.area - inter
return inter / union if union > 0 else 0.0