Spaces:
Sleeping
Sleeping
import argparse | |
from scipy.spatial import distance as dist | |
from imutils import face_utils | |
import numpy as np | |
import imutils | |
import time | |
import dlib | |
import cv2 | |
import matplotlib.pyplot as plt | |
from keras.preprocessing.image import img_to_array | |
from keras.models import load_model | |
def eye_brow_distance(leye, reye): | |
global points | |
distq = dist.euclidean(leye, reye) | |
points.append(int(distq)) | |
return distq | |
def emotion_finder(faces, frame): | |
global emotion_classifier | |
EMOTIONS = ["angry", "disgust", "scared", "happy", "sad", "surprised", "neutral"] | |
x, y, w, h = face_utils.rect_to_bb(faces) | |
frame = frame[y:y + h, x:x + w] | |
roi = cv2.resize(frame, (64, 64)) | |
roi = roi.astype("float") / 255.0 | |
roi = img_to_array(roi) | |
roi = np.expand_dims(roi, axis=0) | |
preds = emotion_classifier.predict(roi)[0] | |
emotion_probability = np.max(preds) | |
label = EMOTIONS[preds.argmax()] | |
return label | |
def normalize_values(points, disp): | |
normalized_value = abs(disp - np.min(points)) / abs(np.max(points) - np.min(points)) | |
stress_value = np.exp(-(normalized_value)) | |
return stress_value | |
def stress(video_path, duration): | |
global points, emotion_classifier | |
detector = dlib.get_frontal_face_detector() | |
predictor = dlib.shape_predictor("stress_detection/models/data") | |
emotion_classifier = load_model("stress_detection/models/_mini_XCEPTION.102-0.66.hdf5", compile=False) | |
cap = cv2.VideoCapture(video_path) | |
points = [] | |
stress_labels = [] | |
start_time = time.time() | |
while True: | |
current_time = time.time() | |
if current_time - start_time >= duration: | |
break | |
ret, frame = cap.read() | |
if not ret: | |
break | |
frame = cv2.flip(frame, 1) | |
frame = imutils.resize(frame, width=500, height=500) | |
(lBegin, lEnd) = face_utils.FACIAL_LANDMARKS_IDXS["right_eyebrow"] | |
(rBegin, rEnd) = face_utils.FACIAL_LANDMARKS_IDXS["left_eyebrow"] | |
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) | |
try: | |
detections = detector(gray, 0) | |
for detection in detections: | |
emotion = emotion_finder(detection, gray) | |
shape = predictor(gray, detection) | |
shape = face_utils.shape_to_np(shape) | |
leyebrow = shape[lBegin:lEnd] | |
reyebrow = shape[rBegin:rEnd] | |
distq = eye_brow_distance(leyebrow[-1], reyebrow[0]) | |
stress_value = normalize_values(points, distq) | |
# Determine stress label for this frame | |
if emotion in ['scared', 'sad', 'angry'] and stress_value >= 0.75: | |
stress_label = 'stressed' | |
else: | |
stress_label = 'not stressed' | |
# Store stress label in list | |
stress_labels.append(stress_label) | |
except Exception as e: | |
print(f'Error: {e}') | |
key = cv2.waitKey(1) & 0xFF | |
if key == ord('q'): | |
break | |
cap.release() | |
# Count occurrences of 'stressed' and 'not stressed' | |
stressed_count = stress_labels.count('stressed') | |
not_stressed_count = stress_labels.count('not stressed') | |
# Determine which label occurred more frequently | |
if stressed_count > not_stressed_count: | |
most_frequent_label = 'stressed' | |
else: | |
most_frequent_label = 'not stressed' | |
return stressed_count, not_stressed_count, most_frequent_label | |
def main(): | |
# Argument parsing | |
parser = argparse.ArgumentParser(description='Stress Detection from Video') | |
parser.add_argument('--video', type=str, required=True, default='output.mp4', help='Path to the input video file') | |
parser.add_argument('--duration', type=int, default=30, help='Duration for analysis in seconds') | |
args = parser.parse_args() | |
# Call the stress function and get the results | |
stressed_count, not_stressed_count, most_frequent_label = stress(args.video, args.duration) | |
# Display the result | |
print(f"Stressed frames: {stressed_count}") | |
print(f"Not stressed frames: {not_stressed_count}") | |
print(f"Most frequent state: {most_frequent_label}") | |
if __name__ == '__main__': | |
main() | |