File size: 7,639 Bytes
c93aa7f
 
 
 
 
 
 
 
 
 
1d2dca4
 
 
 
 
 
c93aa7f
 
 
 
 
 
 
 
 
efae1c1
c93aa7f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e4fc860
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c93aa7f
 
1d2dca4
e4fc860
 
 
 
1d2dca4
e4fc860
 
ea45513
e4fc860
 
 
 
ea45513
 
e4fc860
 
ea45513
 
1d2dca4
 
 
e4fc860
648876d
 
 
1d2dca4
e4fc860
1d2dca4
 
c93aa7f
e4fc860
1d2dca4
 
 
 
 
 
 
 
c93aa7f
e4fc860
c93aa7f
 
1d2dca4
e4fc860
1d2dca4
 
 
 
e4fc860
efae1c1
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
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 .exp_recognition_model import *
from PIL import Image
import base64
import io
import os
import torch
import torch.nn as nn
from torchvision import models
import torchvision.transforms as transforms
import torch.nn.functional as F

## 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__))
classes = {0: 'ANGER', 1: 'DISGUST', 2: 'FEAR', 3: 'HAPPINESS', 4: 'NEUTRAL', 5: 'SADNESS', 6: 'SURPRISE'}


#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 Expression detected by your network.
#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 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), this should return the Expression in string form ex: "Anger"
#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_expression(img):
#     device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#
#     # Recreate the same model architecture
#     num_classes = 7  # 👈 change this to match your training setup
#
#     model = models.resnet18(weights=None)
#     model.conv1 = nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3, bias=False)
#     # no pretrained weights now
#     model.fc = nn.Sequential(
#         nn.Linear(model.fc.in_features, 256),
#         nn.ReLU(inplace=True),
#         nn.Linear(256, num_classes)
#     )
#
#     model = model.to(device)
#
#     # Create the optimizer (same as training)
#     optimizer = torch.optim.Adam(model.parameters(), lr=0.0001)
#
#     # Load the checkpoint
#     BASE_DIR = os.path.dirname(os.path.abspath(__file__))
#     ckpt_path = os.path.join(BASE_DIR, "expression_model.t7")
#     checkpoint = torch.load(ckpt_path, map_location=device)
#
#     # Restore weights and optimizer
#     model.load_state_dict(checkpoint['model_state_dict'])
#     optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
#
#     # Put the model in evaluation mode
#     model.eval()
#
#     ##########################################################################################
#     ##Example for loading a model using weight state dictionary:                            ##
#     ## face_det_net = facExpRec() #Example Network                                          ##
#     ## model = torch.load(current_path + '/exp_recognition_net.t7', map_location=device)    ##
#     ## face_det_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                 ##
#     ##########################################################################################
#     ##########################################################################################
#
#     transform = transforms.Compose([
#         transforms.Grayscale(num_output_channels=1),
#         transforms.Resize(256),
#         transforms.CenterCrop(224),
#         transforms.ToTensor(),
#         transforms.Normalize(mean=[0.5], std=[0.5])
#     ])
#
#     face = detected_face(img)
#     if face==0:
#         face = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY))
#
#     face = transform(face).unsqueeze(0).to(device)
#     # YOUR CODE HERE, return expression using your model
#     with torch.no_grad():
#         outputs = model(face)
#         probs = F.softmax(outputs, dim=1)
#         predicted_class = probs.argmax(dim=1).item()
#     return predicted_class


def get_expression(img):
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

    num_classes = 7  # update as per your dataset

    # Recreate exact same architecture as training
    model = models.resnet18(weights=models.ResNet18_Weights.IMAGENET1K_V1)

    # Convert first conv layer to accept 1 channel (grayscale)
    pretrained_conv = model.conv1.weight
    model.conv1 = nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3, bias=False)
    with torch.no_grad():
        model.conv1.weight = nn.Parameter(pretrained_conv.mean(dim=1, keepdim=True))

    # Fully connected head (same as training)
    model.fc = nn.Sequential(
        nn.Linear(model.fc.in_features, 256),
        nn.ReLU(),
        nn.Dropout(0.5),
        nn.Linear(256, num_classes)
    )

    model = model.to(device)

    # Load checkpoint
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))
    ckpt_path = os.path.join(BASE_DIR, "expression_model.t7")
    checkpoint = torch.load(ckpt_path, map_location=device)

    # Restore weights (no need for optimizer if inference-only)
    model.load_state_dict(checkpoint['model_state_dict'])
    model.eval()

    # Preprocessing pipeline
    transform = transforms.Compose([
        transforms.Grayscale(num_output_channels=1),
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.5], std=[0.5])
    ])

    face = detected_face(img)
    if face == 0:
        face = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY))

    face = transform(face).unsqueeze(0).to(device)

    with torch.no_grad():
        outputs = model(face)
        probs = F.softmax(outputs, dim=1)
        predicted_class = probs.argmax(dim=1).item()

    return classes[predicted_class]