Spaces:
Sleeping
Sleeping
Upload 4 files
Browse files- CNN_Model_acc_75.h5 +3 -0
- app.py +224 -0
- attendance.db +0 -0
- requirements.txt +7 -0
CNN_Model_acc_75.h5
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:4f17414ec703aa77db97a22766b6f4454f766e367148285d16cbbc729e69725c
|
3 |
+
size 94225136
|
app.py
ADDED
@@ -0,0 +1,224 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import cv2
|
3 |
+
import face_recognition
|
4 |
+
import os
|
5 |
+
import sqlite3
|
6 |
+
import pandas as pd
|
7 |
+
import numpy as np
|
8 |
+
from datetime import datetime
|
9 |
+
from PIL import Image
|
10 |
+
from keras.models import load_model
|
11 |
+
|
12 |
+
# --- Streamlit Configuration ---
|
13 |
+
st.set_page_config(
|
14 |
+
page_title="Face and Emotion Recognition Attendance System",
|
15 |
+
page_icon=":camera:",
|
16 |
+
layout="wide"
|
17 |
+
)
|
18 |
+
|
19 |
+
# --- Initialize session_state attributes ---
|
20 |
+
if "camera_active" not in st.session_state:
|
21 |
+
st.session_state.camera_active = False
|
22 |
+
|
23 |
+
# --- Password Protection (Optional) ---
|
24 |
+
password = st.text_input("Enter password", type="password")
|
25 |
+
|
26 |
+
# Stop if the password is incorrect
|
27 |
+
if password != "ravinder":
|
28 |
+
st.stop()
|
29 |
+
|
30 |
+
# --- Database Setup ---
|
31 |
+
conn = sqlite3.connect('attendance.db')
|
32 |
+
cursor = conn.cursor()
|
33 |
+
|
34 |
+
# Create Table with Emotion Column
|
35 |
+
cursor.execute('''
|
36 |
+
CREATE TABLE IF NOT EXISTS attendance (
|
37 |
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
38 |
+
name TEXT,
|
39 |
+
roll_no TEXT,
|
40 |
+
date TEXT,
|
41 |
+
time TEXT,
|
42 |
+
status TEXT,
|
43 |
+
emotion TEXT
|
44 |
+
)
|
45 |
+
''')
|
46 |
+
conn.commit()
|
47 |
+
|
48 |
+
# --- Load Known Faces ---
|
49 |
+
def load_known_faces():
|
50 |
+
images = []
|
51 |
+
classnames = []
|
52 |
+
directory = "Photos"
|
53 |
+
|
54 |
+
for cls in os.listdir(directory):
|
55 |
+
if os.path.splitext(cls)[1] in [".jpg", ".jpeg", ".png"]:
|
56 |
+
img_path = os.path.join(directory, cls)
|
57 |
+
curImg = cv2.imread(img_path)
|
58 |
+
images.append(curImg)
|
59 |
+
classnames.append(os.path.splitext(cls)[0])
|
60 |
+
|
61 |
+
return images, classnames
|
62 |
+
|
63 |
+
# --- Encode Known Faces ---
|
64 |
+
def find_encodings(images):
|
65 |
+
encode_list = []
|
66 |
+
for img in images:
|
67 |
+
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
68 |
+
encode = face_recognition.face_encodings(img)[0]
|
69 |
+
encode_list.append(encode)
|
70 |
+
return encode_list
|
71 |
+
|
72 |
+
Images, classnames = load_known_faces()
|
73 |
+
encodeListKnown = find_encodings(Images)
|
74 |
+
|
75 |
+
# --- Load Emotion Detection Model ---
|
76 |
+
@st.cache_resource
|
77 |
+
def load_emotion_model():
|
78 |
+
return load_model('CNN_Model_acc_75.h5')
|
79 |
+
|
80 |
+
emotion_model = load_emotion_model()
|
81 |
+
img_shape = 48
|
82 |
+
emotion_labels = ['angry', 'fear', 'happy', 'neutral', 'sad', 'surprise']
|
83 |
+
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
|
84 |
+
|
85 |
+
# --- Preprocess Frame for Emotion Detection ---
|
86 |
+
def process_frame(frame):
|
87 |
+
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
88 |
+
faces = face_cascade.detectMultiScale(gray_frame, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
|
89 |
+
|
90 |
+
emotions_detected = []
|
91 |
+
|
92 |
+
for (x, y, w, h) in faces:
|
93 |
+
roi_gray = gray_frame[y:y+h, x:x+w]
|
94 |
+
roi_color = frame[y:y+h, x:x+w]
|
95 |
+
|
96 |
+
face_roi = cv2.resize(roi_color, (img_shape, img_shape))
|
97 |
+
face_roi = np.expand_dims(face_roi, axis=0)
|
98 |
+
face_roi = face_roi / float(img_shape)
|
99 |
+
predictions = emotion_model.predict(face_roi)
|
100 |
+
emotion = emotion_labels[np.argmax(predictions[0])]
|
101 |
+
emotions_detected.append(emotion)
|
102 |
+
|
103 |
+
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
|
104 |
+
cv2.putText(frame, emotion, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (36, 255, 12), 2)
|
105 |
+
|
106 |
+
return frame, emotions_detected
|
107 |
+
|
108 |
+
# --- Camera Functionality ---
|
109 |
+
camera_active = st.session_state.get("camera_active", False)
|
110 |
+
|
111 |
+
if st.sidebar.button("Start Camera"):
|
112 |
+
st.session_state.camera_active = True
|
113 |
+
|
114 |
+
if st.sidebar.button("Stop Camera"):
|
115 |
+
st.session_state.camera_active = False
|
116 |
+
|
117 |
+
# --- Add New Face ---
|
118 |
+
def add_new_face():
|
119 |
+
new_name = st.text_input("Enter your name:")
|
120 |
+
roll_no = st.text_input("Enter your roll number:")
|
121 |
+
|
122 |
+
if st.session_state.camera_active:
|
123 |
+
img_file_buffer = st.camera_input("Take a picture")
|
124 |
+
if img_file_buffer is not None and new_name and roll_no:
|
125 |
+
st.session_state.camera_active = False # Stop camera after photo is taken
|
126 |
+
|
127 |
+
# Check if the user already exists in the database
|
128 |
+
cursor.execute("SELECT * FROM attendance WHERE name = ? AND roll_no = ?", (new_name, roll_no))
|
129 |
+
existing_user = cursor.fetchone()
|
130 |
+
|
131 |
+
if existing_user:
|
132 |
+
st.warning(f"{new_name} ({roll_no}) is already registered.")
|
133 |
+
else:
|
134 |
+
# Save the photo and update face encodings
|
135 |
+
image = np.array(Image.open(img_file_buffer))
|
136 |
+
img_path = os.path.join("Photos", f"{new_name}_{roll_no}.jpg")
|
137 |
+
cv2.imwrite(img_path, image)
|
138 |
+
|
139 |
+
global Images, classnames, encodeListKnown
|
140 |
+
Images, classnames = load_known_faces()
|
141 |
+
encodeListKnown = find_encodings(Images)
|
142 |
+
|
143 |
+
st.success(f"New face added for {new_name} ({roll_no}).")
|
144 |
+
else:
|
145 |
+
st.info("Camera is not active. Start the camera to take a picture.")
|
146 |
+
|
147 |
+
# --- Recognize Face and Emotion ---
|
148 |
+
def recognize_face():
|
149 |
+
if st.session_state.camera_active:
|
150 |
+
img_file_buffer = st.camera_input("Take a picture")
|
151 |
+
if img_file_buffer is not None:
|
152 |
+
st.session_state.camera_active = False # Stop camera after photo is taken
|
153 |
+
with st.spinner("Processing..."):
|
154 |
+
image = np.array(Image.open(img_file_buffer))
|
155 |
+
imgS = cv2.resize(image, (0, 0), None, 0.25, 0.25)
|
156 |
+
imgS = cv2.cvtColor(imgS, cv2.COLOR_BGR2RGB)
|
157 |
+
|
158 |
+
facesCurFrame = face_recognition.face_locations(imgS)
|
159 |
+
encodesCurFrame = face_recognition.face_encodings(imgS, facesCurFrame)
|
160 |
+
|
161 |
+
detected_emotions = []
|
162 |
+
if len(encodesCurFrame) > 0:
|
163 |
+
for encodeFace, faceLoc in zip(encodesCurFrame, facesCurFrame):
|
164 |
+
matches = face_recognition.compare_faces(encodeListKnown, encodeFace)
|
165 |
+
faceDis = face_recognition.face_distance(encodeListKnown, encodeFace)
|
166 |
+
matchIndex = np.argmin(faceDis)
|
167 |
+
|
168 |
+
if matches[matchIndex]:
|
169 |
+
name = classnames[matchIndex].split("_")[0]
|
170 |
+
roll_no = classnames[matchIndex].split("_")[1]
|
171 |
+
|
172 |
+
y1, x2, y2, x1 = faceLoc
|
173 |
+
y1, x2, y2, x1 = y1 * 4, x2 * 4, y2 * 4, x1 * 4
|
174 |
+
cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2)
|
175 |
+
cv2.putText(image, name, (x1 + 6, y2 - 6), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)
|
176 |
+
|
177 |
+
frame, detected_emotions = process_frame(image)
|
178 |
+
date = datetime.now().strftime('%Y-%m-%d')
|
179 |
+
time = datetime.now().strftime('%H:%M:%S')
|
180 |
+
emotion = detected_emotions[0] if detected_emotions else "Unknown"
|
181 |
+
|
182 |
+
cursor.execute("INSERT INTO attendance (name, roll_no, date, time, status, emotion) VALUES (?, ?, ?, ?, 'Present', ?)",
|
183 |
+
(name, roll_no, date, time, emotion))
|
184 |
+
conn.commit()
|
185 |
+
st.success(f"Attendance marked for {name} with emotion: {emotion}.")
|
186 |
+
else:
|
187 |
+
st.warning("Face not recognized.")
|
188 |
+
else:
|
189 |
+
st.warning("No face detected.")
|
190 |
+
st.image(image, caption="Detected Face and Emotion", use_container_width=True)
|
191 |
+
|
192 |
+
else:
|
193 |
+
st.info("Camera is not active. Start the camera to take a picture.")
|
194 |
+
|
195 |
+
# --- View Attendance Records ---
|
196 |
+
def view_attendance_records():
|
197 |
+
st.subheader("Attendance Records")
|
198 |
+
cursor.execute("SELECT * FROM attendance ORDER BY date DESC, time DESC")
|
199 |
+
records = cursor.fetchall()
|
200 |
+
|
201 |
+
if records:
|
202 |
+
df = pd.DataFrame(records, columns=["ID", "Name", "Roll No", "Date", "Time", "Status", "Emotion"])
|
203 |
+
st.table(df)
|
204 |
+
else:
|
205 |
+
st.info("No attendance records available.")
|
206 |
+
|
207 |
+
# --- Main Logic ---
|
208 |
+
if __name__ == "__main__":
|
209 |
+
st.title("EMOTION-MARK-AI (FACIAL SENTIMENT ANALYSIZED ATTENDANCE TRACKER)")
|
210 |
+
# Larger title
|
211 |
+
st.markdown("<h2 style='text-align: center;'>Can Recognise Face and Detect:</h2>", unsafe_allow_html=True)
|
212 |
+
# Smaller subtitle
|
213 |
+
st.markdown("<h3 style='text-align: center;'>Emotions: angry, fear, happy, neutral, sad, surprise </h3>", unsafe_allow_html=True)
|
214 |
+
|
215 |
+
app_mode = st.sidebar.selectbox("Select Mode", ["Recognize Face & Emotion", "Add New Face", "View Records"])
|
216 |
+
|
217 |
+
if app_mode == "Recognize Face & Emotion":
|
218 |
+
recognize_face()
|
219 |
+
elif app_mode == "Add New Face":
|
220 |
+
add_new_face()
|
221 |
+
elif app_mode == "View Records":
|
222 |
+
view_attendance_records()
|
223 |
+
|
224 |
+
conn.close()
|
attendance.db
ADDED
Binary file (12.3 kB). View file
|
|
requirements.txt
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
streamlit
|
2 |
+
opencv-python-headless
|
3 |
+
face_recognition @ git+https://github.com/ravinder2023/dlib_face_recognition.git
|
4 |
+
tensorflow
|
5 |
+
keras
|
6 |
+
pandas
|
7 |
+
numpy
|