|
|
""" |
|
|
Face Comparator - Comparaci贸n de embeddings con niveles de confianza adaptativos |
|
|
""" |
|
|
|
|
|
import numpy as np |
|
|
from sklearn.metrics.pairwise import cosine_similarity |
|
|
from loguru import logger |
|
|
|
|
|
|
|
|
class FaceComparator: |
|
|
""" |
|
|
Compara embeddings faciales con umbrales adaptativos. |
|
|
Implementa el sistema de 3 niveles: Seguro, Probable, Descartado. |
|
|
""" |
|
|
|
|
|
def __init__(self, threshold=0.75): |
|
|
""" |
|
|
Args: |
|
|
threshold: Umbral base de similitud (0.0-1.0) |
|
|
""" |
|
|
self.threshold = threshold |
|
|
|
|
|
|
|
|
self.SECURE_MATCH = 0.85 |
|
|
self.PROBABLE_MATCH = 0.72 |
|
|
|
|
|
|
|
|
def calculate_similarity(self, embedding1, embedding2): |
|
|
""" |
|
|
Calcula la similitud coseno entre dos embeddings. |
|
|
|
|
|
Args: |
|
|
embedding1: Vector de embedding 1 |
|
|
embedding2: Vector de embedding 2 |
|
|
|
|
|
Returns: |
|
|
Similitud entre 0.0 y 1.0 |
|
|
""" |
|
|
emb1 = np.array(embedding1).reshape(1, -1) |
|
|
emb2 = np.array(embedding2).reshape(1, -1) |
|
|
|
|
|
similarity = cosine_similarity(emb1, emb2)[0][0] |
|
|
|
|
|
return float(similarity) |
|
|
|
|
|
def verify_identity(self, source_emb, target_emb): |
|
|
""" |
|
|
Verifica identidad con an谩lisis de confianza adaptativo. |
|
|
|
|
|
Returns: |
|
|
Tupla (nivel_confianza: str, similitud: float) |
|
|
""" |
|
|
similarity = self.calculate_similarity(source_emb, target_emb) |
|
|
|
|
|
if similarity > self.SECURE_MATCH: |
|
|
confidence_level = "Match Seguro" |
|
|
logger.info(f"Match Seguro: {similarity:.3f}") |
|
|
elif similarity > self.PROBABLE_MATCH: |
|
|
confidence_level = "Coincidencia Probable (Requiere revisi贸n)" |
|
|
logger.info(f"Coincidencia Probable: {similarity:.3f}") |
|
|
else: |
|
|
confidence_level = "Descartado" |
|
|
logger.debug(f"Descartado: {similarity:.3f}") |
|
|
|
|
|
return confidence_level, similarity |
|
|
|
|
|
def compare_embeddings(self, query_embedding, candidate_results): |
|
|
""" |
|
|
Compara el embedding query con m煤ltiples candidatos. |
|
|
|
|
|
Args: |
|
|
query_embedding: Embedding de la imagen query |
|
|
candidate_results: Lista de resultados con embeddings |
|
|
|
|
|
Returns: |
|
|
Lista de matches verificados ordenados por similitud |
|
|
""" |
|
|
verified_matches = [] |
|
|
|
|
|
for candidate in candidate_results: |
|
|
if 'embedding' not in candidate: |
|
|
continue |
|
|
|
|
|
|
|
|
similarity = self.calculate_similarity( |
|
|
query_embedding, |
|
|
candidate['embedding'] |
|
|
) |
|
|
|
|
|
|
|
|
if similarity >= self.threshold: |
|
|
|
|
|
if similarity > self.SECURE_MATCH: |
|
|
confidence_level = "Match Seguro" |
|
|
elif similarity > self.PROBABLE_MATCH: |
|
|
confidence_level = "Coincidencia Probable" |
|
|
else: |
|
|
confidence_level = "Baja confianza" |
|
|
|
|
|
candidate['similarity'] = similarity |
|
|
candidate['confidence_level'] = confidence_level |
|
|
candidate['embedding_distance'] = 1 - similarity |
|
|
candidate['verified'] = True |
|
|
|
|
|
verified_matches.append(candidate) |
|
|
|
|
|
logger.debug(f"Match verificado: {similarity:.3f} - {confidence_level}") |
|
|
|
|
|
|
|
|
verified_matches.sort(key=lambda x: x['similarity'], reverse=True) |
|
|
|
|
|
logger.info(f"Comparaci贸n completada: {len(verified_matches)}/{len(candidate_results)} verificados") |
|
|
|
|
|
return verified_matches |
|
|
|