Spaces:
Sleeping
Sleeping
| import cv2 | |
| import numpy as np | |
| import base64 | |
| def compare_faces(face1_base64, face2_base64, threshold=0.50): # Seuil plus haut | |
| """ | |
| Compare deux images de visages en base64 | |
| Retourne (is_match, score) | |
| """ | |
| try: | |
| # Décoder les images base64 | |
| if ',' in face1_base64: | |
| face1_bytes = base64.b64decode(face1_base64.split(',')[1]) | |
| else: | |
| face1_bytes = base64.b64decode(face1_base64) | |
| if ',' in face2_base64: | |
| face2_bytes = base64.b64decode(face2_base64.split(',')[1]) | |
| else: | |
| face2_bytes = base64.b64decode(face2_base64) | |
| # Convertir en images OpenCV | |
| nparr1 = np.frombuffer(face1_bytes, np.uint8) | |
| nparr2 = np.frombuffer(face2_bytes, np.uint8) | |
| img1 = cv2.imdecode(nparr1, cv2.IMREAD_COLOR) | |
| img2 = cv2.imdecode(nparr2, cv2.IMREAD_COLOR) | |
| if img1 is None or img2 is None: | |
| print("❌ Impossible de décoder les images") | |
| return False, 0 | |
| # Redimensionner | |
| img1 = cv2.resize(img1, (100, 100)) | |
| img2 = cv2.resize(img2, (100, 100)) | |
| # Convertir en gris | |
| gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) | |
| gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) | |
| # MÉTHODE 1: Corrélation croisée (POIDS FORT) | |
| try: | |
| result = cv2.matchTemplate(gray1, gray2, cv2.TM_CCOEFF_NORMED) | |
| corr_score = result[0][0] | |
| except: | |
| corr_score = 0.0 | |
| # MÉTHODE 2: MSE (Mean Squared Error) - moins de poids | |
| mse = np.mean((gray1.astype(float) - gray2.astype(float)) ** 2) | |
| max_mse = 255**2 | |
| mse_score = 1 - min(mse / max_mse, 1) | |
| # MÉTHODE 3: Différence structurelle (Sobel) - NOUVEAU | |
| sobel1 = cv2.Sobel(gray1, cv2.CV_64F, 1, 1, ksize=5) | |
| sobel2 = cv2.Sobel(gray2, cv2.CV_64F, 1, 1, ksize=5) | |
| sobel_diff = np.mean(np.abs(sobel1 - sobel2)) | |
| sobel_score = 1 - min(sobel_diff / 1000, 1) | |
| # MÉTHODE 4: Histogrammes (poids FAIBLE car sensible aux couleurs) | |
| hist1 = cv2.calcHist([gray1], [0], None, [256], [0, 256]) | |
| hist2 = cv2.calcHist([gray2], [0], None, [256], [0, 256]) | |
| hist_score = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CORREL) | |
| hist_score = max(0, min(1, hist_score)) | |
| # NOUVEAU: Détection de visage pour vérifier | |
| face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml') | |
| faces1 = face_cascade.detectMultiScale(gray1, 1.1, 4) | |
| faces2 = face_cascade.detectMultiScale(gray2, 1.1, 4) | |
| is_face1 = len(faces1) > 0 | |
| is_face2 = len(faces2) > 0 | |
| # Score combiné avec NOUVEAUX POIDS | |
| # On donne plus de poids à la corrélation et à Sobel (forme) | |
| # Moins de poids aux histogrammes (couleur) | |
| final_score = (corr_score * 0.5 + mse_score * 0.1 + sobel_score * 0.3 + hist_score * 0.1) | |
| # Pénalité si ce n'est pas un visage | |
| if not is_face1 or not is_face2: | |
| final_score *= 0.5 | |
| print("⚠️ Image non faciale détectée - score réduit") | |
| print(f"📊 Scores - Corr: {corr_score:.2%}, MSE: {mse_score:.2%}, Sobel: {sobel_score:.2%}, Hist: {hist_score:.2%}") | |
| print(f"📈 Score final: {final_score:.2%}") | |
| return final_score > threshold, final_score | |
| except Exception as e: | |
| print(f"❌ Erreur comparaison: {e}") | |
| import traceback | |
| traceback.print_exc() | |
| return False, 0 |