Spaces:
Runtime error
Runtime error
Upload attendance_system.py
Browse files- attendance_system.py +86 -0
attendance_system.py
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import logging
|
3 |
+
from typing import List, Tuple, Optional
|
4 |
+
|
5 |
+
import face_recognition
|
6 |
+
import numpy as np
|
7 |
+
|
8 |
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
9 |
+
|
10 |
+
class AttendanceSystem:
|
11 |
+
def __init__(self, database_dir: str):
|
12 |
+
self.database_dir = database_dir
|
13 |
+
self.database = self._load_database()
|
14 |
+
|
15 |
+
def _load_database(self) -> dict:
|
16 |
+
database = {}
|
17 |
+
for filename in os.listdir(self.database_dir):
|
18 |
+
if filename.endswith(('.jpg', '.jpeg', '.png')):
|
19 |
+
roll_number = os.path.splitext(filename)[0]
|
20 |
+
image_path = os.path.join(self.database_dir, filename)
|
21 |
+
try:
|
22 |
+
image = face_recognition.load_image_file(image_path)
|
23 |
+
encodings = face_recognition.face_encodings(image)
|
24 |
+
if encodings:
|
25 |
+
database[roll_number] = encodings[0]
|
26 |
+
else:
|
27 |
+
logging.warning(f"No face found in {filename}. Skipping.")
|
28 |
+
except Exception as e:
|
29 |
+
logging.error(f"Error processing {filename}: {str(e)}")
|
30 |
+
return database
|
31 |
+
|
32 |
+
def process_classroom_image(self, image_path: str) -> List[Tuple[str, float]]:
|
33 |
+
try:
|
34 |
+
classroom_image = face_recognition.load_image_file(image_path)
|
35 |
+
except Exception as e:
|
36 |
+
logging.error(f"Error loading classroom image: {str(e)}")
|
37 |
+
return []
|
38 |
+
|
39 |
+
face_locations = face_recognition.face_locations(classroom_image)
|
40 |
+
if not face_locations:
|
41 |
+
logging.warning("No faces detected in the classroom image.")
|
42 |
+
return []
|
43 |
+
|
44 |
+
face_encodings = face_recognition.face_encodings(classroom_image, face_locations)
|
45 |
+
|
46 |
+
matches = []
|
47 |
+
for face_encoding in face_encodings:
|
48 |
+
match = self._find_best_match(face_encoding)
|
49 |
+
if match:
|
50 |
+
matches.append(match)
|
51 |
+
|
52 |
+
return matches
|
53 |
+
|
54 |
+
def _find_best_match(self, face_encoding: np.ndarray) -> Optional[Tuple[str, float]]:
|
55 |
+
best_match = None
|
56 |
+
best_distance = float('inf')
|
57 |
+
for roll_number, known_encoding in self.database.items():
|
58 |
+
distance = face_recognition.face_distance([known_encoding], face_encoding)[0]
|
59 |
+
if distance < best_distance:
|
60 |
+
best_distance = distance
|
61 |
+
best_match = (roll_number, distance)
|
62 |
+
|
63 |
+
if best_match and best_match[1] < 0.6: # Adjust this threshold as needed
|
64 |
+
return best_match
|
65 |
+
return None
|
66 |
+
|
67 |
+
def record_attendance(self, course: str, date: str, classroom_image_path: str) -> List[str]:
|
68 |
+
matches = self.process_classroom_image(classroom_image_path)
|
69 |
+
present_students = [roll_number for roll_number, _ in matches]
|
70 |
+
logging.info(f"Recorded attendance for {len(present_students)} students in {course} on {date}")
|
71 |
+
return present_students
|
72 |
+
|
73 |
+
def add_to_database(self, roll_number: str, image_path: str) -> bool:
|
74 |
+
try:
|
75 |
+
image = face_recognition.load_image_file(image_path)
|
76 |
+
encodings = face_recognition.face_encodings(image)
|
77 |
+
if encodings:
|
78 |
+
self.database[roll_number] = encodings[0]
|
79 |
+
logging.info(f"Added {roll_number} to the database successfully.")
|
80 |
+
return True
|
81 |
+
else:
|
82 |
+
logging.warning(f"No face found in the image for {roll_number}. Not added to database.")
|
83 |
+
return False
|
84 |
+
except Exception as e:
|
85 |
+
logging.error(f"Error adding {roll_number} to database: {str(e)}")
|
86 |
+
return False
|