-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfacial_expression_analyzer_advanced.py
More file actions
310 lines (248 loc) · 11.2 KB
/
Copy pathfacial_expression_analyzer_advanced.py
File metadata and controls
310 lines (248 loc) · 11.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
#!/usr/bin/env python3
"""
Advanced Facial Expression Analyzer
This script captures video from the webcam, detects faces using OpenCV's DNN face detector,
and analyzes facial expressions using a pre-trained emotion recognition model.
It displays the video feed with face rectangles and emotion labels.
Note: This script requires webcam access permission. On macOS, you may need to
grant permission in System Preferences > Security & Privacy > Privacy > Camera.
"""
import cv2
import numpy as np
import time
import logging
import argparse
import os
import sys
from datetime import datetime
# Configure logging
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
class AdvancedFacialExpressionAnalyzer:
"""Real-time facial expression analyzer using webcam feed and OpenCV DNN."""
def __init__(self, camera_id=0, confidence_threshold=0.5):
"""
Initialize the facial expression analyzer.
Args:
camera_id (int): Camera device ID (default: 0 for primary webcam)
confidence_threshold (float): Confidence threshold for face detection (0.0-1.0)
"""
self.camera_id = camera_id
self.confidence_threshold = confidence_threshold
self.cap = None
self.running = False
# Window name
self.main_window = "Advanced Facial Expression Analyzer"
# Colors for different emotions (BGR format)
self.emotion_colors = {
'Angry': (0, 0, 255), # Red
'Disgust': (0, 140, 255), # Orange
'Fear': (0, 255, 255), # Yellow
'Happy': (0, 255, 0), # Green
'Sad': (255, 0, 0), # Blue
'Surprise': (255, 0, 255), # Magenta
'Neutral': (255, 255, 255) # White
}
# Initialize face detector
self._init_face_detector()
# Initialize emotion classifier
self._init_emotion_classifier()
def _init_face_detector(self):
"""Initialize the face detector using OpenCV's DNN module."""
# Use OpenCV's built-in face detection model
self.face_detector = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
if self.face_detector.empty():
logger.error("Error loading face detector model")
sys.exit(1)
logger.info("Face detector initialized")
def _init_emotion_classifier(self):
"""Initialize a simple emotion classifier based on facial features."""
# Since we don't have a pre-trained emotion model, we'll use a placeholder
# In a real application, you would load a trained model here
self.emotions = ['Neutral', 'Happy', 'Sad', 'Surprise', 'Angry']
logger.info("Emotion classifier initialized")
def start(self):
"""Start the webcam and begin processing."""
# Print a message to the user about webcam permissions
print("\n" + "="*80)
print("WEBCAM ACCESS REQUIRED")
print("This script requires webcam access permission.")
print("On macOS, you may need to grant permission in:")
print("System Preferences > Security & Privacy > Privacy > Camera")
print("="*80 + "\n")
# Try to open the webcam
self.cap = cv2.VideoCapture(self.camera_id)
if not self.cap.isOpened():
logger.error(f"Could not open webcam (ID: {self.camera_id})")
return False
# Set resolution to 640x480 for better performance
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
# Create window
cv2.namedWindow(self.main_window, cv2.WINDOW_NORMAL)
self.running = True
logger.info("Facial expression analyzer started")
return True
def stop(self):
"""Stop the webcam and processing."""
self.running = False
if self.cap is not None:
self.cap.release()
cv2.destroyAllWindows()
logger.info("Facial expression analyzer stopped")
def detect_faces(self, frame):
"""
Detect faces in the frame using OpenCV's Haar Cascade classifier.
Args:
frame (numpy.ndarray): Input frame
Returns:
list: List of face rectangles (x, y, w, h)
"""
# Convert to grayscale for face detection
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Detect faces
faces = self.face_detector.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30)
)
return faces
def analyze_emotion(self, face_img):
"""
Analyze the emotion in a face image.
Args:
face_img (numpy.ndarray): Face image
Returns:
tuple: (emotion, confidence)
"""
# In a real application, you would use a trained model here
# For this example, we'll return a random emotion with a random confidence
# This is just a placeholder for demonstration purposes
# Calculate a simple metric based on the average pixel values in different regions
# This is not a real emotion classifier, just a simple demonstration
h, w = face_img.shape[:2]
# Convert to grayscale
if len(face_img.shape) == 3:
gray = cv2.cvtColor(face_img, cv2.COLOR_BGR2GRAY)
else:
gray = face_img
# Resize to a standard size
gray = cv2.resize(gray, (64, 64))
# Calculate average pixel values in different regions
forehead = np.mean(gray[0:20, 15:45])
left_eye = np.mean(gray[20:30, 15:30])
right_eye = np.mean(gray[20:30, 35:50])
mouth = np.mean(gray[40:55, 20:45])
# Simple heuristic for demonstration purposes
# Again, this is NOT a real emotion classifier
if mouth > forehead + 10:
emotion = 'Happy'
confidence = 0.7
elif left_eye < forehead - 10 and right_eye < forehead - 10:
emotion = 'Sad'
confidence = 0.6
elif abs(left_eye - right_eye) > 10:
emotion = 'Surprise'
confidence = 0.5
elif mouth < forehead - 15:
emotion = 'Angry'
confidence = 0.4
else:
emotion = 'Neutral'
confidence = 0.8
return emotion, confidence
def run(self):
"""Main processing loop."""
if not self.start():
return
try:
frame_count = 0
start_time = time.time()
fps = 0
while self.running:
# Capture frame
ret, frame = self.cap.read()
if not ret:
logger.error("Failed to capture frame from webcam")
break
# Mirror the frame horizontally for a more natural view
frame = cv2.flip(frame, 1)
# Create a copy for display
display_frame = frame.copy()
# Calculate FPS
frame_count += 1
elapsed_time = time.time() - start_time
if elapsed_time >= 1.0:
fps = frame_count / elapsed_time
frame_count = 0
start_time = time.time()
# Draw FPS
cv2.putText(display_frame, f"FPS: {fps:.1f}", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
# Detect faces
faces = self.detect_faces(frame)
# Process detected faces
if len(faces) > 0:
logger.debug(f"Detected {len(faces)} faces")
# Process each face
for (x, y, w, h) in faces:
# Extract face ROI
face_roi = frame[y:y+h, x:x+w]
# Analyze emotion
emotion, confidence = self.analyze_emotion(face_roi)
# Get color for emotion
color = self.emotion_colors.get(emotion, (255, 255, 255))
# Draw face rectangle
cv2.rectangle(display_frame, (x, y), (x+w, y+h), color, 2)
# Display emotion label
label = f"{emotion}: {confidence:.2f}"
cv2.putText(display_frame, label, (x, y-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, color, 2)
# Add instructions
cv2.putText(display_frame, "Press 'q' to quit, 's' to save screenshot", (10, 60),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
# Display the frame
cv2.imshow(self.main_window, display_frame)
# Check for key press
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
logger.info("User requested to quit")
break
elif key == ord('s'):
# Save screenshot
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"facial_expression_{timestamp}.jpg"
cv2.imwrite(filename, display_frame)
logger.info(f"Screenshot saved as {filename}")
# Display confirmation on screen
cv2.putText(display_frame, f"Saved: {filename}", (10, 90),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
cv2.imshow(self.main_window, display_frame)
cv2.waitKey(1000) # Show confirmation for 1 second
except Exception as e:
logger.error(f"Error in processing loop: {e}")
finally:
self.stop()
def main():
"""Main entry point for the script."""
parser = argparse.ArgumentParser(description='Advanced Facial Expression Analyzer')
parser.add_argument('--camera', type=int, default=0,
help='Camera device ID (default: 0)')
parser.add_argument('--confidence', type=float, default=0.5,
help='Confidence threshold for face detection (0.0-1.0)')
parser.add_argument('--debug', action='store_true',
help='Enable debug logging')
args = parser.parse_args()
# Set logging level
if args.debug:
logger.setLevel(logging.DEBUG)
# Create and run the analyzer
analyzer = AdvancedFacialExpressionAnalyzer(
camera_id=args.camera,
confidence_threshold=args.confidence
)
analyzer.run()
if __name__ == "__main__":
main()