from flask import Flask, render_template, request, jsonify import os import cv2 import numpy as np import pandas as pd from datetime import datetime import base64 app = Flask(__name__) # Setup face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_alt.xml") dataset_path = "./face_dataset/" attendance_path = "./attendance_data/" os.makedirs(dataset_path, exist_ok=True) os.makedirs(attendance_path, exist_ok=True) # KNN distance utility def distance(v1, v2): return np.sqrt(((v1 - v2) ** 2).sum()) def knn(train, test, k=5): dist = [] for i in range(train.shape[0]): ix = train[i, :-1] iy = train[i, -1] d = distance(test, ix) dist.append([d, iy]) dk = sorted(dist, key=lambda x: x[0])[:k] labels = np.array(dk)[:, -1] return np.unique(labels, return_counts=True)[0][0] # Attendance management per class class AttendanceSystem: def __init__(self, class_name): self.class_name = class_name self.file = os.path.join(attendance_path, f"{class_name}.xlsx") self.columns = ["Enrollment", "Name", "Date", "CheckIn", "CheckOut"] if not os.path.exists(self.file): df = pd.DataFrame(columns=self.columns) df.to_excel(self.file, index=False) def checkin(self, enrollment, name): today = datetime.now().strftime("%Y-%m-%d") now = datetime.now().strftime("%H:%M:%S") df = pd.read_excel(self.file) existing = df[(df["Enrollment"] == enrollment) & (df["Date"] == today)] if existing.empty: new_entry = pd.DataFrame([[enrollment, name, today, now, ""]], columns=self.columns) df = pd.concat([df, new_entry], ignore_index=True) df.to_excel(self.file, index=False) return True, "Check-in successful" return False, "Already checked in" def checkout(self, enrollment): today = datetime.now().strftime("%Y-%m-%d") now = datetime.now().strftime("%H:%M:%S") df = pd.read_excel(self.file) idx = df[(df["Enrollment"] == enrollment) & (df["Date"] == today)].index if idx.empty: return False, "Please check-in first" row = df.loc[idx[0]] if pd.isna(row["CheckOut"]) or row["CheckOut"] == "": df.at[idx[0], "CheckOut"] = now df.to_excel(self.file, index=False) return True, "Check-out successful" return False, "Already checked out" # Routes @app.route('/') def index(): return render_template('index.html') @app.route('/register') def register(): return render_template('register.html') @app.route('/mark') def mark(): return render_template('mark.html') # API to save face during registration @app.route('/api/register_face', methods=['POST']) def register_face(): data = request.json class_name = data['class_name'] name = data['name'] enrollment = data['enrollment'] images = data['images'] # List of base64 images class_folder = os.path.join(dataset_path, class_name) os.makedirs(class_folder, exist_ok=True) face_data = [] for img_data in images: img_bytes = base64.b64decode(img_data.split(",")[1]) np_arr = np.frombuffer(img_bytes, np.uint8) img = cv2.imdecode(np_arr, cv2.IMREAD_COLOR) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray = cv2.equalizeHist(gray) faces = face_cascade.detectMultiScale(gray, 1.3, 5) for (x, y, w, h) in faces[:1]: face = img[y:y+h, x:x+w] face = cv2.resize(face, (100, 100)) face_data.append(face.flatten()) flipped = cv2.flip(face, 1) face_data.append(flipped.flatten()) if face_data: face_data = np.array(face_data) filename = f"{enrollment}_{name}.npy" np.save(os.path.join(class_folder, filename), face_data) return jsonify({"status": "success", "message": f"{len(face_data)} faces saved"}) return jsonify({"status": "fail", "message": "No faces detected"}) # API to identify face without marking @app.route('/api/identify_face', methods=['POST']) def identify_face(): data = request.json class_name = data['class_name'] img_data = data['image'] img_bytes = base64.b64decode(img_data.split(",")[1]) np_arr = np.frombuffer(img_bytes, np.uint8) img = cv2.imdecode(np_arr, cv2.IMREAD_COLOR) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.3, 5) class_folder = os.path.join(dataset_path, class_name) if not os.path.exists(class_folder): return jsonify({"status": "fail", "message": "No data for this class"}) # Load training data for this class face_data = [] labels = [] names = {} class_id = 0 for file in os.listdir(class_folder): if file.endswith('.npy'): data_arr = np.load(os.path.join(class_folder, file)) face_data.append(data_arr) parts = file[:-4].split('_', 1) labels.extend([class_id] * data_arr.shape[0]) names[class_id] = {'enrollment': parts[0], 'name': parts[1]} class_id += 1 if not face_data: return jsonify({"status": "fail", "message": "No trained data found"}) X_train = np.concatenate(face_data, axis=0) y_train = np.array(labels).reshape(-1, 1) trainset = np.hstack((X_train, y_train)) for (x, y, w, h) in faces[:1]: face = img[y:y+h, x:x+w] face = cv2.resize(face, (100, 100)).flatten() pred_id = knn(trainset, face) info = names.get(pred_id) if info: return jsonify({ "status": "success", "name": info['name'], "enrollment": info['enrollment'] }) return jsonify({"status": "fail", "message": "Face not recognized"}) # API to check-in @app.route('/api/checkin', methods=['POST']) def api_checkin(): data = request.json class_name = data['class_name'] enrollment = data['enrollment'] name = data['name'] attendance = AttendanceSystem(class_name) ok, msg = attendance.checkin(enrollment, name) status = "success" if ok else "fail" return jsonify({"status": status, "message": msg}) # API to check-out @app.route('/api/checkout', methods=['POST']) def api_checkout(): data = request.json class_name = data['class_name'] enrollment = data['enrollment'] attendance = AttendanceSystem(class_name) ok, msg = attendance.checkout(enrollment) status = "success" if ok else "fail" return jsonify({"status": status, "message": msg}) if __name__ == '__main__': app.run(host='0.0.0.0', port=7860, debug=True)