Kousik Kumar Siddavaram commited on
Commit
dcb23aa
·
1 Parent(s): 4730a0e

Updated face recognition python files

Browse files
app/Hackathon_setup/face_recognition.py CHANGED
@@ -8,12 +8,17 @@ import os
8
  import joblib
9
  import torch.nn.functional as F
10
 
 
11
  # Current_path stores absolute path of the file from where it runs.
12
  current_path = os.path.dirname(os.path.abspath(__file__))
13
 
 
 
 
14
  # -------------------------
15
  # Load trained classifier and label encoder
16
  # -------------------------
 
17
  clf_path = os.path.join(current_path, "team_classifier.joblib")
18
  le_path = os.path.join(current_path, "label_encoder.joblib")
19
  clf = joblib.load(clf_path)
@@ -23,22 +28,29 @@ le = joblib.load(le_path)
23
  # Face Detection
24
  # -------------------------
25
  def detected_face(image):
 
 
 
 
26
  eye_haar = current_path + '/haarcascade_eye.xml'
27
  face_haar = current_path + '/haarcascade_frontalface_default.xml'
28
  face_cascade = cv2.CascadeClassifier(face_haar)
29
- eye_cascade = cv2.CascadeClassifier(eye_haar)
30
  gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
31
- faces = face_cascade.detectMultiScale(gray, 1.3, 5)
32
- face_areas = []
33
- images = []
34
- required_image = 0
35
- for i, (x, y, w, h) in enumerate(faces):
36
- face_cropped = gray[y:y+h, x:x+w]
37
- face_areas.append(w*h)
38
- images.append(face_cropped)
39
- required_image = images[np.argmax(face_areas)]
40
- required_image = Image.fromarray(required_image)
41
- return required_image
 
 
 
42
 
43
  # -------------------------
44
  # Compute Similarity
@@ -47,16 +59,19 @@ def get_similarity(img1, img2):
47
  # Detect faces
48
  det_img1 = detected_face(img1)
49
  det_img2 = detected_face(img2)
50
- if det_img1 == 0 or det_img2 == 0:
 
 
51
  det_img1 = Image.fromarray(cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY))
 
52
  det_img2 = Image.fromarray(cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY))
53
 
54
  # Transform images
55
  face1 = trnscm(det_img1).unsqueeze(0).to(device)
56
  face2 = trnscm(det_img2).unsqueeze(0).to(device)
57
 
58
- # Load Siamese model
59
- model_path = current_path + '/siamese_model.t7'
60
  checkpoint = torch.load(model_path, map_location=device)
61
  feature_net = Siamese().to(device)
62
  feature_net.load_state_dict(checkpoint['net_dict'])
@@ -76,22 +91,23 @@ def get_similarity(img1, img2):
76
  def get_face_class(img1):
77
  # Detect face
78
  det_img1 = detected_face(img1)
 
79
  if det_img1 == 0:
80
  det_img1 = Image.fromarray(cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY))
81
 
82
  # Transform image
83
  face = trnscm(det_img1).unsqueeze(0).to(device)
84
 
85
- # Load Siamese model
86
- model_path = current_path + '/siamese_model.t7'
87
  checkpoint = torch.load(model_path, map_location=device)
88
  feature_net = Siamese().to(device)
89
  feature_net.load_state_dict(checkpoint['net_dict'])
90
  feature_net.eval()
91
 
92
- # Get embedding
93
  with torch.no_grad():
94
- embedding = feature_net.forward_once(face)
95
  embedding_np = embedding.cpu().numpy()
96
 
97
  # Predict class using trained classifier
 
8
  import joblib
9
  import torch.nn.functional as F
10
 
11
+
12
  # Current_path stores absolute path of the file from where it runs.
13
  current_path = os.path.dirname(os.path.abspath(__file__))
14
 
15
+ # Define the new model path constant for clarity
16
+ SIAMESE_MODEL_FILENAME = 'face_recognition_model.t7'
17
+
18
  # -------------------------
19
  # Load trained classifier and label encoder
20
  # -------------------------
21
+ # NOTE: Ensure 'team_classifier.joblib' is retrained on 80,000 features!
22
  clf_path = os.path.join(current_path, "team_classifier.joblib")
23
  le_path = os.path.join(current_path, "label_encoder.joblib")
24
  clf = joblib.load(clf_path)
 
28
  # Face Detection
29
  # -------------------------
30
  def detected_face(image):
31
+ """
32
+ Detects faces in the image and returns the largest detected face (PIL Image).
33
+ Returns 0 if no face is detected.
34
+ """
35
  eye_haar = current_path + '/haarcascade_eye.xml'
36
  face_haar = current_path + '/haarcascade_frontalface_default.xml'
37
  face_cascade = cv2.CascadeClassifier(face_haar)
38
+
39
  gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
40
+ faces = face_cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5)
41
+
42
+ if len(faces) == 0:
43
+ return 0 # No face detected
44
+
45
+ # Select the face with the largest area
46
+ face_areas = [w * h for (x, y, w, h) in faces]
47
+ max_idx = np.argmax(face_areas)
48
+ x, y, w, h = faces[max_idx]
49
+
50
+ # Crop the largest face
51
+ face_cropped = gray[y:y + h, x:x + w]
52
+ return Image.fromarray(face_cropped)
53
+
54
 
55
  # -------------------------
56
  # Compute Similarity
 
59
  # Detect faces
60
  det_img1 = detected_face(img1)
61
  det_img2 = detected_face(img2)
62
+
63
+ # Fallback to entire image if no face detected
64
+ if det_img1 == 0:
65
  det_img1 = Image.fromarray(cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY))
66
+ if det_img2 == 0:
67
  det_img2 = Image.fromarray(cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY))
68
 
69
  # Transform images
70
  face1 = trnscm(det_img1).unsqueeze(0).to(device)
71
  face2 = trnscm(det_img2).unsqueeze(0).to(device)
72
 
73
+ # Load Siamese model (Updated filename)
74
+ model_path = os.path.join(current_path, SIAMESE_MODEL_FILENAME)
75
  checkpoint = torch.load(model_path, map_location=device)
76
  feature_net = Siamese().to(device)
77
  feature_net.load_state_dict(checkpoint['net_dict'])
 
91
  def get_face_class(img1):
92
  # Detect face
93
  det_img1 = detected_face(img1)
94
+
95
  if det_img1 == 0:
96
  det_img1 = Image.fromarray(cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY))
97
 
98
  # Transform image
99
  face = trnscm(det_img1).unsqueeze(0).to(device)
100
 
101
+ # Load Siamese model (Updated filename)
102
+ model_path = os.path.join(current_path, SIAMESE_MODEL_FILENAME)
103
  checkpoint = torch.load(model_path, map_location=device)
104
  feature_net = Siamese().to(device)
105
  feature_net.load_state_dict(checkpoint['net_dict'])
106
  feature_net.eval()
107
 
108
+ # Get embedding (CRITICAL FIX: Use extract_features for classification)
109
  with torch.no_grad():
110
+ embedding = feature_net.extract_features(face) # <--- FIX APPLIED HERE
111
  embedding_np = embedding.cpu().numpy()
112
 
113
  # Predict class using trained classifier
app/Hackathon_setup/face_recognition_model.py CHANGED
@@ -5,16 +5,20 @@ import torch.nn as nn
5
  import torch.nn.functional as F
6
  from torchvision import transforms
7
 
 
8
  # ---------------------------
9
  # Device configuration
10
  # ---------------------------
 
11
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
12
 
13
  # ---------------------------
14
  # Transformation Function
15
  # ---------------------------
16
- # Same transforms as used during training in Colab
17
  trnscm = transforms.Compose([
 
 
18
  transforms.Resize((100, 100)),
19
  transforms.ToTensor()
20
  ])
@@ -26,7 +30,7 @@ class Siamese(nn.Module):
26
  def __init__(self):
27
  super(Siamese, self).__init__()
28
 
29
- # CNN layers (same as your Colab model)
30
  self.cnn1 = nn.Sequential(
31
  nn.ReflectionPad2d(1),
32
  nn.Conv2d(1, 4, kernel_size=3),
@@ -44,35 +48,44 @@ class Siamese(nn.Module):
44
  nn.BatchNorm2d(8)
45
  )
46
 
47
- # Fully connected layers
 
48
  self.fc1 = nn.Sequential(
49
  nn.Linear(8 * 100 * 100, 500),
50
  nn.ReLU(inplace=True),
51
  nn.Linear(500, 500),
52
  nn.ReLU(inplace=True),
53
- nn.Linear(500, 5)
54
  )
55
 
 
56
  def forward_once(self, x):
57
- # Forward pass for one image
58
  output = self.cnn1(x)
59
  output = output.view(output.size(0), -1)
60
  output = self.fc1(output)
61
  return output
 
 
 
 
 
 
 
 
 
 
 
62
 
63
  def forward(self, x1, x2):
64
- # Forward pass for both images
65
  output1 = self.forward_once(x1)
66
  output2 = self.forward_once(x2)
67
  return output1, output2
68
 
69
  ##########################################################################################################
70
- ## Classifier for face recognition
71
- ## Not used for face similarity; now we use a Sklearn classifier separately
72
  ##########################################################################################################
73
- classifier = None # Keep as None; we use joblib-loaded Sklearn model in facerecognition.py
74
 
75
- # ---------------------------
76
  # Class labels (optional, for reference)
77
- # ---------------------------
78
  classes = ['person1', 'person2', 'person3', 'person4', 'person5', 'person6', 'person7']
 
5
  import torch.nn.functional as F
6
  from torchvision import transforms
7
 
8
+
9
  # ---------------------------
10
  # Device configuration
11
  # ---------------------------
12
+ # Use GPU if available, otherwise fall back to CPU
13
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
14
 
15
  # ---------------------------
16
  # Transformation Function
17
  # ---------------------------
18
+ # This pipeline must match the transforms used during Siamese training.
19
  trnscm = transforms.Compose([
20
+ # Crucial: Ensures 1-channel input for the CNN backbone
21
+ transforms.Grayscale(num_output_channels=1),
22
  transforms.Resize((100, 100)),
23
  transforms.ToTensor()
24
  ])
 
30
  def __init__(self):
31
  super(Siamese, self).__init__()
32
 
33
+ # CNN layers (Feature Extractor)
34
  self.cnn1 = nn.Sequential(
35
  nn.ReflectionPad2d(1),
36
  nn.Conv2d(1, 4, kernel_size=3),
 
48
  nn.BatchNorm2d(8)
49
  )
50
 
51
+ # Fully connected layers (Metric Head for Siamese Loss)
52
+ # Output size is 8 * 100 * 100 = 80,000 features before first Linear layer
53
  self.fc1 = nn.Sequential(
54
  nn.Linear(8 * 100 * 100, 500),
55
  nn.ReLU(inplace=True),
56
  nn.Linear(500, 500),
57
  nn.ReLU(inplace=True),
58
+ nn.Linear(500, 5) # Final 5-dimensional embedding
59
  )
60
 
61
+ # Method to return the final low-dimensional embedding (used for similarity)
62
  def forward_once(self, x):
 
63
  output = self.cnn1(x)
64
  output = output.view(output.size(0), -1)
65
  output = self.fc1(output)
66
  return output
67
+
68
+ # Method to return the high-dimensional features (used for classification)
69
+ def extract_features(self, x):
70
+ """
71
+ Returns the raw, high-dimensional features (80,000) from the CNN backbone.
72
+ This output is what the Gradient Boosting Classifier (team_classifier.joblib) expects.
73
+ """
74
+ output = self.cnn1(x)
75
+ # Flatten the output: 8 channels * 100 height * 100 width = 80,000 features
76
+ output = output.view(output.size(0), -1)
77
+ return output
78
 
79
  def forward(self, x1, x2):
80
+ # Forward pass for similarity comparison
81
  output1 = self.forward_once(x1)
82
  output2 = self.forward_once(x2)
83
  return output1, output2
84
 
85
  ##########################################################################################################
86
+ ## Utility Variables
 
87
  ##########################################################################################################
88
+ classifier = None # Placeholder. The actual classifier is loaded via joblib in face_recognition.py
89
 
 
90
  # Class labels (optional, for reference)
 
91
  classes = ['person1', 'person2', 'person3', 'person4', 'person5', 'person6', 'person7']