|
|
import streamlit as st
|
|
|
import cv2
|
|
|
import numpy as np
|
|
|
import dlib
|
|
|
from scipy.spatial import distance as dist
|
|
|
from imutils import face_utils
|
|
|
|
|
|
|
|
|
EYE_AR_THRESH = 0.3
|
|
|
EYE_AR_CONSEC_FRAMES = 30
|
|
|
YAWN_THRESH = 20
|
|
|
|
|
|
|
|
|
COUNTER = 0
|
|
|
|
|
|
|
|
|
def eye_aspect_ratio(eye):
|
|
|
A = dist.euclidean(eye[1], eye[5])
|
|
|
B = dist.euclidean(eye[2], eye[4])
|
|
|
C = dist.euclidean(eye[0], eye[3])
|
|
|
ear = (A + B) / (2.0 * C)
|
|
|
return ear
|
|
|
|
|
|
def final_ear(shape):
|
|
|
(lStart, lEnd) = face_utils.FACIAL_LANDMARKS_IDXS["left_eye"]
|
|
|
(rStart, rEnd) = face_utils.FACIAL_LANDMARKS_IDXS["right_eye"]
|
|
|
leftEye = shape[lStart:lEnd]
|
|
|
rightEye = shape[rStart:rEnd]
|
|
|
leftEAR = eye_aspect_ratio(leftEye)
|
|
|
rightEAR = eye_aspect_ratio(rightEye)
|
|
|
ear = (leftEAR + rightEAR) / 2.0
|
|
|
return (ear, leftEye, rightEye)
|
|
|
|
|
|
def lip_distance(shape):
|
|
|
top_lip = shape[50:53]
|
|
|
top_lip = np.concatenate((top_lip, shape[61:64]))
|
|
|
low_lip = shape[56:59]
|
|
|
low_lip = np.concatenate((low_lip, shape[65:68]))
|
|
|
top_mean = np.mean(top_lip, axis=0)
|
|
|
low_mean = np.mean(low_lip, axis=0)
|
|
|
distance = abs(top_mean[1] - low_mean[1])
|
|
|
return distance
|
|
|
|
|
|
def process_frame(frame, detector, predictor):
|
|
|
"""Process the frame and detect drowsiness and yawning."""
|
|
|
global COUNTER
|
|
|
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
|
|
rects = detector.detectMultiScale(
|
|
|
gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30), flags=cv2.CASCADE_SCALE_IMAGE
|
|
|
)
|
|
|
|
|
|
for (x, y, w, h) in rects:
|
|
|
rect = dlib.rectangle(int(x), int(y), int(x + w), int(y + h))
|
|
|
shape = predictor(gray, rect)
|
|
|
shape = face_utils.shape_to_np(shape)
|
|
|
|
|
|
ear, leftEye, rightEye = final_ear(shape)
|
|
|
distance = lip_distance(shape)
|
|
|
|
|
|
leftEyeHull = cv2.convexHull(leftEye)
|
|
|
rightEyeHull = cv2.convexHull(rightEye)
|
|
|
cv2.drawContours(frame, [leftEyeHull], -1, (0, 255, 0), 1)
|
|
|
cv2.drawContours(frame, [rightEyeHull], -1, (0, 255, 0), 1)
|
|
|
|
|
|
lip = shape[48:60]
|
|
|
cv2.drawContours(frame, [lip], -1, (0, 255, 0), 1)
|
|
|
|
|
|
if ear < EYE_AR_THRESH:
|
|
|
COUNTER += 1
|
|
|
if COUNTER >= EYE_AR_CONSEC_FRAMES:
|
|
|
cv2.putText(frame, "DROWSINESS", (10, 30),
|
|
|
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
|
|
|
else:
|
|
|
COUNTER = 0
|
|
|
|
|
|
if distance > YAWN_THRESH:
|
|
|
cv2.putText(frame, "YAWN", (10, 60),
|
|
|
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
|
|
|
|
|
|
cv2.putText(frame, f"EAR: {ear:.2f}", (300, 30),
|
|
|
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
|
|
|
cv2.putText(frame, f"YAWN: {distance:.2f}", (300, 60),
|
|
|
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
|
|
|
|
|
|
return frame
|
|
|
|
|
|
|
|
|
detector = cv2.CascadeClassifier('./haarcascade_frontalface_default.xml')
|
|
|
predictor = dlib.shape_predictor('./shape_predictor_68_face_landmarks.dat')
|
|
|
|
|
|
|
|
|
st.title("Sleep Detection using OpenCV")
|
|
|
st.markdown("**Check the box below to start the camera:**")
|
|
|
|
|
|
run = st.checkbox("Run Camera")
|
|
|
|
|
|
|
|
|
if run:
|
|
|
cap = cv2.VideoCapture(0)
|
|
|
FRAME_WINDOW = st.image([])
|
|
|
|
|
|
while True:
|
|
|
ret, frame = cap.read()
|
|
|
if not ret:
|
|
|
st.error("Failed to open webcam.")
|
|
|
break
|
|
|
|
|
|
frame = cv2.resize(frame, (450, 300))
|
|
|
frame = process_frame(frame, detector, predictor)
|
|
|
FRAME_WINDOW.image(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
|
|
|
else:
|
|
|
st.info("Check 'Run Camera' to start detection.") |