Python‑Based IoT Attendance System with 2D Face Recognition
This article describes a Python IoT attendance system that uses 2D face recognition for clock‑in/clock‑out, calculates attendance time, stores records in CSV files, and provides a PyQt5 graphical interface, detailing required environments, core code, and system limitations.
The project implements an IoT laboratory attendance system where personnel can sign in and out using 2D face recognition, calculate attendance duration, and save records as CSV files. The system avoids the complex training phase of deep‑learning face models, offering a lightweight and quick solution.
Key Features 1. Face‑based sign‑in/sign‑out 2. Attendance time calculation 3. CSV data export
Required Environment Core libraries: OpenCV‑Python 4.5.5.64, face_recognition 1.30 (with face_recognition_model 0.3.0), dlib 19.23.1. UI framework: PyQt5 5.15.4 (including pyqt5‑plugins, PyQt5‑Qt5, PyQt5‑sip, pyqt5‑tools). Development tools: PyCharm 2021.1.3, Python 3.9.12, Anaconda.
Core Code – MainWindow.py
class Ui_Dialog(QDialog):
def __init__(self):
super(Ui_Dialog, self).__init__()
loadUi("mainwindow.ui", self) # load QT UI file
self.runButton.clicked.connect(self.runSlot)
self._new_window = None
self.Videocapture_ = NoneCamera Invocation
def refreshAll(self):
print("Current camera index (0 = built‑in, 1 = USB):")
self.Videocapture_ = "0"Core Code – OutWindow.py (Time Display)
class Ui_OutputDialog(QDialog):
def __init__(self):
super(Ui_OutputDialog, self).__init__()
loadUi("./outputwindow.ui", self) # load output UI
now = QDate.currentDate()
current_date = now.toString('ddd dd MMMM yyyy')
current_time = datetime.datetime.now().strftime("%I:%M %p")
self.Date_Label.setText(current_date)
self.Time_Label.setText(current_time)Attendance Time Calculation
def ElapseList(self, name):
with open('Attendance.csv', "r") as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
line_count = 2
Time1 = datetime.datetime.now()
Time2 = datetime.datetime.now()
for row in csv_reader:
for field in row:
if field in row:
if field == 'Clock In' and row[0] == name:
Time1 = datetime.datetime.strptime(row[1], '%y/%m/%d %H:%M:%S')
self.TimeList1.append(Time1)
if field == 'Clock Out' and row[0] == name:
Time2 = datetime.datetime.strptime(row[1], '%y/%m/%d %H:%M:%S')
self.TimeList2.append(Time2)Face Recognition Process
# Face recognition part
faces_cur_frame = face_recognition.face_locations(frame)
encodes_cur_frame = face_recognition.face_encodings(frame, faces_cur_frame)
for encodeFace, faceLoc in zip(encodes_cur_frame, faces_cur_frame):
match = face_recognition.compare_faces(encode_list_known, encodeFace, tolerance=0.50)
face_dis = face_recognition.face_distance(encode_list_known, encodeFace)
name = "unknown"
best_match_index = np.argmin(face_dis)
if match[best_match_index]:
name = class_names[best_match_index].upper()
y1, x2, y2, x1 = faceLoc
cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv2.rectangle(frame, (x1, y2-20), (x2, y2), (0, 255, 0), cv2.FILLED)
cv2.putText(frame, name, (x1+6, y2-6), cv2.FONT_HERSHEY_COMPLEX, 0.5, (255,255,255), 1)
mark_attendance(name)
return frameCSV Data Saving and Sign‑In/Sign‑Out Logic
def mark_attendance(name):
if self.ClockInButton.isChecked():
self.ClockInButton.setEnabled(False)
with open('Attendance.csv', 'a') as f:
if name != 'unknown':
buttonReply = QMessageBox.question(self, 'Welcome ' + name, 'Start sign‑in', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if buttonReply == QMessageBox.Yes:
date_time_string = datetime.datetime.now().strftime("%y/%m/%d %H:%M:%S")
f.writelines(f'\n{name},{date_time_string},Clock In')
self.ClockInButton.setChecked(False)
self.NameLabel.setText(name)
self.StatusLabel.setText('Sign‑in')
self.HoursLabel.setText('Timing started')
self.Time1 = datetime.datetime.now()
self.ClockInButton.setEnabled(True)
else:
print('Sign‑in failed')
self.ClockInButton.setEnabled(True)
elif self.ClockOutButton.isChecked():
self.ClockOutButton.setEnabled(False)
with open('Attendance.csv', 'a') as f:
if name != 'unknown':
buttonReply = QMessageBox.question(self, 'Hi ' + name, 'Confirm sign‑out?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if buttonReply == QMessageBox.Yes:
date_time_string = datetime.datetime.now().strftime("%y/%m/%d %H:%M:%S")
f.writelines(f'\n{name},{date_time_string},Clock Out')
self.ClockOutButton.setChecked(False)
self.NameLabel.setText(name)
self.StatusLabel.setText('Sign‑out')
self.Time2 = datetime.datetime.now()
self.ElapseList(name)
self.TimeList2.append(datetime.datetime.now())
CheckInTime = self.TimeList1[-1]
CheckOutTime = self.TimeList2[-1]
self.ElapseHours = (CheckOutTime - CheckInTime)
self.MinLabel.setText(f"{abs(self.ElapseHours.total_seconds() / 60) % 60:.0f}m")
self.HoursLabel.setText(f"{abs(self.ElapseHours.total_seconds() / 3600):.0f}h")
self.ClockOutButton.setEnabled(True)
else:
print('Sign‑out failed')
self.ClockOutButton.setEnabled(True)The article also shows UI screenshots of the login screen, main interface, sign‑in/out displays, and backend CSV records, as well as the project directory structure. The concluding remarks note that the system lacks a trained face model, leading to higher mis‑recognition rates, high CPU usage, low frame rates, and limited data security due to CSV storage.
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.