import numpy as np import cv2 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 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__)) _siamese_model = None _face_classifier = None def _load_siamese_model(device): global _siamese_model if _siamese_model is None: checkpoint = torch.load(current_path + '/siamese_model.t7', map_location=device) #model = SiameseV2().to(device) model = Siamese().to(device) model.load_state_dict(checkpoint['net_dict']) model.eval() _siamese_model = model return _siamese_model.to(device) def _load_face_classifier(): global _face_classifier if _face_classifier is None: classifier_path = current_path + '/face_classifier.joblib' print(f"Loading face classifier from: {classifier_path}") if not os.path.exists(classifier_path): return None try: _face_classifier = joblib.load(classifier_path) except Exception as exc: print(f"Failed to load face classifier: {exc}") return None return _face_classifier def _predict_face_class(classifier_artifact, embedding): if "prototypes" in classifier_artifact: prototypes = np.asarray(classifier_artifact["prototypes"], dtype=np.float32) classes = np.asarray(classifier_artifact["classes"]) distances = 1.0 - np.matmul(prototypes, embedding.astype(np.float32).T).reshape(-1) return classes[int(np.argmin(distances))] if "classifier" in classifier_artifact: return classifier_artifact["classifier"].predict(embedding)[0] if classifier_artifact.get("type") == "sklearn_mlp_weights": output = embedding.astype(np.float32) coefs = classifier_artifact["coefs"] intercepts = classifier_artifact["intercepts"] activation = classifier_artifact.get("activation", "relu") for layer_index, (weights, bias) in enumerate(zip(coefs, intercepts)): output = np.matmul(output, np.asarray(weights, dtype=np.float32)) output = output + np.asarray(bias, dtype=np.float32) is_hidden_layer = layer_index < len(coefs) - 1 if is_hidden_layer and activation == "relu": output = np.maximum(output, 0) elif is_hidden_layer and activation == "tanh": output = np.tanh(output) elif is_hidden_layer and activation == "logistic": output = 1 / (1 + np.exp(-output)) classes = np.asarray(classifier_artifact["classes"]) return classes[int(np.argmax(output, axis=1)[0])] embeddings = np.asarray(classifier_artifact["embeddings"], dtype=np.float32) labels = np.asarray(classifier_artifact["labels"]) distances = np.linalg.norm(embeddings - embedding.astype(np.float32), axis=1) return labels[int(np.argmin(distances))] #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) equalized = cv2.equalizeHist(gray) faces = [] for candidate_image in (gray, equalized): for scale_factor, min_neighbors in ( (1.05, 3), (1.08, 3), (1.1, 4), (1.1, 5), (1.2, 3), (1.3, 5), ): detected_faces = face_cascade.detectMultiScale( candidate_image, scaleFactor=scale_factor, minNeighbors=min_neighbors, minSize=(30, 30), ) faces.extend(detected_faces) 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).to(device) face2 = trnscm(det_img2).unsqueeze(0).to(device) ########################################################################################## ##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 + '/' is path of the saved model if present in ## ##the same path as this file, we recommend to put in the same directory ## ########################################################################################## ########################################################################################## feature_net = _load_siamese_model(device) with torch.no_grad(): output1, output2 = feature_net(face1, face2) output1 = F.normalize(output1, p=2, dim=1) output2 = F.normalize(output2, p=2, dim=1) distance = 1.0 - F.cosine_similarity(output1, output2) return distance.item() #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") det_img1 = detected_face(img1) if(det_img1 == 0): det_img1 = Image.fromarray(cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)) classifier_artifact = _load_face_classifier() if classifier_artifact is None: return "Classifier model not found" face1 = trnscm(det_img1).unsqueeze(0).to(device) feature_net = _load_siamese_model(device) with torch.no_grad(): embedding = feature_net.forward_once(face1) embedding = F.normalize(embedding, p=2, dim=1).cpu().numpy() prediction = _predict_face_class(classifier_artifact, embedding) return str(prediction)