| import numpy as np | |
| import cv2 | |
| from matplotlib import pyplot as plt | |
| import torch | |
| import torch.nn.functional as F | |
| # 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 .face_recognition_model import Siamese | |
| from PIL import Image | |
| import base64 | |
| import io | |
| import os | |
| import joblib | |
| import pickle | |
| # 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__)) | |
| #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=0 | |
| 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) | |
| required_image = images[np.argmax(face_areas)] | |
| required_image = Image.fromarray(required_image) | |
| return required_image | |
| #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 == 0 or det_img2 == 0): | |
| 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) | |
| ########################################################################################## | |
| ##Example for loading a model using weight state dictionary: ## | |
| ## feature_net = light_cnn() #Example Network ## | |
| ## model = torch.load(current_path + '/siamese_model.t7', map_location=device) ## | |
| ## feature_net.load_state_dict(model['net_dict']) ## | |
| ## ## | |
| ##current_path + '/<network_definition>' is path of the saved model if present in ## | |
| ##the same path as this file, we recommend to put in the same directory ## | |
| ########################################################################################## | |
| ########################################################################################## | |
| # YOUR CODE HERE, load the model | |
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") | |
| myModel = Siamese().to(device) | |
| BASE_DIR = os.path.dirname(os.path.abspath(__file__)) | |
| ckpt_path = os.path.join(BASE_DIR, "siamese_model.t7") | |
| ckpt = torch.load(ckpt_path, map_location=device) | |
| myModel.load_state_dict(ckpt['net_dict']) | |
| myModel.eval() | |
| # Forward pass | |
| with torch.no_grad(): | |
| output1, output2 = myModel(face1, face2) | |
| euclidean_distance = F.pairwise_distance(output1, output2) | |
| # YOUR CODE HERE, return similarity measure using your model | |
| euclidean_distance = F.pairwise_distance(output1, output2) | |
| similarity = 1 / (1 + euclidean_distance.item()) | |
| return similarity | |
| #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" if torch.cuda.is_available() else "cpu") | |
| BASE_DIR = os.path.dirname(os.path.abspath(__file__)) | |
| # 1 Load the Decision Tree classifier | |
| # clf_path = os.path.join(BASE_DIR, "decision_tree_model.sav") | |
| clf_path = os.path.join(BASE_DIR, "SVC_3.sav") | |
| clf = joblib.load(clf_path) | |
| scaler_path = os.path.join(BASE_DIR, "scaler.joblib") | |
| scaler = joblib.load(scaler_path) | |
| # 2 Load the Siamese feature extractor | |
| myModel = Siamese().to(device) | |
| ckpt_path = os.path.join(BASE_DIR, "siamese_model_1.t7") | |
| ckpt = torch.load(ckpt_path, map_location=device) | |
| myModel.load_state_dict(ckpt['net_dict']) | |
| myModel.eval() | |
| # myModel = myModel.float() | |
| # 3 Face detection (if available) | |
| # det_img1 = detected_face(img1) # returns cropped face or 0 if not detected | |
| # if det_img1 == 0: | |
| # # fallback: use original image | |
| # det_img1 = Image.fromarray(cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)) | |
| # 4 Transform the face | |
| img_tensor = transform1(img1).unsqueeze(0).to(device) | |
| # 5 Extract embeddings | |
| with torch.no_grad(): | |
| embedding = myModel.forward_once(img_tensor) | |
| embedding = embedding.view(embedding.size(0), -1).cpu().numpy() # shape (1, embedding_dim) | |
| # 6 Predict class using Decision Tree | |
| pred_label = clf.predict(scaler.transform(embedding))[0] | |
| # --- Predict --- | |
| # scaled_emb = scaler.transform(embedding) | |
| # probs = clf.predict_proba(scaled_emb) | |
| # pred_label = np.argmax(probs) | |
| # confidence = probs[0, pred_label] | |
| # 7 Optional: return class name (if available) | |
| # If you have the dataset available: | |
| # class_names = finalClassifierDset.classes | |
| # return class_names[pred_label] | |
| # class_names = ['Aayush', 'Aditya', 'Vikram'] | |
| # return class_names[pred_label] + " " + str(pred_label) | |
| class_names = ['Aayush', 'Aditya', 'Vikram'] | |
| return f"{class_names[pred_label]} {pred_label} {embedding}" | |
| # def get_face_class(img1): | |
| # | |
| # device = torch.device("cuda" if torch.cuda.is_available() else "cpu") | |
| # BASE_DIR = os.path.dirname(os.path.abspath(__file__)) | |
| # | |
| # # 1 Load the Decision Tree classifier | |
| # # clf_path = os.path.join(BASE_DIR, "decision_tree_model.sav") | |
| # clf_path = os.path.join(BASE_DIR, "SVC_3.sav") | |
| # clf = joblib.load(clf_path) | |
| # | |
| # scaler_path = os.path.join(BASE_DIR, "scaler.joblib") | |
| # scaler = joblib.load(scaler_path) | |
| # | |
| # # 2 Load the Siamese feature extractor | |
| # myModel = Siamese().to(device) | |
| # ckpt_path = os.path.join(BASE_DIR, "siamese_model.t7") | |
| # ckpt = torch.load(ckpt_path, map_location=device) | |
| # | |
| # myModel.load_state_dict(ckpt['net_dict']) | |
| # myModel.eval() | |
| # myModel = myModel.float() | |
| # | |
| # img_tensor = transform1(img1).unsqueeze(0).to(device).float() | |
| # | |
| # with torch.no_grad(): | |
| # embedding = myModel.forward_once(img_tensor) | |
| # embedding = embedding.view(embedding.size(0), -1).cpu().numpy() # shape (1, embedding_dim) | |
| # pred_label = clf.predict(scaler.transform(embedding))[0] | |
| # | |
| # class_names = ['Aayush', 'Aditya', 'Vikram'] | |
| # return f"{class_names[pred_label]} {pred_label} {embedding}" | |
| # def get_face_class(img1): | |
| # """ | |
| # img1: BGR image as numpy array (from cv2) OR path string accepted by detected_face. | |
| # Returns: "Name label_index" or debug info. | |
| # """ | |
| # | |
| # device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") | |
| # BASE_DIR = os.path.dirname(os.path.abspath(__file__)) | |
| # | |
| # # 1) Load classifier + scaler | |
| # clf_path = os.path.join(BASE_DIR, "logistic_regression_5.sav") | |
| # scaler_path = os.path.join(BASE_DIR, "standar_scaler.sav") | |
| # clf = joblib.load(clf_path) | |
| # scaler = joblib.load(scaler_path) | |
| # | |
| # # 2) Load Siamese feature extractor | |
| # myModel = Siamese().to(device) | |
| # ckpt_path = os.path.join(BASE_DIR, "siamese_model.t7") | |
| # ckpt = torch.load(ckpt_path, map_location=device) | |
| # myModel.load_state_dict(ckpt['net_dict']) | |
| # myModel.eval() | |
| # | |
| # # 3) Face detection & crop | |
| # det_img1 = detected_face(img1) # your function: should return cropped face (preferably PIL.Image or np.uint8) | |
| # if det_img1 == 0: | |
| # # fallback: convert original to grayscale PIL | |
| # if isinstance(img1, str): | |
| # pil_img = Image.open(img1).convert("L") | |
| # else: | |
| # # img1 assumed BGR numpy (cv2) | |
| # gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) | |
| # pil_img = Image.fromarray(gray) | |
| # det_img1 = pil_img | |
| # | |
| # # Ensure det_img1 is a PIL Image in mode 'L' (single channel). Convert if needed. | |
| # if isinstance(det_img1, np.ndarray): | |
| # # if it's color BGR -> convert to gray | |
| # if det_img1.ndim == 3 and det_img1.shape[2] == 3: | |
| # det_img1 = cv2.cvtColor(det_img1, cv2.COLOR_BGR2GRAY) | |
| # det_img1 = Image.fromarray(det_img1) | |
| # det_img1 = det_img1.convert("L") # enforce single-channel | |
| # | |
| # # 4) Transform the face: trnscm must be the exact same transform used when creating embeddings | |
| # img_tensor = trnscm(det_img1).unsqueeze(0) # shape: (1, C, H, W) | |
| # img_tensor = img_tensor.to(device) # <--- IMPORTANT: move to device! | |
| # | |
| # # 5) Extract embeddings | |
| # with torch.no_grad(): | |
| # embedding_t = myModel.forward_once(img_tensor) # tensor on device | |
| # embedding_t = embedding_t.view(embedding_t.size(0), -1) | |
| # embedding = embedding_t.cpu().numpy() # shape (1, embedding_dim) | |
| # | |
| # # Debug prints (uncomment if needed) | |
| # # print("embedding shape:", embedding.shape) | |
| # # print("embedding min/max:", embedding.min(), embedding.max()) | |
| # # print("embedding mean/std:", embedding.mean(), embedding.std()) | |
| # | |
| # # 6) Check for NaNs / inf | |
| # if np.isnan(embedding).any() or np.isinf(embedding).any(): | |
| # return "ERROR: embedding contains NaN or inf" | |
| # | |
| # # 7) Scale + predict | |
| # try: | |
| # scaled = scaler.transform(embedding) # ensure scaler expects shape (1, D) | |
| # except Exception as e: | |
| # return f"Scaler transform error: {e}" | |
| # | |
| # try: | |
| # pred_label = clf.predict(scaled)[0] | |
| # except Exception as e: | |
| # return f"Classifier predict error: {e}" | |
| # | |
| # # 8) Optional: probabilities (if classifier supports it) | |
| # confidence = None | |
| # if hasattr(clf, "predict_proba"): | |
| # try: | |
| # probs = clf.predict_proba(scaled) | |
| # confidence = float(probs.max()) | |
| # except Exception: | |
| # confidence = None | |
| # | |
| # # 9) Map to class names | |
| # class_names = ['Aayush', 'Aditya', 'Vikram'] # replace with your saved names or load from file | |
| # name = class_names[pred_label] if pred_label < len(class_names) else str(pred_label) | |
| # | |
| # if confidence is not None: | |
| # return f"{name} {pred_label} (conf={confidence:.3f})" | |
| # else: | |
| # return f"{name} {pred_label}" |