hackathon-group27 / app /Hackathon_setup /face_recognition.py
arbarikcp
group27-hackathon-first commit
a47c171
Raw
History Blame Contribute Delete
9.35 kB
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 + '/<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 ##
##########################################################################################
##########################################################################################
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)