""" Face verification utilities. This module provides functions to compare face embeddings and decide whether two faces belong to the same person. It relies on ``extract_embeddings.extract_embedding`` to obtain the embeddings. """ from typing import Tuple, Optional import numpy as np from PIL import Image from .extract_embeddings import extract_embedding def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float: """Compute the cosine similarity between two vectors. Parameters ---------- a, b: np.ndarray 1D vectors of the same length. Returns ------- float The cosine similarity ranging from -1 (opposite) to 1 (identical). """ return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))) def verify_images(img1: Image.Image, img2: Image.Image, threshold: float = 0.8, device: str = "cpu") -> Tuple[Optional[float], bool, str]: """Verify whether two images depict the same person. This function detects faces in each image, extracts embeddings and computes the cosine similarity. A threshold decides whether the similarity represents the same identity. Parameters ---------- img1, img2: PIL.Image.Image The two images to compare. threshold: float, optional Similarity threshold above which the faces are considered the same person. Defaults to 0.8. device: str, optional Device to run the embedding extraction on. Defaults to ``"cpu"``. Returns ------- Tuple[Optional[float], bool, str] A tuple of (similarity score, decision, message). If no face is detected in either image, the similarity is ``None`` and the decision is ``False``. """ emb1 = extract_embedding(img1, device=device) emb2 = extract_embedding(img2, device=device) if emb1 is None or emb2 is None: return None, False, "Face not detected in one or both images." sim = cosine_similarity(emb1, emb2) is_same = sim >= threshold return sim, is_same, "Same person" if is_same else "Different people" __all__ = ["verify_images", "cosine_similarity"]