import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import cv2 as cv
import os
import numpy as np
from [Link] import MTCNN
from keras_facenet import FaceNet
from [Link] import LabelEncoder
from [Link] import SVC
from sklearn.model_selection import train_test_split
from [Link] import accuracy_score
import pickle
import uuid
import time
import shutil
import csv
class StudentDataApp([Link]):
def __init__(self):
super().__init__()
[Link]("Student Data Entry & Recognition")
[Link]("800x600")
# Initialize face recognition components
[Link] = MTCNN()
[Link] = FaceNet()
[Link] = LabelEncoder()
[Link] = None # Placeholder for SVM model
# Initialize image paths
self.image_paths = []
# Load existing face embeddings and labels
self.load_existing_data()
# Create Tab Control
self.tab_control = [Link](self)
# Create Tabs
self.data_entry_tab = [Link](self.tab_control)
self.attendance_tab = [Link](self.tab_control)
# Add Tabs to Tab Control
self.tab_control.add(self.data_entry_tab, text='Data Entry')
self.tab_control.add(self.attendance_tab, text='Attendance')
# Pack Tab Control
self.tab_control.pack(expand=1, fill='both')
# Initialize UI for Data Entry Tab
self.init_data_entry_ui()
# Initialize UI for Attendance Tab
self.init_attendance_ui()
def enable_train_if_dataset_exists(self):
DATASET_PATH = "dataset"
if [Link](DATASET_PATH) and any([Link](DATASET_PATH)):
self.train_button.config(state=[Link])
def init_data_entry_ui(self):
# ID Label and Entry
self.label_id = [Link](self.data_entry_tab, text="Student ID:")
self.label_id.pack(pady=5)
self.entry_id = [Link](self.data_entry_tab)
self.entry_id.pack(pady=5)
# Name Label and Entry
self.label_name = [Link](self.data_entry_tab, text="Student Name:")
self.label_name.pack(pady=5)
self.entry_name = [Link](self.data_entry_tab)
self.entry_name.pack(pady=5)
# Image Listbox
self.label_image = [Link](self.data_entry_tab, text="Selected Images:")
self.label_image.pack(pady=5)
self.listbox_images = [Link](self.data_entry_tab, height=8)
self.listbox_images.pack(pady=5)
# Upload Button
self.upload_button = [Link](self.data_entry_tab, text="Upload Images",
command=self.upload_images)
self.upload_button.pack(pady=5)
# Capture Button
self.capture_button = [Link](self.data_entry_tab, text="Capture
Images", command=self.capture_images)
self.capture_button.pack(pady=5)
# Save Button
self.save_button = [Link](self.data_entry_tab, text="Save",
command=self.save_data)
self.save_button.pack(pady=20)
# Train Button
self.train_button = [Link](self.data_entry_tab, text="Train New
Student", command=self.train_new_student,
state=[Link])
self.train_button.pack(pady=10)
self.enable_train_if_dataset_exists()
# Face Recognition Button
self.face_recognition_button = [Link](self.data_entry_tab, text="Face
Recognition",
command=self.face_recognition)
self.face_recognition_button.pack(pady=5)
def init_attendance_ui(self):
# Course Label and Entry
self.label_course = [Link](self.attendance_tab, text="Course:")
self.label_course.pack(pady=5)
self.entry_course = [Link](self.attendance_tab)
self.entry_course.pack(pady=5)
# Date Label and Entry
self.label_date = [Link](self.attendance_tab, text="Date (YYYY-MM-DD):")
self.label_date.pack(pady=5)
self.entry_date = [Link](self.attendance_tab)
self.entry_date.pack(pady=5)
# Attendance Button
self.attendance_button = [Link](self.attendance_tab, text="Take
Attendance", command=self.take_attendance)
self.attendance_button.pack(pady=10)
# Attendance Table
self.attendance_table = [Link](self.attendance_tab, columns=('ID',
'Name', 'Date', 'Time'),
show='headings')
self.attendance_table.heading('ID', text='ID')
self.attendance_table.heading('Name', text='Name')
self.attendance_table.heading('Date', text='Date')
self.attendance_table.heading('Time', text='Time')
self.attendance_table.pack(padx=10, pady=10)
def load_existing_data(self):
# Load existing face embeddings and labels if available
if [Link]('faces_embeddings_done_4classes.npz'):
data = [Link]('faces_embeddings_done_4classes.npz')
self.X = data['arr_0']
self.Y = data['arr_1']
[Link](self.Y) # Fit label encoder
else:
self.X = [Link]((0, 160, 160, 3))
self.Y = [Link]([])
def upload_images(self):
file_paths = [Link](
title="Select Images",
filetypes=[("Image files", "*.jpg *.jpeg *.png")]
)
if file_paths:
self.image_paths.extend(file_paths)
for path in file_paths:
# Copy the uploaded image to dataset/id folder
student_id = self.entry_id.get()
if not student_id:
[Link]("Input Error", "Please enter the Student
ID before uploading images.")
return
IMAGES_PATH = [Link]("dataset", student_id)
[Link](IMAGES_PATH, exist_ok=True)
dest_path = [Link](IMAGES_PATH, [Link](path))
try:
[Link](path, dest_path)
self.listbox_images.insert([Link], [Link](dest_path))
except Exception as e:
[Link]("Error", f"Error copying file: {str(e)}")
def capture_images(self):
student_id = self.entry_id.get()
student_name = self.entry_name.get()
if not student_id or not student_name:
[Link]("Input Error", "Please enter both Student ID and
Name before capturing images.")
return
IMAGES_PATH = [Link]("dataset", student_id)
[Link](IMAGES_PATH, exist_ok=True)
number_images = 10
cap = [Link](0)
if not [Link]():
[Link]("Error", "Cannot open camera.")
return
captured_image_paths = []
for imgnum in range(number_images):
ret, frame = [Link]()
if not ret:
[Link]("Error", "Failed to capture image.")
break
imgname = [Link](IMAGES_PATH, f'{str(uuid.uuid1())}.jpg')
[Link](imgname, frame)
captured_image_paths.append(imgname)
[Link]('frame', frame)
if [Link](1) & 0xFF == ord('q'):
break
[Link](0.5)
[Link]()
[Link]()
self.image_paths.extend(captured_image_paths)
for path in captured_image_paths:
self.listbox_images.insert([Link], [Link](path))
def save_data(self):
student_id = self.entry_id.get()
student_name = self.entry_name.get()
if not student_id or not student_name or not self.image_paths:
[Link]("Input Error", "Please enter ID, Name, and
select images.")
return
try:
# Save student data to CSV
csv_file = 'student_data.csv'
if not [Link](csv_file):
with open(csv_file, mode='w', newline='') as file:
writer = [Link](file)
[Link](['ID', 'Name', 'ImagePath'])
# Write the student information
with open(csv_file, mode='a', newline='') as file:
writer = [Link](file)
[Link]([student_id, student_name, self.image_paths[0]]) #
Save the first image path
# Update UI state
self.train_button.config(state=[Link]) # Enable train button after
saving
# Clear the input fields and image listbox
self.entry_id.delete(0, [Link])
self.entry_name.delete(0, [Link])
self.listbox_images.delete(0, [Link])
self.image_paths = []
[Link]("Success", "Student data saved successfully.")
except Exception as e:
[Link]("Error", f"Error saving data: {str(e)}")
def train_new_student(self):
class FACELOADING:
def __init__(self, directory):
[Link] = directory
[Link] = MTCNN()
self.target_size = (160, 160)
self.X = []
self.Y = []
def extract_face(self, filename):
try:
img = [Link](filename)
img_rgb = [Link](img, cv.COLOR_BGR2RGB)
results = [Link].detect_faces(img_rgb)
if results:
x1, y1, width, height = results[0]['box']
x2, y2 = x1 + width, y1 + height
face = img_rgb[y1:y2, x1:x2]
image = [Link](face, self.target_size)
return image
except Exception as e:
print(f"Error extracting face: {str(e)}")
return None
def load_faces(self, subdir):
faces = []
y = subdir
subdir_full = [Link]([Link], subdir)
for filename in [Link](subdir_full):
path = [Link](subdir_full, filename)
face = self.extract_face(path)
if face is not None:
[Link](face)
return faces, y
def load_dataset(self):
for subdir in [Link]([Link]):
subdir_full = [Link]([Link], subdir)
if not [Link](subdir_full):
continue
faces, y = self.load_faces(subdir)
labels = [y] * len(faces)
print(f'Loaded {len(faces)} examples for class: {y}')
[Link](faces)
[Link](labels)
return [Link](self.X), [Link](self.Y)
directory = "dataset"
faceloading = FACELOADING(directory)
self.X, self.Y = faceloading.load_dataset()
[Link](self.Y)
Y = [Link](self.Y)
[Link] = SVC(kernel='linear', probability=True)
faces = [Link](self.X)
print("Shape of faces:", [Link]) # Phải là (N, 160, 160, 3)
print("Faces dtype:", [Link])
faces = [Link]('float32')
# Kiểm tra shape, nếu không đúng thì báo lỗi và dừng lại
if [Link] != 4 or [Link][-1] != 3:
raise Exception("faces shape không đúng, cần (N, 160, 160, 3)")
# Trích xuất embedding cho cả batch
X = [Link](faces) # shape (N, 512)
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.2,
random_state=42)
[Link](X_train, Y_train)
Y_pred = [Link](X_test)
accuracy = accuracy_score(Y_test, Y_pred)
[Link]("Training Complete", f"Model trained with accuracy:
{accuracy * 100:.2f}%")
with open('svm_model_160x160.pkl', 'wb') as file:
[Link]([Link], file)
def face_recognition(self):
cap = [Link](0)
if not [Link]():
[Link]("Error", "Cannot open camera.")
return
with open('svm_model_160x160.pkl', 'rb') as file:
[Link] = [Link](file)
while True:
ret, frame = [Link]()
if not ret:
[Link]("Error", "Failed to capture image.")
break
frame_rgb = [Link](frame, cv.COLOR_BGR2RGB)
faces = [Link].detect_faces(frame_rgb)
for result in faces:
x1, y1, width, height = result['box']
x2, y2 = x1 + width, y1 + height
face = frame_rgb[y1:y2, x1:x2]
face = [Link](face, (160, 160))
face_emb = [Link](face[[Link], :])
face_emb = face_emb / [Link](face_emb, axis=1,
keepdims=True)
probs = [Link].predict_proba(face_emb)[0]
best_idx = [Link](probs)
confidence = probs[best_idx]
if confidence < 0.7:
pred_name = "Unknown"
else:
pred_name = [Link].inverse_transform([best_idx])[0]
label = f"{pred_name} ({confidence * 100:.1f}%)"
[Link](frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
[Link](frame, label, (x1, y1 - 10), cv.FONT_HERSHEY_SIMPLEX,
0.9, (0, 255, 0), 2)
[Link]('Face Recognition', frame)
if [Link](1) & 0xFF == ord('q'):
break
[Link]()
[Link]()
def take_attendance(self):
course = self.entry_course.get()
date = self.entry_date.get()
if not course or not date:
[Link]("Input Error", "Please enter both Course and
Date.")
return
# Create the course folder if it doesn't exist
course_folder = [Link]('attendance', course)
[Link](course_folder, exist_ok=True)
# File path for the attendance CSV
file_path = [Link](course_folder, f"{date}.csv")
# Load student data from CSV
student_data = {}
with open('student_data.csv', mode='r') as file:
reader = [Link](file)
for row in reader:
student_data[row['ID']] = row['Name']
cap = [Link](0)
if not [Link]():
[Link]("Error", "Cannot open camera.")
return
with open('svm_model_160x160.pkl', 'rb') as file:
[Link] = [Link](file)
attendance_records = []
recorded_students = set() # To keep track of recorded student IDs
while True:
ret, frame = [Link]()
if not ret:
[Link]("Error", "Failed to capture image.")
break
frame_rgb = [Link](frame, cv.COLOR_BGR2RGB)
faces = [Link].detect_faces(frame_rgb)
for result in faces:
x1, y1, width, height = result['box']
x2, y2 = x1 + width, y1 + height
face = frame_rgb[y1:y2, x1:x2]
face = [Link](face, (160, 160))
face_emb = [Link](face[[Link], :])
face_emb = face_emb / [Link](face_emb, axis=1,
keepdims=True)
probs = [Link].predict_proba(face_emb)[0]
best_idx = [Link](probs)
confidence = probs[best_idx]
if confidence < 0.7:
pred_id = "Unknown"
pred_name = "Unknown"
else :
pred_id = [Link].inverse_transform([best_idx])[0]
# Use student ID to get the student name
pred_name = student_data.get(pred_id, "Unknown")
# Draw bounding box and label on the image
[Link](frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
[Link](frame, pred_name, (x1, y1 - 10),
cv.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
# Check if the student has already been recorded
if pred_id not in recorded_students:
# Record attendance
current_time = [Link]("%H:%M:%S")
attendance_records.append([pred_id, pred_name, date,
current_time, f"{confidence*100:.1f}%"])
# Add the student ID to the set
recorded_students.add(pred_id)
[Link]('Face Recognition', frame)
if [Link](1) & 0xFF == ord('q'):
break
[Link]()
[Link]()
# Save attendance records to CSV
with open(file_path, mode='w', newline='') as file:
writer = [Link](file)
[Link](['ID', 'Name', 'Date', 'Time', 'Confidence'])
[Link](attendance_records)
# Update attendance table
self.update_attendance_table(file_path)
def update_attendance_table(self, attendance_file):
for row in self.attendance_table.get_children():
self.attendance_table.delete(row)
with open(attendance_file, mode='r') as file:
reader = [Link](file)
next(reader) # Skip header row
for row in reader:
self.attendance_table.insert("", [Link], values=row)
# Run the application
if __name__ == "__main__":
app = StudentDataApp()
[Link]()