martinbadrous's picture
Upload 6 files
4ded275 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"]