LovnishVerma commited on
Commit
a6b4b4a
·
verified ·
1 Parent(s): 2bb6e06

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +252 -102
app.py CHANGED
@@ -1,49 +1,55 @@
1
  import streamlit as st
2
  import cv2
3
- import os
4
  import numpy as np
 
 
5
  from keras.models import load_model
6
  from PIL import Image
7
- import sqlite3
8
  from huggingface_hub import HfApi
9
- from datetime import datetime
10
- from sklearn.preprocessing import LabelEncoder
 
 
 
 
 
 
11
 
12
  # Constants
13
  KNOWN_FACES_DIR = "known_faces" # Directory to save user images
14
  DATABASE = "students.db" # SQLite database file to store student information
15
- EMOTION_MODEL_FILE = "CNN_Model_acc_75.h5"
16
- EMOTION_LABELS = ["Angry", "Disgust", "Fear", "Happy", "Sad", "Surprise", "Neutral"]
17
- REPO_NAME = "face_and_emotion_detection"
18
- REPO_ID = f"LovnishVerma/{REPO_NAME}"
19
 
20
- # Ensure the directories exist
21
  os.makedirs(KNOWN_FACES_DIR, exist_ok=True)
22
 
23
- # Retrieve Hugging Face token from environment variable
24
- hf_token = os.getenv("upload") # Replace with your actual Hugging Face token
25
  if not hf_token:
26
- st.error("Hugging Face token not found. Please set the environment variable.")
27
- st.stop()
28
 
29
  # Initialize Hugging Face API
30
  api = HfApi()
 
 
 
 
 
 
 
31
  try:
32
- api.create_repo(repo_id=REPO_ID, repo_type="space", space_sdk="streamlit", token=hf_token, exist_ok=True)
33
  st.success(f"Repository '{REPO_NAME}' is ready on Hugging Face!")
34
  except Exception as e:
35
- st.error(f"Error creating Hugging Face repository: {e}")
36
 
37
- # Load the emotion detection model
38
- try:
39
- emotion_model = load_model(EMOTION_MODEL_FILE)
40
- except Exception as e:
41
- st.error(f"Error loading emotion model: {e}")
42
- st.stop()
43
 
44
- # Database Functions
45
  def initialize_database():
46
- """ Initializes the SQLite database by creating the students table if it doesn't exist. """
 
 
 
47
  conn = sqlite3.connect(DATABASE)
48
  cursor = conn.cursor()
49
  cursor.execute("""
@@ -59,7 +65,15 @@ def initialize_database():
59
  conn.close()
60
 
61
  def save_to_database(name, roll_no, image_path):
62
- """ Saves the student's data to the database. """
 
 
 
 
 
 
 
 
63
  conn = sqlite3.connect(DATABASE)
64
  cursor = conn.cursor()
65
  try:
@@ -75,17 +89,38 @@ def save_to_database(name, roll_no, image_path):
75
  conn.close()
76
 
77
  def save_image_to_hugging_face(image, name, roll_no):
78
- """ Saves the image locally and uploads it to Hugging Face. """
 
 
 
 
 
 
 
 
 
 
 
 
79
  filename = f"{name}_{roll_no}.jpg"
80
  local_path = os.path.join(KNOWN_FACES_DIR, filename)
81
- image.save(local_path)
82
 
 
 
 
 
83
  try:
84
- api.upload_file(path_or_fileobj=local_path, path_in_repo=filename, repo_id=REPO_ID, repo_type="space", token=hf_token)
 
 
 
 
 
 
85
  st.success(f"Image uploaded to Hugging Face: {filename}")
86
  except Exception as e:
87
  st.error(f"Error uploading image to Hugging Face: {e}")
88
-
89
  return local_path
90
 
91
  # Initialize the database when the app starts
@@ -98,22 +133,32 @@ st.title("Student Registration with Hugging Face Image Upload")
98
  name = st.text_input("Enter your name")
99
  roll_no = st.text_input("Enter your roll number")
100
 
101
- # Choose input method for the image (only webcam now)
102
- capture_mode = "Use Webcam" # Only keep the webcam option now
103
 
104
- # Handle webcam capture
105
- picture = st.camera_input("Take a picture") # Capture image using webcam
 
 
 
 
 
 
 
 
106
 
107
  # Save data and process image on button click
108
  if st.button("Register"):
109
  if not name or not roll_no:
110
  st.error("Please fill in both name and roll number.")
111
  elif not picture:
112
- st.error("Please capture an image using the webcam.")
113
  else:
114
  try:
115
  # Open the image based on capture mode
116
- if picture:
 
 
117
  image = Image.open(picture)
118
 
119
  # Save the image locally and upload it to Hugging Face
@@ -136,81 +181,186 @@ if st.checkbox("Show registered students"):
136
  st.write(f"**Name:** {name}, **Roll No:** {roll_no}, **Timestamp:** {timestamp}")
137
  st.image(image_path, caption=f"{name} ({roll_no})", use_column_width=True)
138
 
139
- # Initialize OpenCV's face detector (Haar Cascade)
140
- face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
141
 
142
- # Initialize LBPH face recognizer
143
- face_recognizer = cv2.face_LBPHFaceRecognizer_create()
 
 
 
 
 
 
 
144
 
145
- # Function to load and train face recognizer
146
- def train_face_recognizer():
147
- faces = []
148
- labels = []
149
- label_encoder = LabelEncoder()
150
 
151
- # Load known faces
152
- for filename in os.listdir(KNOWN_FACES_DIR):
153
- if filename.endswith(".jpg"):
154
- image_path = os.path.join(KNOWN_FACES_DIR, filename)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  image = cv2.imread(image_path)
156
- gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
157
-
158
- # Detect face(s)
159
- faces_detected = face_cascade.detectMultiScale(gray_image, 1.3, 5)
160
- for (x, y, w, h) in faces_detected:
161
- face = gray_image[y:y+h, x:x+w]
162
- faces.append(face)
163
- labels.append(filename.split('_')[0]) # Assuming name is in the filename
164
-
165
- labels = label_encoder.fit_transform(labels)
166
- face_recognizer.train(faces, np.array(labels))
167
- st.success("Face recognizer trained successfully!")
168
 
169
- train_face_recognizer()
 
 
 
 
170
 
171
- # Face and Emotion Detection Function
172
- def detect_faces_and_emotions(image):
173
- # Convert the image to grayscale for face detection
174
- gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
175
 
176
- # Detect faces using OpenCV's Haar Cascade
177
- faces = face_cascade.detectMultiScale(gray_image, scaleFactor=1.3, minNeighbors=5)
 
 
 
 
 
 
 
 
 
178
 
179
- # If faces are detected, predict emotions and recognize faces
180
  for (x, y, w, h) in faces:
181
- face = gray_image[y:y+h, x:x+w]
182
- resized_face = cv2.resize(face, (48, 48)) # Resize face to 48x48
183
- rgb_face = cv2.cvtColor(resized_face, cv2.COLOR_BGR2RGB)
184
- normalized_face = rgb_face / 255.0
185
- reshaped_face = np.reshape(normalized_face, (1, 48, 48, 3))
186
-
187
- # Predict the emotion
188
- emotion_prediction = emotion_model.predict(reshaped_face)
189
- emotion_label = np.argmax(emotion_prediction)
190
-
191
- # Recognize the face
192
- label, confidence = face_recognizer.predict(face)
193
- recognized_label = label_encoder.inverse_transform([label])[0]
194
-
195
- return EMOTION_LABELS[emotion_label], recognized_label
196
-
197
- return None, None
198
 
199
- # UI for Emotion Detection (Only using webcam now)
200
- if st.sidebar.selectbox("Menu", ["Register Student", "Face Recognition and Emotion Detection", "View Attendance"]) == "Face Recognition and Emotion Detection":
201
- st.subheader("Recognize Faces and Detect Emotions")
202
-
203
- st.info("Use the camera input widget to capture an image.")
204
- camera_image = st.camera_input("Take a picture")
205
- if camera_image:
206
- img = Image.open(camera_image)
207
- img_array = np.array(img)
208
-
209
- # Detect emotion and recognize face in the captured image
210
- emotion_label, recognized_label = detect_faces_and_emotions(img_array)
211
-
212
- if emotion_label:
213
- st.success(f"Emotion Detected: {emotion_label}")
214
- st.success(f"Face Recognized as: {recognized_label}")
215
- else:
216
- st.warning("No face detected.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
  import cv2
 
3
  import numpy as np
4
+ import time
5
+ import os
6
  from keras.models import load_model
7
  from PIL import Image
8
+ import tempfile
9
  from huggingface_hub import HfApi
10
+
11
+ # Larger title
12
+ st.markdown("<h1 style='text-align: center;'>Emotion Detection with Face Recognition</h1>", unsafe_allow_html=True)
13
+
14
+ # Smaller subtitle
15
+ st.markdown("<h3 style='text-align: center;'>angry, fear, happy, neutral, sad, surprise</h3>", unsafe_allow_html=True)
16
+
17
+ start = time.time()
18
 
19
  # Constants
20
  KNOWN_FACES_DIR = "known_faces" # Directory to save user images
21
  DATABASE = "students.db" # SQLite database file to store student information
 
 
 
 
22
 
23
+ # Ensure the directory exists
24
  os.makedirs(KNOWN_FACES_DIR, exist_ok=True)
25
 
26
+ # Retrieve the Hugging Face token from environment variable
27
+ hf_token = os.getenv("upload") # The key must match the secret name set in Hugging Face
28
  if not hf_token:
29
+ raise ValueError("Hugging Face token not found. Ensure it's set as a secret in the Hugging Face Space.")
 
30
 
31
  # Initialize Hugging Face API
32
  api = HfApi()
33
+
34
+ # Repository Details on Hugging Face
35
+ REPO_NAME = "face_and_emotion_detection" # Replace with your Hugging Face repository name
36
+ REPO_ID = "LovnishVerma/" + REPO_NAME # Replace "LovnishVerma" with your Hugging Face username
37
+ REPO_TYPE = "space" # 'space' type for Streamlit-based projects
38
+
39
+ # Ensure the repository exists or create it
40
  try:
41
+ api.create_repo(repo_id=REPO_ID, repo_type=REPO_TYPE, space_sdk="streamlit", token=hf_token, exist_ok=True)
42
  st.success(f"Repository '{REPO_NAME}' is ready on Hugging Face!")
43
  except Exception as e:
44
+ st.error(f"Error creating repository: {e}")
45
 
 
 
 
 
 
 
46
 
47
+ # Database setup
48
  def initialize_database():
49
+ """
50
+ Initializes the SQLite database by creating a table to store student data
51
+ such as name, roll number, image path, and registration timestamp.
52
+ """
53
  conn = sqlite3.connect(DATABASE)
54
  cursor = conn.cursor()
55
  cursor.execute("""
 
65
  conn.close()
66
 
67
  def save_to_database(name, roll_no, image_path):
68
+ """
69
+ Saves the student's information (name, roll number, image path) to the SQLite database.
70
+ Ensures roll number is unique.
71
+
72
+ Args:
73
+ name (str): The name of the student.
74
+ roll_no (str): The roll number of the student.
75
+ image_path (str): Path to the stored image of the student.
76
+ """
77
  conn = sqlite3.connect(DATABASE)
78
  cursor = conn.cursor()
79
  try:
 
89
  conn.close()
90
 
91
  def save_image_to_hugging_face(image, name, roll_no):
92
+ """
93
+ Saves the captured image locally in the 'known_faces' directory and uploads it to Hugging Face.
94
+ The image is renamed using the format 'UserName_RollNo.jpg'.
95
+
96
+ Args:
97
+ image (PIL Image): The image object captured by the user.
98
+ name (str): The name of the student.
99
+ roll_no (str): The roll number of the student.
100
+
101
+ Returns:
102
+ str: The local path where the image is saved.
103
+ """
104
+ # Rename the image using the format 'UserName_RollNo.jpg'
105
  filename = f"{name}_{roll_no}.jpg"
106
  local_path = os.path.join(KNOWN_FACES_DIR, filename)
 
107
 
108
+ # Save the image locally to the known_faces directory
109
+ image.save(local_path)
110
+
111
+ # Try uploading the image to Hugging Face
112
  try:
113
+ api.upload_file(
114
+ path_or_fileobj=local_path,
115
+ path_in_repo=filename,
116
+ repo_id=REPO_ID,
117
+ repo_type=REPO_TYPE,
118
+ token=hf_token # Pass the Hugging Face token directly
119
+ )
120
  st.success(f"Image uploaded to Hugging Face: {filename}")
121
  except Exception as e:
122
  st.error(f"Error uploading image to Hugging Face: {e}")
123
+
124
  return local_path
125
 
126
  # Initialize the database when the app starts
 
133
  name = st.text_input("Enter your name")
134
  roll_no = st.text_input("Enter your roll number")
135
 
136
+ # Choose input method for the image (webcam or file upload)
137
+ capture_mode = st.radio("Choose an option to upload your image", ["Use Webcam", "Upload File"])
138
 
139
+ # Handle webcam capture or file upload
140
+ if capture_mode == "Use Webcam":
141
+ try:
142
+ picture = st.camera_input("Take a picture") # Capture image using webcam
143
+ except Exception as e:
144
+ st.error(f"Error accessing webcam: {e}")
145
+ picture = None
146
+
147
+ elif capture_mode == "Upload File":
148
+ picture = st.file_uploader("Upload an image", type=["jpg", "jpeg", "png"]) # Upload image from file system
149
 
150
  # Save data and process image on button click
151
  if st.button("Register"):
152
  if not name or not roll_no:
153
  st.error("Please fill in both name and roll number.")
154
  elif not picture:
155
+ st.error("Please upload or capture an image.")
156
  else:
157
  try:
158
  # Open the image based on capture mode
159
+ if capture_mode == "Use Webcam" and picture:
160
+ image = Image.open(picture)
161
+ elif capture_mode == "Upload File" and picture:
162
  image = Image.open(picture)
163
 
164
  # Save the image locally and upload it to Hugging Face
 
181
  st.write(f"**Name:** {name}, **Roll No:** {roll_no}, **Timestamp:** {timestamp}")
182
  st.image(image_path, caption=f"{name} ({roll_no})", use_column_width=True)
183
 
 
 
184
 
185
+ # Constants
186
+ DB_FILE = "students.db"
187
+ KNOWN_FACES_DIR = "known_faces"
188
+ EMOTION_MODEL_FILE = "CNN_Model_acc_75.h5"
189
+ EMOTION_LABELS = ["Angry", "Disgust", "Fear", "Happy", "Sad", "Surprise", "Neutral"]
190
+
191
+ # Hugging Face Repository Details
192
+ REPO_NAME = "face_and_emotion_detection"
193
+ REPO_ID = f"LovnishVerma/{REPO_NAME}" # Replace with your Hugging Face username and repository name
194
 
195
+ # Ensure Directories
196
+ os.makedirs(KNOWN_FACES_DIR, exist_ok=True)
 
 
 
197
 
198
+ # Load Hugging Face Token
199
+ hf_token = os.getenv("upload")
200
+ if not hf_token:
201
+ st.error("Hugging Face token not found. Please set the environment variable.")
202
+
203
+ # Initialize Hugging Face API
204
+ api = HfApi()
205
+ try:
206
+ api.create_repo(repo_id=REPO_ID, repo_type="space", space_sdk="streamlit", token=hf_token, exist_ok=True)
207
+ st.success(f"Repository '{REPO_NAME}' is ready on Hugging Face!")
208
+ except Exception as e:
209
+ st.error(f"Error creating Hugging Face repository: {e}")
210
+
211
+ # Load Emotion Model
212
+ try:
213
+ emotion_model = load_model(EMOTION_MODEL_FILE)
214
+ except Exception as e:
215
+ st.error(f"Error loading emotion model: {e}")
216
+
217
+ # Database Functions
218
+ def create_table():
219
+ with sqlite3.connect(DB_FILE) as conn:
220
+ conn.execute("""CREATE TABLE IF NOT EXISTS students (
221
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
222
+ name TEXT NOT NULL,
223
+ roll_number TEXT NOT NULL UNIQUE,
224
+ image_path TEXT NOT NULL)""")
225
+ conn.commit()
226
+
227
+ def insert_student(name, roll_number, image_path):
228
+ try:
229
+ with sqlite3.connect(DB_FILE) as conn:
230
+ conn.execute("INSERT INTO students (name, roll_number, image_path) VALUES (?, ?, ?)",
231
+ (name, roll_number, image_path))
232
+ conn.commit()
233
+ except sqlite3.IntegrityError:
234
+ st.warning("Roll number already exists!")
235
+
236
+ def get_all_students():
237
+ with sqlite3.connect(DB_FILE) as conn:
238
+ cursor = conn.execute("SELECT * FROM students")
239
+ return cursor.fetchall()
240
+
241
+ # Load the emotion model
242
+ @st.cache_resource
243
+ def load_emotion_model():
244
+ model = load_model('CNN_Model_acc_75.h5') # Ensure this file is in your Space
245
+ return model
246
+
247
+ model = load_emotion_model()
248
+ print("time taken to load model: ", time.time() - start)
249
+
250
+ # Emotion labels
251
+ emotion_labels = ['angry', 'fear', 'happy', 'neutral', 'sad', 'surprise']
252
+
253
+ # Load known faces (from images in a folder)
254
+ known_faces = []
255
+ known_names = []
256
+ face_recognizer = cv2.face.LBPHFaceRecognizer_create()
257
+
258
+ def load_known_faces():
259
+ folder_path = "known_faces" # Place your folder with known faces here
260
+ for image_name in os.listdir(folder_path):
261
+ if image_name.endswith(('.jpg', '.jpeg', '.png')):
262
+ image_path = os.path.join(folder_path, image_name)
263
  image = cv2.imread(image_path)
264
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
265
+ # Detect face in the image
266
+ faces = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml').detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
 
 
 
 
 
 
 
 
 
267
 
268
+ for (x, y, w, h) in faces:
269
+ roi_gray = gray[y:y+h, x:x+w]
270
+ # We only need the face, so we crop it and store it for training
271
+ known_faces.append(roi_gray)
272
+ known_names.append(image_name.split('.')[0]) # Assuming file name is the person's name
273
 
274
+ # Train the recognizer with the known faces
275
+ face_recognizer.train(known_faces, np.array([i for i in range(len(known_faces))]))
 
 
276
 
277
+ load_known_faces()
278
+
279
+ # Face detection using OpenCV
280
+ face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
281
+ img_shape = 48
282
+
283
+ def process_frame(frame):
284
+ gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
285
+ faces = face_cascade.detectMultiScale(gray_frame, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
286
+
287
+ result_text = "" # Initialize the result text for display
288
 
 
289
  for (x, y, w, h) in faces:
290
+ roi_gray = gray_frame[y:y+h, x:x+w]
291
+ roi_color = frame[y:y+h, x:x+w]
292
+ face_roi = cv2.resize(roi_color, (img_shape, img_shape)) # Resize to 48x48
293
+ face_roi = cv2.cvtColor(face_roi, cv2.COLOR_BGR2RGB) # Convert to RGB (3 channels)
294
+ face_roi = np.expand_dims(face_roi, axis=0) # Add batch dimension
295
+ face_roi = face_roi / 255.0 # Normalize the image
 
 
 
 
 
 
 
 
 
 
 
296
 
297
+ # Emotion detection
298
+ predictions = model.predict(face_roi)
299
+ emotion = emotion_labels[np.argmax(predictions[0])]
300
+
301
+ # Face recognition using LBPH
302
+ label, confidence = face_recognizer.predict(roi_gray)
303
+ name = "Unknown"
304
+ if confidence < 100:
305
+ name = known_names[label]
306
+
307
+ # Format the result text as "Name is feeling Emotion"
308
+ result_text = f"{name} is feeling {emotion}"
309
+
310
+ # Draw bounding box and label on the frame
311
+ cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
312
+ cv2.putText(frame, result_text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
313
+
314
+ return frame, result_text
315
+
316
+ # Video feed
317
+ def video_feed(video_source):
318
+ frame_placeholder = st.empty() # This placeholder will be used to replace frames in-place
319
+ text_placeholder = st.empty() # This placeholder will display the result text
320
+
321
+ while True:
322
+ ret, frame = video_source.read()
323
+ if not ret:
324
+ break
325
+
326
+ frame, result_text = process_frame(frame)
327
+
328
+ # Display the frame in the placeholder
329
+ frame_placeholder.image(frame, channels="BGR", use_column_width=True)
330
+
331
+ # Display the result text in the text placeholder
332
+ text_placeholder.markdown(f"<h3 style='text-align: center;'>{result_text}</h3>", unsafe_allow_html=True)
333
+
334
+ # Sidebar for video or image upload
335
+ upload_choice = st.sidebar.radio("Choose input source", ["Upload Image", "Upload Video", "Camera"])
336
+
337
+ if upload_choice == "Camera":
338
+ # Use Streamlit's built-in camera input widget for capturing images from the webcam
339
+ image = st.camera_input("Take a picture")
340
+
341
+ if image is not None:
342
+ # Convert the image to a numpy array
343
+ frame = np.array(Image.open(image))
344
+ frame, result_text = process_frame(frame)
345
+ st.image(frame, caption='Processed Image', use_column_width=True)
346
+ st.markdown(f"<h3 style='text-align: center;'>{result_text}</h3>", unsafe_allow_html=True)
347
+
348
+ elif upload_choice == "Upload Image":
349
+ uploaded_image = st.file_uploader("Upload Image", type=["png", "jpg", "jpeg", "gif"])
350
+ if uploaded_image:
351
+ image = Image.open(uploaded_image)
352
+ frame = np.array(image)
353
+ frame, result_text = process_frame(frame)
354
+ st.image(frame, caption='Processed Image', use_column_width=True)
355
+ st.markdown(f"<h3 style='text-align: center;'>{result_text}</h3>", unsafe_allow_html=True)
356
+
357
+ elif upload_choice == "Upload Video":
358
+ uploaded_video = st.file_uploader("Upload Video", type=["mp4", "mov", "avi", "mkv", "webm"])
359
+ if uploaded_video:
360
+ # Temporarily save the video to disk
361
+ with tempfile.NamedTemporaryFile(delete=False) as tfile:
362
+ tfile.write(uploaded_video.read())
363
+ video_source = cv2.VideoCapture(tfile.name)
364
+ video_feed(video_source)
365
+
366
+ st.sidebar.write("Emotion Labels: Angry, Fear, Happy, Neutral, Sad, Surprise")