diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ed032ba
Binary files /dev/null and b/LICENSE differ
diff --git a/README.md b/README.md
index b97da59..3f6d44b 100644
--- a/README.md
+++ b/README.md
@@ -1,38 +1,80 @@
+# Attendance Management System Using Face Recognition
-# Face based attendance system using python and openCV
+A **Python-based attendance management system** using OpenCV and face recognition.
+This system allows you to register students by capturing face images, train a face recognition model, and automatically take and view attendance.
-[](https://www.python.org/)
-[](https://www.python.org/downloads/release/python-390/)
+---
-### What steps you have to follow??
-- Download or clone my Repository to your device
-- type `pip install -r requirements.txt` in command prompt(this will install required package for project)
-- Create a `TrainingImage` folder in a project folder.
-- open `attendance.py` and `automaticAttendance.py`, change all the path accoriding to your system
-- Run `attandance.py` file
+## π Features
+- Register new students with face images.
+- Train face recognition model using Local Binary Patterns Histograms (LBPH).
+- Take attendance automatically via webcam.
+- View attendance logs.
+- Text-to-speech notifications for better accessibility.
-### Project flow & explaination
-- After you run the project you have to register your face so that system can identify you, so click on register new student
-- After you click a small window will pop up in that you have to enter you ID and name and then click on `Take Image` button
-- After clicking `Take Image` button A camera window will pop up and it will detect your Face and take upto 50 Images(you can change the number of Image it can take) and stored in the folder named `TrainingImage`. more you give the image to system, the better it will perform while recognising the face.
-- Then you have to click on `Train Image` button, It will train the model and convert all the Image into numeric format so that computer can understand. we are training the image so that next time when we will show the same face to the computer it will easily identify the face.
-- It will take some time(depends on you system).
-- After training model click on `Automatic Attendance` ,you have to enter the subject name and then it can fill attendace by your face using our trained model.
-- it will create `.csv` file for every subject you enter and seperate every `.csv` file accoriding the subject
-- You can view the attendance after clicking `View Attendance` button. It will show record in tabular format.
+---
-### Screenshots
+## π Project Structure
+Attendance-Management-system-using-face-recognition/
+β
+βββ Attendance.py # Main GUI application
+βββ requirements.txt # Required Python packages
+βββ takeImage.py # Module to capture student face images
+βββ trainImage.py # Module to train face recognition model
+βββ automaticAttendance.py # Module for automated attendance capture
+βββ show_attendance.py # Module to view attendance logs
+βββ StudentDetails/ # Folder containing student details CSV
+βββ TrainingImage/ # Folder containing captured images
+βββ TrainingImageLabel/ # Folder containing trained model
+βββ UI_Image/ # Folder containing UI icons/images
+βββ README.md # Project documentation
-### Simple UI
-
-### While taking Image
-
+---
-## While taking Attendance
-
+## βοΈ Requirements
+- Python 3.8+
+- OpenCV
+- NumPy
+- Pandas
+- Pillow
+- pyttsx3
-## Attendance in tabular format
-
+---
+
+## π¦ Installation
+1. Clone the repository:
+```bash
+git clone https://github.com//Attendance-Management-system-using-face-recognition.git
+cd Attendance-Management-system-using-face-recognition
+
+Install dependencies:
+
+pip install -r requirements.txt
+
+π How to Run
+
+Run the main program:
+
+python Attendance.py
+
+π License
+
+This project is licensed under the MIT License β see the LICENSE
+ file for details.
+
+π‘ Contributing
+
+Contributions are welcome!
+If you find any bugs or want to add features, please open an issue or submit a pull request.
+
+π€ Author
+
+Mohd Mudabbir Arafat
+Email: mudabbir.arafat@example.com
+
+GitHub: https://github.com/Mudabbirarafat
+
+
+---
-## Just follow me and Starβ my repository
diff --git a/attendance.py b/attendance.py
index d83d3c9..fe86c0c 100644
--- a/attendance.py
+++ b/attendance.py
@@ -18,7 +18,299 @@
import automaticAttedance
# engine = pyttsx3.init()
-# engine.say("Welcome!")
+# engine.say("Welcome!")import tkinter as tk
+from tkinter import *
+import os, cv2
+import shutil
+import csv
+import numpy as np
+from PIL import ImageTk, Image
+import pandas as pd
+import datetime
+import time
+import tkinter.font as font
+import pyttsx3
+import argparse
+
+# project module
+import show_attendance
+import takeImage
+import trainImage
+import automaticAttedance
+
+# Function: Text to Speech
+def text_to_speech(user_text):
+ engine = pyttsx3.init()
+ engine.say(user_text)
+ engine.runAndWait()
+
+# ===== Path Handling Fixes =====
+BASE_DIR = os.path.dirname(os.path.abspath(__file__))
+
+haarcasecade_path = os.path.join(BASE_DIR, "haarcascade_frontalface_default.xml")
+trainimagelabel_path = os.path.join(BASE_DIR, "TrainingImageLabel", "Trainner.yml")
+trainimage_path = os.path.join(BASE_DIR, "TrainingImage")
+studentdetail_path = os.path.join(BASE_DIR, "StudentDetails", "studentdetails.csv")
+attendance_path = os.path.join(BASE_DIR, "Attendance")
+
+# Create directories if missing
+os.makedirs(trainimage_path, exist_ok=True)
+os.makedirs(attendance_path, exist_ok=True)
+os.makedirs(os.path.dirname(trainimagelabel_path), exist_ok=True)
+os.makedirs(os.path.dirname(studentdetail_path), exist_ok=True)
+
+# ===== Tkinter Window =====
+window = Tk()
+window.title("Face Recognizer")
+window.geometry("1280x720")
+dialog_title = "QUIT"
+dialog_text = "Are you sure want to close?"
+window.configure(background="#1c1c1c") # Dark theme
+
+# Destroy screen function
+def del_sc1():
+ sc1.destroy()
+
+# Error message function
+def err_screen():
+ global sc1
+ sc1 = tk.Tk()
+ sc1.geometry("400x110")
+ sc1.iconbitmap(os.path.join(BASE_DIR, "AMS.ico"))
+ sc1.title("Warning!!")
+ sc1.configure(background="#1c1c1c")
+ sc1.resizable(0, 0)
+ tk.Label(
+ sc1,
+ text="Enrollment & Name required!!!",
+ fg="yellow",
+ bg="#1c1c1c",
+ font=("Verdana", 16, "bold"),
+ ).pack()
+ tk.Button(
+ sc1,
+ text="OK",
+ command=del_sc1,
+ fg="yellow",
+ bg="#333333",
+ width=9,
+ height=1,
+ activebackground="red",
+ font=("Verdana", 16, "bold"),
+ ).place(x=110, y=50)
+
+# Validation for entry fields
+def testVal(inStr, acttyp):
+ if acttyp == "1": # insert
+ if not inStr.isdigit():
+ return False
+ return True
+
+# Load logo
+logo = Image.open(os.path.join(BASE_DIR, "UI_Image", "0001.png"))
+logo = logo.resize((50, 47), Image.LANCZOS)
+logo1 = ImageTk.PhotoImage(logo)
+titl = tk.Label(window, bg="#1c1c1c", relief=RIDGE, bd=10, font=("Verdana", 30, "bold"))
+titl.pack(fill=X)
+l1 = tk.Label(window, image=logo1, bg="#1c1c1c")
+l1.place(x=470, y=10)
+
+titl = tk.Label(
+ window, text="CLASS VISION", bg="#1c1c1c", fg="yellow", font=("Verdana", 27, "bold"),
+)
+titl.place(x=525, y=12)
+
+a = tk.Label(
+ window,
+ text="Welcome to CLASS VISION",
+ bg="#1c1c1c",
+ fg="yellow",
+ bd=10,
+ font=("Verdana", 35, "bold"),
+)
+a.pack()
+
+# Load images
+ri = Image.open(os.path.join(BASE_DIR, "UI_Image", "register.png"))
+r = ImageTk.PhotoImage(ri)
+label1 = Label(window, image=r)
+label1.image = r
+label1.place(x=100, y=270)
+
+ai = Image.open(os.path.join(BASE_DIR, "UI_Image", "attendance.png"))
+a = ImageTk.PhotoImage(ai)
+label2 = Label(window, image=a)
+label2.image = a
+label2.place(x=980, y=270)
+
+vi = Image.open(os.path.join(BASE_DIR, "UI_Image", "verifyy.png"))
+v = ImageTk.PhotoImage(vi)
+label3 = Label(window, image=v)
+label3.image = v
+label3.place(x=600, y=270)
+
+# Function to open image registration UI
+def TakeImageUI():
+ ImageUI = Tk()
+ ImageUI.title("Take Student Image..")
+ ImageUI.geometry("780x480")
+ ImageUI.configure(background="#1c1c1c")
+ ImageUI.resizable(0, 0)
+ titl = tk.Label(ImageUI, bg="#1c1c1c", relief=RIDGE, bd=10, font=("Verdana", 30, "bold"))
+ titl.pack(fill=X)
+
+ titl = tk.Label(
+ ImageUI, text="Register Your Face", bg="#1c1c1c", fg="green", font=("Verdana", 30, "bold"),
+ )
+ titl.place(x=270, y=12)
+
+ a = tk.Label(
+ ImageUI,
+ text="Enter the details",
+ bg="#1c1c1c",
+ fg="yellow",
+ bd=10,
+ font=("Verdana", 24, "bold"),
+ )
+ a.place(x=280, y=75)
+
+ lbl1 = tk.Label(
+ ImageUI,
+ text="Enrollment No",
+ width=10,
+ height=2,
+ bg="#1c1c1c",
+ fg="yellow",
+ bd=5,
+ relief=RIDGE,
+ font=("Verdana", 14),
+ )
+ lbl1.place(x=120, y=130)
+
+ txt1 = tk.Entry(
+ ImageUI,
+ width=17,
+ bd=5,
+ validate="key",
+ bg="#333333",
+ fg="yellow",
+ relief=RIDGE,
+ font=("Verdana", 18, "bold"),
+ )
+ txt1.place(x=250, y=130)
+ txt1["validatecommand"] = (txt1.register(testVal), "%P", "%d")
+
+ lbl2 = tk.Label(
+ ImageUI,
+ text="Name",
+ width=10,
+ height=2,
+ bg="#1c1c1c",
+ fg="yellow",
+ bd=5,
+ relief=RIDGE,
+ font=("Verdana", 14),
+ )
+ lbl2.place(x=120, y=200)
+
+ txt2 = tk.Entry(
+ ImageUI,
+ width=17,
+ bd=5,
+ bg="#333333",
+ fg="yellow",
+ relief=RIDGE,
+ font=("Verdana", 18, "bold"),
+ )
+ txt2.place(x=250, y=200)
+
+ lbl3 = tk.Label(
+ ImageUI,
+ text="Notification",
+ width=10,
+ height=2,
+ bg="#1c1c1c",
+ fg="yellow",
+ bd=5,
+ relief=RIDGE,
+ font=("Verdana", 14),
+ )
+ lbl3.place(x=120, y=270)
+
+ message = tk.Label(
+ ImageUI,
+ text="",
+ width=32,
+ height=2,
+ bd=5,
+ bg="#333333",
+ fg="yellow",
+ relief=RIDGE,
+ font=("Verdana", 14, "bold"),
+ )
+ message.place(x=250, y=270)
+
+ def take_image():
+ l1 = txt1.get()
+ l2 = txt2.get()
+ takeImage.TakeImage(
+ l1,
+ l2,
+ haarcasecade_path,
+ trainimage_path,
+ trainimagelabel_path,
+ message,
+ err_screen,
+ text_to_speech,
+ )
+ txt1.delete(0, "end")
+ txt2.delete(0, "end")
+
+ takeImg = tk.Button(
+ ImageUI,
+ text="Take Image",
+ command=take_image,
+ bd=10,
+ font=("Verdana", 18, "bold"),
+ bg="#333333",
+ fg="yellow",
+ height=2,
+ width=12,
+ relief=RIDGE,
+ )
+ takeImg.place(x=130, y=350)
+
+ def train_image():
+ trainImage.TrainImage(
+ haarcasecade_path,
+ trainimage_path,
+ trainimagelabel_path,
+ message,
+ text_to_speech,
+ )
+
+ trainImg = tk.Button(
+ ImageUI,
+ text="Train Image",
+ command=train_image,
+ bd=10,
+ font=("Verdana", 18, "bold"),
+ bg="#333333",
+ fg="yellow",
+ height=2,
+ width=12,
+ relief=RIDGE,
+ )
+ trainImg.place(x=360, y=350)
+
+# Buttons for main window
+tk.Button(window, text="Register a new student", command=TakeImageUI, bd=10, font=("Verdana", 16), bg="black", fg="yellow", height=2, width=17).place(x=100, y=520)
+tk.Button(window, text="Take Attendance", command=lambda: automaticAttedance.subjectChoose(text_to_speech), bd=10, font=("Verdana", 16), bg="black", fg="yellow", height=2, width=17).place(x=600, y=520)
+tk.Button(window, text="View Attendance", command=lambda: show_attendance.subjectchoose(text_to_speech), bd=10, font=("Verdana", 16), bg="black", fg="yellow", height=2, width=17).place(x=1000, y=520)
+tk.Button(window, text="EXIT", bd=10, command=quit, font=("Verdana", 16), bg="black", fg="yellow", height=2, width=17).place(x=600, y=660)
+
+window.mainloop()
+
# engine.say("Please browse through your options..")
# engine.runAndWait()
diff --git a/requirements.txt b/requirements.txt
index ef49b8a..57e0005 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,5 @@
-numpy
-opencv-contrib-python
-opencv-python
-openpyxl
-pandas
-pillow
-pyttsx3
\ No newline at end of file
+opencv-python==4.5.5.62
+numpy==1.23.5
+pandas==1.5.3
+Pillow==9.5.0
+face-recognition==1.3.0
diff --git a/takeImage.py b/takeImage.py
index 82c14f5..0a0887f 100644
--- a/takeImage.py
+++ b/takeImage.py
@@ -1,68 +1,77 @@
import csv
-import os, cv2
+import os
+import cv2
import numpy as np
import pandas as pd
import datetime
import time
-
-# take Image of user
-def TakeImage(l1, l2, haarcasecade_path, trainimage_path, message, err_screen,text_to_speech):
- if (l1 == "") and (l2==""):
- t='Please Enter the your Enrollment Number and Name.'
+def TakeImage(l1, l2, haarcasecade_path, trainimage_path, message, err_screen, text_to_speech):
+ if (l1 == "") and (l2 == ""):
+ t = "Please Enter your Enrollment Number and Name."
text_to_speech(t)
- elif l1=='':
- t='Please Enter the your Enrollment Number.'
+ return
+ elif l1 == "":
+ t = "Please Enter your Enrollment Number."
text_to_speech(t)
+ return
elif l2 == "":
- t='Please Enter the your Name.'
+ t = "Please Enter your Name."
text_to_speech(t)
- else:
- try:
- cam = cv2.VideoCapture(0)
- detector = cv2.CascadeClassifier(haarcasecade_path)
- Enrollment = l1
- Name = l2
- sampleNum = 0
- directory = Enrollment + "_" + Name
- path = os.path.join(trainimage_path, directory)
- os.mkdir(path)
- while True:
- ret, img = cam.read()
- gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
- faces = detector.detectMultiScale(gray, 1.3, 5)
- for (x, y, w, h) in faces:
- cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
- sampleNum = sampleNum + 1
- cv2.imwrite(
- f"{path}\ "
- + Name
- + "_"
- + Enrollment
- + "_"
- + str(sampleNum)
- + ".jpg",
- gray[y : y + h, x : x + w],
- )
- cv2.imshow("Frame", img)
- if cv2.waitKey(1) & 0xFF == ord("q"):
- break
- elif sampleNum > 50:
- break
- cam.release()
- cv2.destroyAllWindows()
- row = [Enrollment, Name]
- with open(
- "StudentDetails/studentdetails.csv",
- "a+",
- ) as csvFile:
- writer = csv.writer(csvFile, delimiter=",")
- writer.writerow(row)
- csvFile.close()
- res = "Images Saved for ER No:" + Enrollment + " Name:" + Name
- message.configure(text=res)
- text_to_speech(res)
- except FileExistsError as F:
- F = "Student Data already exists"
- text_to_speech(F)
+ return
+
+ try:
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # Fixed base directory
+ haarcasecade_path = os.path.join(BASE_DIR, haarcasecade_path)
+ trainimage_path = os.path.join(BASE_DIR, trainimage_path)
+ studentdetail_path = os.path.join(BASE_DIR, "StudentDetails", "studentdetails.csv")
+
+ os.makedirs(trainimage_path, exist_ok=True)
+ os.makedirs(os.path.dirname(studentdetail_path), exist_ok=True)
+
+ cam = cv2.VideoCapture(0)
+ detector = cv2.CascadeClassifier(haarcasecade_path)
+
+ Enrollment = l1
+ Name = l2
+ sampleNum = 0
+ directory = Enrollment + "_" + Name
+ path = os.path.join(trainimage_path, directory)
+ os.makedirs(path, exist_ok=True) # Avoid FileExistsError
+
+ while True:
+ ret, img = cam.read()
+ gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
+ faces = detector.detectMultiScale(gray, 1.3, 5)
+
+ for (x, y, w, h) in faces:
+ cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
+ sampleNum += 1
+ filename = os.path.join(
+ path,
+ f"{Name}_{Enrollment}_{sampleNum}.jpg"
+ )
+ cv2.imwrite(filename, gray[y:y + h, x:x + w])
+ cv2.imshow("Frame", img)
+
+ if cv2.waitKey(1) & 0xFF == ord("q"):
+ break
+ elif sampleNum > 50:
+ break
+
+ cam.release()
+ cv2.destroyAllWindows()
+
+ row = [Enrollment, Name]
+ with open(studentdetail_path, "a+", newline="") as csvFile:
+ writer = csv.writer(csvFile, delimiter=",")
+ writer.writerow(row)
+
+ res = f"Images Saved for ER No: {Enrollment} Name: {Name}"
+ message.configure(text=res)
+ text_to_speech(res)
+
+ except Exception as e:
+ err_screen()
+ text_to_speech(str(e))
diff --git a/trainImage.py b/trainImage.py
index 40ecb66..0738cd4 100644
--- a/trainImage.py
+++ b/trainImage.py
@@ -1,38 +1,66 @@
import csv
-import os, cv2
+import os
+import cv2
import numpy as np
-import pandas as pd
-import datetime
-import time
-from PIL import ImageTk, Image
+from PIL import Image
-# Train Image
-def TrainImage(haarcasecade_path, trainimage_path, trainimagelabel_path, message,text_to_speech):
- recognizer = cv2.face.LBPHFaceRecognizer_create()
- detector = cv2.CascadeClassifier(haarcasecade_path)
- faces, Id = getImagesAndLables(trainimage_path)
- recognizer.train(faces, np.array(Id))
- recognizer.save(trainimagelabel_path)
- res = "Image Trained successfully" # +",".join(str(f) for f in Id)
- message.configure(text=res)
- text_to_speech(res)
+def TrainImage(haarcasecade_path, trainimage_path, trainimagelabel_path, message, text_to_speech):
+ try:
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
+
+ haarcasecade_path = os.path.join(BASE_DIR, haarcasecade_path)
+ trainimage_path = os.path.join(BASE_DIR, trainimage_path)
+ trainimagelabel_path = os.path.join(BASE_DIR, trainimagelabel_path)
+
+ os.makedirs(trainimage_path, exist_ok=True)
+ os.makedirs(os.path.dirname(trainimagelabel_path), exist_ok=True)
+
+ recognizer = cv2.face.LBPHFaceRecognizer_create()
+ detector = cv2.CascadeClassifier(haarcasecade_path)
+
+ faces, Id = getImagesAndLables(trainimage_path)
+ if len(faces) == 0:
+ raise Exception("No face images found for training!")
+
+ recognizer.train(faces, np.array(Id))
+ recognizer.save(trainimagelabel_path)
+
+ res = "Images Trained Successfully"
+ message.configure(text=res)
+ text_to_speech(res)
+
+ except Exception as e:
+ res = f"Training Failed: {str(e)}"
+ message.configure(text=res)
+ text_to_speech(res)
def getImagesAndLables(path):
- # imagePath = [os.path.join(path, f) for d in os.listdir(path) for f in d]
- newdir = [os.path.join(path, d) for d in os.listdir(path)]
- imagePath = [
- os.path.join(newdir[i], f)
- for i in range(len(newdir))
- for f in os.listdir(newdir[i])
- ]
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
+ path = os.path.join(BASE_DIR, path)
+
faces = []
Ids = []
- for imagePath in imagePath:
- pilImage = Image.open(imagePath).convert("L")
- imageNp = np.array(pilImage, "uint8")
- Id = int(os.path.split(imagePath)[-1].split("_")[1])
- faces.append(imageNp)
- Ids.append(Id)
+
+ if not os.path.exists(path):
+ raise Exception(f"Training image path does not exist: {path}")
+
+ # Get subdirectories (student folders)
+ directories = [os.path.join(path, d) for d in os.listdir(path) if os.path.isdir(os.path.join(path, d))]
+
+ for directory in directories:
+ imageFiles = [os.path.join(directory, f) for f in os.listdir(directory) if f.endswith(".jpg")]
+ for imagePath in imageFiles:
+ pilImage = Image.open(imagePath).convert("L") # convert to grayscale
+ imageNp = np.array(pilImage, "uint8")
+
+ try:
+ Id = int(os.path.split(imagePath)[-1].split("_")[1])
+ except Exception:
+ continue # skip files that do not match pattern
+
+ faces.append(imageNp)
+ Ids.append(Id)
+
return faces, Ids