Brightsun10 commited on
Commit
0a3f751
·
verified ·
1 Parent(s): 1b819c6

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +173 -0
  2. requirements.txt +7 -0
app.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ import cv2
4
+ import numpy as np
5
+ from PIL import Image
6
+ from facenet_pytorch import MTCNN, InceptionResnetV1
7
+ import os
8
+ import glob
9
+
10
+ # --- MODEL INITIALIZATION ---
11
+
12
+ # Check for GPU availability and set the device
13
+ device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
14
+ print(f'Running on device: {device}')
15
+
16
+ # Initialize MTCNN for face detection
17
+ # keep_all=True allows detection of multiple faces in a frame
18
+ mtcnn = MTCNN(
19
+ image_size=160, margin=14, min_face_size=20,
20
+ thresholds=[0.6, 0.7, 0.7], factor=0.709, post_process=True,
21
+ device=device, keep_all=True
22
+ )
23
+
24
+ # Initialize FaceNet (InceptionResnetV1) for face recognition
25
+ # Use a pre-trained model on VGGFace2 dataset
26
+ resnet = InceptionResnetV1(pretrained='vggface2', device=device).eval()
27
+
28
+ # --- FACE DATABASE SETUP ---
29
+
30
+ def build_face_database(directory):
31
+ """
32
+ Builds a database of known face embeddings from a directory of images.
33
+
34
+ Args:
35
+ directory (str): The path to the directory containing subdirectories of images,
36
+ where each subdirectory is named after the person.
37
+
38
+ Returns:
39
+ tuple: A tuple containing two lists:
40
+ - known_face_embeddings (list): A list of face embedding tensors.
41
+ - known_face_names (list): A list of corresponding names.
42
+ """
43
+ known_face_embeddings = []
44
+ known_face_names = []
45
+
46
+ if not os.path.exists(directory):
47
+ print(f"Database directory '{directory}' not found. Creating it.")
48
+ os.makedirs(directory)
49
+ return known_face_embeddings, known_face_names
50
+
51
+ # Iterate over each person in the directory
52
+ for person_name in os.listdir(directory):
53
+ person_dir = os.path.join(directory, person_name)
54
+ if not os.path.isdir(person_dir):
55
+ continue
56
+
57
+ # Find all image files for the person
58
+ image_files = glob.glob(os.path.join(person_dir, '*.jpg')) + \
59
+ glob.glob(os.path.join(person_dir, '*.png'))
60
+
61
+ for image_path in image_files:
62
+ try:
63
+ img = Image.open(image_path).convert('RGB')
64
+ # Detect face and get the face tensor
65
+ img_cropped = mtcnn(img)
66
+ if img_cropped is not None:
67
+ # Generate embedding
68
+ embedding = resnet(img_cropped.unsqueeze(0).to(device))
69
+ known_face_embeddings.append(embedding.detach().cpu())
70
+ known_face_names.append(person_name)
71
+ print(f"Processed {person_name} from {os.path.basename(image_path)}")
72
+ except Exception as e:
73
+ print(f"Error processing image {image_path}: {e}")
74
+
75
+ return known_face_embeddings, known_face_names
76
+
77
+ # Build the database from the 'known_faces' directory
78
+ # For Hugging Face Spaces, you can upload a zip file and unzip it,
79
+ # or add the folder to your repository.
80
+ known_embeddings, known_names = build_face_database('known_faces')
81
+ print(f"Loaded {len(known_names)} known faces.")
82
+
83
+ # --- REAL-TIME RECOGNITION FUNCTION ---
84
+
85
+ def recognize_faces(video_frame):
86
+ """
87
+ Performs face detection and recognition on a single video frame.
88
+
89
+ Args:
90
+ video_frame (np.ndarray): The input video frame from the webcam.
91
+
92
+ Returns:
93
+ np.ndarray: The video frame with bounding boxes and names drawn on it.
94
+ """
95
+ if video_frame is None:
96
+ return None
97
+
98
+ # Convert frame from BGR (OpenCV format) to RGB (PIL format)
99
+ frame_rgb = cv2.cvtColor(video_frame, cv2.COLOR_BGR2RGB)
100
+ img_pil = Image.fromarray(frame_rgb)
101
+
102
+ # Detect faces using MTCNN
103
+ boxes, _ = mtcnn.detect(img_pil)
104
+
105
+ # Get face embeddings for all detected faces in the frame
106
+ try:
107
+ # mtcnn() returns a tensor of cropped face images
108
+ face_tensors = mtcnn(img_pil)
109
+ if face_tensors is None:
110
+ # If no faces are detected, return the original frame
111
+ return video_frame
112
+
113
+ embeddings = resnet(face_tensors.to(device))
114
+ embeddings = embeddings.detach().cpu()
115
+ except Exception as e:
116
+ # This can happen if a face is detected but then fails processing
117
+ print(f"Could not get embeddings: {e}")
118
+ return video_frame
119
+
120
+ # Compare detected faces with the known faces database
121
+ if boxes is not None:
122
+ for i, box in enumerate(boxes):
123
+ embedding = embeddings[i]
124
+ min_dist = float('inf')
125
+ identity = "Unknown"
126
+
127
+ if known_embeddings:
128
+ # Calculate distances to all known faces
129
+ distances = [(embedding - known_emb).norm().item() for known_emb in known_embeddings]
130
+ min_dist = min(distances)
131
+
132
+ # Set a threshold for recognition
133
+ # This value may need tuning depending on your dataset
134
+ recognition_threshold = 0.8
135
+ if min_dist < recognition_threshold:
136
+ # Get the index of the closest match
137
+ min_dist_idx = distances.index(min_dist)
138
+ identity = known_names[min_dist_idx]
139
+
140
+ # Draw bounding box and name on the frame
141
+ x1, y1, x2, y2 = [int(b) for b in box]
142
+ color = (0, 255, 0) if identity != "Unknown" else (0, 0, 255) # Green for known, Red for unknown
143
+ cv2.rectangle(video_frame, (x1, y1), (x2, y2), color, 2)
144
+
145
+ # Prepare text label
146
+ label = f"{identity} ({min_dist:.2f})"
147
+
148
+ # Calculate text size to draw a solid background
149
+ (text_width, text_height), baseline = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.7, 2)
150
+ cv2.rectangle(video_frame, (x1, y2 - text_height - baseline), (x1 + text_width, y2), color, -1)
151
+ cv2.putText(video_frame, label, (x1, y2 - baseline), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
152
+
153
+ return video_frame
154
+
155
+ # --- GRADIO INTERFACE ---
156
+
157
+ # Define the Gradio interface
158
+ # inputs="webcam" creates a real-time video input component
159
+ # outputs="image" will display the processed video frames
160
+ iface = gr.Interface(
161
+ fn=recognize_faces,
162
+ inputs=gr.Image(sources=['webcam'], type="numpy", streaming=True),
163
+ outputs="image",
164
+ title="Advanced Real-Time Facial Recognition",
165
+ description="This application uses MTCNN for face detection and FaceNet for recognition. "
166
+ "It identifies known faces from a pre-built database. "
167
+ "To add a new person, create a folder with their name inside the 'known_faces' directory and add their pictures.",
168
+ live=True
169
+ )
170
+
171
+ # Launch the application
172
+ if __name__ == "__main__":
173
+ iface.launch(debug=True)
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ gradio
2
+ torch
3
+ torchvision
4
+ opencv-python-headless
5
+ facenet-pytorch
6
+ numpy
7
+ Pillow