Spaces:
Sleeping
Sleeping
File size: 12,802 Bytes
66ff2bc e624310 66ff2bc b7c0340 e8d631e b7c0340 8406457 66ff2bc d6525d1 66ff2bc d6525d1 a99b378 66ff2bc e8d631e 66ff2bc e8d631e 01108cd e8d631e 66ff2bc e8d631e 66ff2bc e8d631e 66ff2bc d6525d1 66ff2bc e8d631e 66ff2bc e8d631e 66ff2bc e624310 d6525d1 e624310 d6525d1 e8d631e 01108cd e624310 e8d631e e624310 e8d631e e624310 3587bdb e624310 e8d631e e624310 e8d631e accaa5c e8d631e accaa5c e8d631e 3587bdb e8d631e 3587bdb 10afa34 e8d631e b7c0340 3587bdb e624310 e8d631e e624310 e8d631e e624310 d6525d1 e624310 e8d631e e624310 e8d631e d6525d1 e8d631e e624310 d6525d1 8b07f8e e8d631e 8b07f8e e624310 8b07f8e e8d631e 8b07f8e accaa5c 8b07f8e e8d631e 8b07f8e e8d631e 8b07f8e 01108cd 8b07f8e 66ff2bc e8d631e 66ff2bc e8d631e 66ff2bc e8d631e 01108cd e8d631e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | import numpy as np
import cv2
from matplotlib import pyplot as plt
import torch
# In the below line,remove '.' while working on your local system. However Make sure that '.' is present before face_recognition_model while uploading to the server, Do not remove it.
from .face_recognition_model import *
from PIL import Image
import base64
import io
import os
import joblib
import pickle
from sklearn.preprocessing import StandardScaler, normalize
# Add more imports if required
###########################################################################################################################################
# Caution: Don't change any of the filenames, function names and definitions #
# Always use the current_path + file_name for refering any files, without it we cannot access files on the server #
###########################################################################################################################################
# Current_path stores absolute path of the file from where it runs.
current_path = os.path.dirname(os.path.abspath(__file__))
# Simple error handling for missing models
def handle_missing_model(error_msg):
"""Helper function to handle missing model files"""
print(f"ERROR: {error_msg}")
return "Unknown"
#1) The below function is used to detect faces in the given image.
#2) It returns only one image which has maximum area out of all the detected faces in the photo.
#3) If no face is detected,then it returns zero(0).
def detected_face(image):
eye_haar = current_path + '/haarcascade_eye.xml'
face_haar = current_path + '/haarcascade_frontalface_default.xml'
face_cascade = cv2.CascadeClassifier(face_haar)
eye_cascade = cv2.CascadeClassifier(eye_haar)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
face_areas=[]
images = []
required_image = None
if len(faces) == 0:
return None
for i, (x,y,w,h) in enumerate(faces):
face_cropped = gray[y:y+h, x:x+w]
face_areas.append(w*h)
images.append(face_cropped)
if face_areas:
max_area_idx = np.argmax(face_areas)
required_image = images[max_area_idx]
required_image = Image.fromarray(required_image)
return required_image
return None
#1) Images captured from mobile is passed as parameter to the below function in the API call. It returns the similarity measure between given images.
#2) The image is passed to the function in base64 encoding, Code for decoding the image is provided within the function.
#3) Define an object to your siamese network here in the function and load the weight from the trained network, set it in evaluation mode.
#4) Get the features for both the faces from the network and return the similarity measure, Euclidean,cosine etc can be it. But choose the Relevant measure.
#5) For loading your model use the current_path+'your model file name', anyhow detailed example is given in comments to the function
#Caution: Don't change the definition or function name; for loading the model use the current_path for path example is given in comments to the function
def get_similarity(img1, img2):
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
det_img1 = detected_face(img1)
det_img2 = detected_face(img2)
if(det_img1 is None or det_img2 is None):
det_img1 = Image.fromarray(cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY))
det_img2 = Image.fromarray(cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY))
face1 = trnscm(det_img1).unsqueeze(0)
face2 = trnscm(det_img2).unsqueeze(0)
try:
# Load the Siamese model
model = SiameseNetwork().to(device)
model_path = current_path + '/siamese_model.t7'
if os.path.exists(model_path):
ckpt = torch.load(model_path, map_location=device)
model.load_state_dict(ckpt['net_dict'])
model.eval()
# Move tensors to device
face1 = face1.to(device)
face2 = face2.to(device)
# Get dissimilarity using Euclidean distance (same as notebook)
with torch.no_grad():
output1, output2 = model(face1, face2)
euclidean_distance = torch.nn.functional.pairwise_distance(output1, output2)
# Return raw distance as dissimilarity (lower = more similar)
dissimilarity = euclidean_distance.item()
return dissimilarity
else:
print(f"Model file not found: {model_path}")
return 0.0
except Exception as e:
print(f"Error in similarity calculation: {str(e)}")
return 0.0
#1) Image captured from mobile is passed as parameter to this function in the API call, It returns the face class in the string form ex: "Person1"
#2) The image is passed to the function in base64 encoding, Code to decode the image provided within the function
#3) Define an object to your network here in the function and load the weight from the trained network, set it in evaluation mode
#4) Perform necessary transformations to the input(detected face using the above function).
#5) Along with the siamese, you need the classifier as well, which is to be finetuned with the faces that you are training
##Caution: Don't change the definition or function name; for loading the model use the current_path for path example is given in comments to the function
def get_face_class(img1):
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(f"LOG: Using device: {device}")
det_img1 = detected_face(img1)
if(det_img1 is None):
det_img1 = Image.fromarray(cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY))
print("LOG: No face detected, using full image")
else:
print("LOG: Face detected successfully")
try:
# Load the Siamese model for feature extraction
model = SiameseNetwork().to(device)
model_path = current_path + '/siamese_model.t7'
print(f"LOG: Looking for model at: {model_path}")
print(f"LOG: Model file exists: {os.path.exists(model_path)}")
if os.path.exists(model_path):
ckpt = torch.load(model_path, map_location=device)
model.load_state_dict(ckpt['net_dict'])
model.eval()
print("LOG: Siamese model loaded successfully")
# Preprocess the image
face_tensor = trnscm(det_img1).unsqueeze(0).to(device)
print(f"LOG: Face tensor shape: {face_tensor.shape}")
# Extract features using Siamese network
with torch.no_grad():
features = model.forward_once(face_tensor)
features_np = features.cpu().numpy()
print(f"LOG: Extracted features shape: {features_np.shape}")
# Load the SVM classifier, scaler, and normalization flag
classifier_path = current_path + '/face_recognition_classifier.pkl'
scaler_path = current_path + '/face_recognition_scaler.pkl'
norm_flag_path = current_path + '/normalization_flag.pkl'
print(f"LOG: Looking for classifier files:")
print(f"LOG: Classifier: {os.path.exists(classifier_path)}")
print(f"LOG: Scaler: {os.path.exists(scaler_path)}")
print(f"LOG: Normalization flag: {os.path.exists(norm_flag_path)}")
# Load normalization flag (default to False if not found)
needs_normalization = False
if os.path.exists(norm_flag_path):
try:
with open(norm_flag_path, 'rb') as f:
needs_normalization = pickle.load(f)
print(f"LOG: Normalization flag loaded: {needs_normalization}")
except Exception as e:
print(f"WARN: Could not load normalization flag: {e}")
# Try to load the classifier
classifier = None
try:
if os.path.exists(classifier_path):
print("LOG: Loading SVM classifier...")
classifier = joblib.load(classifier_path)
print(f"LOG: SVM classifier loaded successfully")
print(f"LOG: Classifier type: {type(classifier).__name__}")
# Debug: Check the actual number of classes in the SVM
if hasattr(classifier, 'classes_'):
print(f"LOG: SVM trained classes: {classifier.classes_}")
print(f"LOG: Number of SVM classes: {len(classifier.classes_)}")
print(f"LOG: Class labels: {list(classifier.classes_)}")
else:
print("WARN: Classifier doesn't have classes_ attribute")
else:
print("ERROR: No classifier file found!")
return "Unknown"
except Exception as classifier_error:
print(f"ERROR: Failed to load classifier: {classifier_error}")
return handle_missing_model("Failed to load classifier")
if classifier is not None:
# Apply L2 normalization if needed
if needs_normalization:
print("LOG: Applying L2 normalization to features")
features_normalized = normalize(features_np, norm='l2')
else:
print("LOG: Using features without L2 normalization")
features_normalized = features_np
# Load and apply the scaler (only if it exists and is not None)
if os.path.exists(scaler_path):
scaler = joblib.load(scaler_path)
# Check if scaler is None (indicates it wasn't used during training)
if scaler is not None:
features_scaled = scaler.transform(features_normalized)
print("LOG: Features scaled using saved StandardScaler")
else:
features_scaled = features_normalized
print("LOG: StandardScaler not used (embeddings are L2 normalized)")
else:
print("WARN: Scaler file not found. Using unscaled features.")
features_scaled = features_normalized
# Make prediction (predict returns the class label, not the index into classes_)
predicted_label = int(classifier.predict(features_scaled)[0])
print(f"LOG: Predicted label: {predicted_label}")
# Get confidence scores if available; probabilities are aligned with classes_ indices
confidence = None
if hasattr(classifier, 'predict_proba'):
probabilities = classifier.predict_proba(features_scaled)[0]
if hasattr(classifier, 'classes_'):
try:
class_index = int(np.where(classifier.classes_ == predicted_label)[0][0])
except Exception as e:
print(f"WARN: Could not map label to classes_ index ({e}); using argmax as fallback")
class_index = int(np.argmax(probabilities))
else:
# Assume labels are 0..N-1 aligned with probability order
class_index = predicted_label if 0 <= predicted_label < len(probabilities) else int(np.argmax(probabilities))
confidence = float(probabilities[class_index])
print(f"LOG: Prediction confidence: {confidence:.3f} ({confidence*100:.1f}%)")
# Map predicted label to team member name
from .face_recognition_model import classes
predicted_class = classes[predicted_label]
if confidence is not None:
return f"{predicted_class} (confidence: {confidence:.3f})"
else:
return predicted_class
else:
print("ERROR: Failed to load classifier!")
return "Unknown"
else:
print(f"ERROR: Model file not found: {model_path}")
return "Unknown"
except Exception as e:
print(f"ERROR: Exception in face classification: {str(e)}")
import traceback
traceback.print_exc()
return "Unknown"
|