File size: 16,394 Bytes
e42e54d c8e2b5c 142ade6 6112eda c8e2b5c 57618ee 142ade6 4ff793f 02d08c9 142ade6 4ff793f 142ade6 e42e54d 142ade6 8f417cb 142ade6 02d08c9 142ade6 6112eda 142ade6 6112eda 4ff793f 142ade6 6112eda 142ade6 4ff793f 142ade6 4ff793f 142ade6 c8e2b5c 142ade6 e42e54d 142ade6 c8e2b5c 142ade6 c8e2b5c 142ade6 c8e2b5c 142ade6 02d08c9 142ade6 c8e2b5c 142ade6 c8e2b5c 142ade6 c8e2b5c 142ade6 c8e2b5c 142ade6 c8e2b5c 142ade6 4ff793f 142ade6 6112eda 4ff793f 142ade6 6112eda 4ff793f 6112eda 142ade6 6112eda 142ade6 4ff793f 142ade6 8f417cb 142ade6 4ff793f 142ade6 c8e2b5c 8f417cb e42e54d 8f417cb e42e54d c8e2b5c 142ade6 c8e2b5c e42e54d 8f417cb e42e54d 8f417cb e42e54d c8e2b5c 142ade6 e42e54d 142ade6 e42e54d 142ade6 6112eda 142ade6 6112eda 142ade6 6112eda 142ade6 6112eda 142ade6 6112eda 142ade6 e42e54d 142ade6 6112eda 142ade6 e42e54d 142ade6 e42e54d 142ade6 e42e54d 142ade6 6112eda 142ade6 6112eda 142ade6 e42e54d 142ade6 6112eda 142ade6 6112eda 142ade6 e42e54d 142ade6 e42e54d c8e2b5c 8f417cb 142ade6 e42e54d 142ade6 6112eda e42e54d 142ade6 e42e54d 142ade6 e42e54d 6112eda e42e54d 6112eda e42e54d 142ade6 e42e54d 142ade6 e42e54d c8e2b5c e42e54d 142ade6 57618ee e42e54d 142ade6 6112eda 142ade6 c8e2b5c 6112eda c8e2b5c 6112eda e42e54d c8e2b5c 6112eda | 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 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 | import gradio as gr
import sqlite3
import numpy as np
import cv2
from PIL import Image
import io
import os
# Global variable for FaceNet availability
FACE_NET_AVAILABLE = False
# Try to import FaceNet with error handling
try:
from facenet_pytorch import MTCNN, InceptionResnetV1
FACE_NET_AVAILABLE = True
print("β
FaceNet models imported successfully")
except ImportError as e:
print(f"β FaceNet import error: {e}")
FACE_NET_AVAILABLE = False
class FaceRecognitionSystem:
def __init__(self):
self.setup_database()
global FACE_NET_AVAILABLE
if FACE_NET_AVAILABLE:
try:
# Initialize MTCNN with simpler settings
self.mtcnn = MTCNN(
keep_all=False, # Only detect one face for simplicity
min_face_size=40,
thresholds=[0.6, 0.7, 0.7],
device='cpu'
)
self.resnet = InceptionResnetV1(pretrained='vggface2', classify=False, device='cpu').eval()
print("β
FaceNet models loaded successfully")
except Exception as e:
print(f"β Error loading FaceNet models: {e}")
FACE_NET_AVAILABLE = False
def setup_database(self):
"""Initialize SQLite database for students and attendance"""
self.conn = sqlite3.connect('face_attendance.db', check_same_thread=False)
self.cursor = self.conn.cursor()
# Students table with face embeddings
self.cursor.execute('''
CREATE TABLE IF NOT EXISTS students (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
student_id TEXT UNIQUE NOT NULL,
class TEXT,
face_embedding BLOB,
registration_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
# Attendance table
self.cursor.execute('''
CREATE TABLE IF NOT EXISTS attendance (
id INTEGER PRIMARY KEY AUTOINCREMENT,
student_id TEXT,
name TEXT,
class TEXT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
status TEXT DEFAULT 'Present'
)
''')
self.conn.commit()
print("β
Database initialized successfully")
def extract_face_embedding(self, image):
"""
Extract face embedding from image using FaceNet
"""
global FACE_NET_AVAILABLE
if not FACE_NET_AVAILABLE:
return None, "Face recognition not available"
try:
# Convert image to PIL format
if isinstance(image, str):
# File path
pil_image = Image.open(image).convert('RGB')
elif isinstance(image, np.ndarray):
# numpy array
if len(image.shape) == 3:
pil_image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
else:
return None, "Invalid image format"
else:
# Handle Gradio file object
pil_image = Image.open(image).convert('RGB')
# Detect face and get cropped face
face_tensor, prob = self.mtcnn(pil_image, return_prob=True)
if face_tensor is None:
return None, "No face detected in the image"
if prob < 0.9: # Confidence threshold
return None, "Low confidence face detection"
# Ensure proper tensor dimensions [3, 160, 160]
if face_tensor.dim() == 4:
face_tensor = face_tensor.squeeze(0) # Remove batch dimension if present
# Get embedding
with torch.no_grad():
embedding = self.resnet(face_tensor.unsqueeze(0)) # Add batch dimension
embedding_np = embedding.detach().numpy().flatten()
return embedding_np, "Face embedding extracted successfully"
except Exception as e:
return None, f"Error processing image: {str(e)}"
def register_student(self, name, student_id, class_name, image):
"""
Register a new student with face embedding
"""
if not name or not student_id:
return "β Please provide name and student ID"
if image is None:
return "β Please upload a face image"
# Extract face embedding
embedding, message = self.extract_face_embedding(image)
if embedding is None:
return f"β {message}"
# Store in database
try:
self.cursor.execute('''
INSERT INTO students (name, student_id, class, face_embedding)
VALUES (?, ?, ?, ?)
''', (name, student_id, class_name, embedding.tobytes()))
self.conn.commit()
return f"β
Student {name} registered successfully with face recognition!"
except sqlite3.IntegrityError:
return f"β Student ID {student_id} already exists"
except Exception as e:
return f"β Database error: {str(e)}"
def recognize_face(self, image):
"""
Recognize face from image and mark attendance
"""
global FACE_NET_AVAILABLE
if not FACE_NET_AVAILABLE:
return image, "Face recognition not available"
if image is None:
return None, "Please upload an image"
# Extract face embedding from input image
embedding, message = self.extract_face_embedding(image)
if embedding is None:
return image, f"β {message}"
# Get all registered students
self.cursor.execute('SELECT student_id, name, class, face_embedding FROM students')
students = self.cursor.fetchall()
if not students:
return image, "β No students registered in the system"
# Find the best match
best_match = None
min_distance = float('inf')
threshold = 1.0 # Similarity threshold
for student_id, name, class_name, embedding_blob in students:
known_embedding = np.frombuffer(embedding_blob, dtype=np.float32)
# Calculate Euclidean distance
distance = np.linalg.norm(embedding - known_embedding)
if distance < min_distance and distance < threshold:
min_distance = distance
best_match = (student_id, name, class_name, distance)
if best_match:
student_id, name, class_name, distance = best_match
# Check if already marked today
self.cursor.execute('''
SELECT * FROM attendance
WHERE student_id = ? AND DATE(timestamp) = DATE('now')
''', (student_id,))
existing = self.cursor.fetchone()
if not existing:
# Mark attendance
self.cursor.execute('''
INSERT INTO attendance (student_id, name, class, status)
VALUES (?, ?, ?, 'Present')
''', (student_id, name, class_name))
self.conn.commit()
result_message = f"β
Attendance marked for {name} (ID: {student_id})"
result_message += f"\nSimilarity: {1-distance:.3f}"
else:
result_message = f"β οΈ {name} already marked today (ID: {student_id})"
# Convert image for display
display_image = self.prepare_display_image(image)
# Add text to image
if display_image is not None:
cv2.putText(display_image, f"Recognized: {name}", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
cv2.putText(display_image, f"ID: {student_id}", (10, 60),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
cv2.putText(display_image, f"Class: {class_name}", (10, 90),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
cv2.putText(display_image, f"Similarity: {1-distance:.3f}", (10, 120),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
return display_image, result_message
return image, "β No matching student found"
def prepare_display_image(self, image):
"""Convert image to display format"""
try:
if isinstance(image, str):
display_image = cv2.imread(image)
elif isinstance(image, np.ndarray):
display_image = image.copy()
if len(display_image.shape) == 3 and display_image.shape[2] == 3:
display_image = cv2.cvtColor(display_image, cv2.COLOR_RGB2BGR)
else:
# Handle Gradio file object
display_image = np.array(Image.open(image))
if len(display_image.shape) == 3 and display_image.shape[2] == 3:
display_image = cv2.cvtColor(display_image, cv2.COLOR_RGB2BGR)
return display_image
except:
return None
def get_all_students(self):
"""Get all registered students"""
self.cursor.execute('SELECT name, student_id, class FROM students ORDER BY name')
students = self.cursor.fetchall()
return students
def get_attendance_records(self, time_range="Today"):
"""Get attendance records"""
if time_range == "Today":
self.cursor.execute('''
SELECT name, student_id, class, timestamp
FROM attendance
WHERE DATE(timestamp) = DATE('now')
ORDER BY timestamp DESC
''')
else:
self.cursor.execute('''
SELECT name, student_id, class, timestamp
FROM attendance
ORDER BY timestamp DESC
LIMIT 50
''')
return self.cursor.fetchall()
# Import torch after FaceNet imports to avoid conflicts
try:
import torch
except ImportError:
torch = None
# Initialize the system
face_system = FaceRecognitionSystem()
def register_student_interface(name, student_id, class_name, image):
return face_system.register_student(name, student_id, class_name, image)
def recognize_face_interface(image):
return face_system.recognize_face(image)
def view_students_interface():
students = face_system.get_all_students()
if not students:
return "No students registered yet"
result = "## π Registered Students\n\n"
for name, student_id, class_name in students:
result += f"**{name}**\n"
result += f"- ID: {student_id}\n"
result += f"- Class: {class_name}\n\n"
return result
def view_attendance_interface(time_range):
records = face_system.get_attendance_records(time_range)
if not records:
return f"No attendance records for {time_range.lower()}"
result = f"## π {time_range}'s Attendance\n\n"
for name, student_id, class_name, timestamp in records:
time_str = timestamp[:16] if timestamp else "Unknown"
result += f"**{name}** ({student_id})\n"
result += f"- Class: {class_name}\n"
result += f"- Time: {time_str}\n\n"
return result
# Create Gradio interface
with gr.Blocks(title="Face Recognition Attendance System") as demo:
gr.Markdown("# π― Face Recognition Attendance System")
gr.Markdown("AI-powered facial recognition for automated attendance marking")
with gr.Tab("π€ Register Student"):
gr.Markdown("### Register New Student with Face Recognition")
with gr.Row():
with gr.Column():
name_input = gr.Textbox(
label="Full Name",
placeholder="Enter student's full name"
)
student_id_input = gr.Textbox(
label="Student ID",
placeholder="Enter unique student ID"
)
class_input = gr.Textbox(
label="Class",
placeholder="Enter class name"
)
image_input = gr.Image(
label="Upload Face Image",
type="filepath"
)
register_btn = gr.Button("Register Student with Face", variant="primary")
with gr.Column():
register_output = gr.Textbox(
label="Registration Status",
lines=5
)
register_btn.click(
register_student_interface,
inputs=[name_input, student_id_input, class_input, image_input],
outputs=register_output
)
with gr.Tab("π· Mark Attendance"):
gr.Markdown("### Mark Attendance using Face Recognition")
with gr.Row():
with gr.Column():
attendance_image = gr.Image(
label="Upload Photo for Attendance",
type="filepath"
)
recognize_btn = gr.Button("Recognize Faces & Mark Attendance", variant="primary")
with gr.Column():
processed_image = gr.Image(
label="Processed Image"
)
recognition_output = gr.Textbox(
label="Recognition Results",
lines=4
)
recognize_btn.click(
recognize_face_interface,
inputs=[attendance_image],
outputs=[processed_image, recognition_output]
)
with gr.Tab("π View Records"):
gr.Markdown("### View Students and Attendance Records")
with gr.Row():
with gr.Column():
gr.Markdown("#### Registered Students")
students_btn = gr.Button("View All Students", variant="secondary")
students_output = gr.Markdown()
with gr.Column():
gr.Markdown("#### Attendance Records")
time_range = gr.Radio(
choices=["Today", "All Time"],
value="Today",
label="Select Time Range"
)
attendance_btn = gr.Button("View Attendance Records", variant="secondary")
attendance_output = gr.Markdown()
students_btn.click(view_students_interface, outputs=students_output)
attendance_btn.click(
view_attendance_interface,
inputs=[time_range],
outputs=attendance_output
)
with gr.Tab("βΉοΈ System Info"):
status_msg = "β
**System Status: FULLY OPERATIONAL**" if FACE_NET_AVAILABLE else "β οΈ **System Status: FACE RECOGNITION UNAVAILABLE**"
gr.Markdown(f"## System Status\n{status_msg}")
gr.Markdown("""
## About Face Recognition Attendance System
This system uses state-of-the-art facial recognition technology to automate attendance marking.
### Features:
- **Face Registration**: Register students with their facial data
- **Automatic Recognition**: Recognize students from photos and mark attendance
- **Attendance Management**: View and manage attendance records
### How to Use:
1. **Register Students**: Go to 'Register Student' tab, enter details and upload face photo
2. **Mark Attendance**: Go to 'Mark Attendance' tab, upload photo with faces
3. **View Records**: Check registered students and attendance records
### Technology:
- FaceNet for face recognition
- Gradio for web interface
- SQLite for data storage
""")
if __name__ == "__main__":
demo.launch() |