martinbadrous's picture
Upload 11 files
8a4d3a7 verified
"""
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"]