对以下代码在不改变功能的情况下,简化代码。import cv2
import dlib
import math
import numpy as np
import time
from scipy.spatial import distance as dist
# Load detector
detector = dlib.get_frontal_face_detector()
# Load predictor
try:
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
except Exception as e:
print(f"Failed to load model file: {e}")
exit()
# Define facial landmarks indices
MOUTH_POINTS = list(range(48, 68))
LEFT_EYE_POINTS = list(range(36, 42))
RIGHT_EYE_POINTS = list(range(42, 48))
# Euclidean distance calculation
def euclidean_distance(point1, point2):
return math.sqrt((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2)
# Mouth Aspect Ratio calculation
def mouth_aspect_ratio(mouth_points):
if len(mouth_points) < 11:
return 0.0
# Vertical distances
A = euclidean_distance(mouth_points[2], mouth_points[10])
B = euclidean_distance(mouth_points[4], mouth_points[8])
# Horizontal distance
C = euclidean_distance(mouth_points[0], mouth_points[6])
mar = (A + B) / (2.0 * C)
return mar
# Eye Aspect Ratio (EAR) calculation
def eye_aspect_ratio(eye_points):
A = dist.euclidean(eye_points[1], eye_points[5])
B = dist.euclidean(eye_points[2], eye_points[4])
C = dist.euclidean(eye_points[0], eye_points[3])
ear = (A + B) / (2.0 * C)
return ear
# Initialize video capture
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("Failed to open camera")
exit()
# Get screen resolution for window sizing
try:
# Default to 1080p
screen_width = 1920
screen_height = 1080
except:
screen_width = 1920
screen_height = 1080
# Scale factor for larger window
SCALE_FACTOR = 1.8
# Threshold settings
MOUTH_CLOSED_THRESHOLD = 0.45
MOUTH_OPEN_THRESHOLD = 0.45
EYE_CLOSED_THRESHOLD = 0.20
EYE_OPEN_THRESHOLD = 0.25
# Drowsiness detection parameters
YAWN_DURATION_THRESH = 1.5 # Minimum yawn duration (seconds)
MICRO_SLEEP_THRESH = 1.0 # Minimum micro-sleep duration (seconds)
CONSECUTIVE_YAWN_THRESH = 3 # Consecutive yawn warning threshold
STATE_RESET_TIME = 60.0 # Reset state every 30 seconds
BLINK_DURATION_THRESH = 2.0 # Minimum blink duration for counting (seconds)
# Face distance calculation parameters
KNOWN_FACE_WIDTH = 16.0 # Average face width in centimeters
FOCAL_LENGTH = 700 # Approximate focal length (adjust based on camera)
# State tracking variables
blink_total = 0
yawn_counter = 0
eye_closed_duration = 0
last_eye_open_time = time.time()
last_yawn_time = 0
last_reset_time = time.time()
last_blink_time = 0
drowsy_warning = ""
drowsy_level = 0
face_distance = 0.0
eyes_closed = False
blink_detected = False
# Performance counters
start_time = time.time()
# Function to calculate face distance
def calculate_face_distance(face_width_pixels):
"""
Calculate distance to face using triangle similarity
:param face_width_pixels: width of face in pixels
:return: distance in centimeters
"""
if face_width_pixels == 0:
return 0.0
return (KNOWN_FACE_WIDTH * FOCAL_LENGTH) / face_width_pixels
while True:
ret, frame = cap.read()
if not ret or frame is None:
print("Failed to capture frame")
continue
# Horizontal flip
frame = cv2.flip(frame, 1)
# Create a copy for transparent overlays
display_frame = frame.copy()
# Convert to grayscale for face detection
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Detect faces
faces = detector(gray)
# Reset per-frame states
mouth_open = False
current_time = time.time()
# Reset state every 30 seconds
if current_time - last_reset_time > STATE_RESET_TIME:
blink_total = 0
yawn_counter = 0
drowsy_level = 0
drowsy_warning = ""
last_reset_time = current_time
print("State reset")
# Calculate face distance if face detected
face_distance = 0.0 # Reset each frame
if len(faces) > 0:
face = faces[0] # Use first face for distance calculation
face_width = face.right() - face.left()
face_distance = calculate_face_distance(face_width)
# Display face distance in top-left corner (RED)
distance_text = f"Distance: {face_distance:.1f} cm"
cv2.putText(display_frame, distance_text, (20, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
for face in faces:
x1, y1, x2, y2 = face.left(), face.top(), face.right(), face.bottom()
cv2.rectangle(display_frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
# Get facial landmarks
try:
landmarks = predictor(gray, face)
except Exception as e:
print(f"Landmark prediction error: {e}")
continue
# Get mouth points
mouth_points = []
for n in MOUTH_POINTS:
try:
x = landmarks.part(n).x
y = landmarks.part(n).y
mouth_points.append((x, y))
except:
continue
# Get eye points
left_eye_points = []
for n in LEFT_EYE_POINTS:
try:
x = landmarks.part(n).x
y = landmarks.part(n).y
left_eye_points.append((x, y))
except:
continue
right_eye_points = []
for n in RIGHT_EYE_POINTS:
try:
x = landmarks.part(n).x
y = landmarks.part(n).y
right_eye_points.append((x, y))
except:
continue
# Calculate mouth state
if len(mouth_points) >= 11:
mar = mouth_aspect_ratio(mouth_points)
if mar > MOUTH_OPEN_THRESHOLD:
mouth_status = "OPEN"
mouth_color = (0, 0, 255) # Red
mouth_open = True
# Record yawn start time
if last_yawn_time == 0:
last_yawn_time = current_time
else:
mouth_status = "CLOSED" if mar < MOUTH_CLOSED_THRESHOLD else "NEUTRAL"
mouth_color = (0, 255, 0) if mouth_status == "CLOSED" else (0, 255, 255)
# Detect yawn completion
if last_yawn_time > 0:
yawn_duration = current_time - last_yawn_time
if yawn_duration >= YAWN_DURATION_THRESH:
yawn_counter += 1
print(f"Yawn detected #{yawn_counter}, duration: {yawn_duration:.2f} seconds")
last_yawn_time = 0
# Display mouth status (red text)
cv2.putText(display_frame, f"Mouth: {mouth_status}",
(x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 255), 1)
# Draw mouth contour
if len(mouth_points) > 2:
try:
mouth_hull = cv2.convexHull(np.array(mouth_points))
cv2.drawContours(display_frame, [mouth_hull], -1, mouth_color, 1)
except:
pass
# Calculate eye states
left_ear, right_ear, avg_ear = 0, 0, 0
left_eye_status = "N/A"
right_eye_status = "N/A"
if len(left_eye_points) == 6:
left_ear = eye_aspect_ratio(left_eye_points)
if left_ear < EYE_CLOSED_THRESHOLD:
left_eye_status = "CLOSED"
left_eye_color = (0, 0, 255)
elif left_ear > EYE_OPEN_THRESHOLD:
left_eye_status = "OPEN"
left_eye_color = (0, 255, 0)
else:
left_eye_status = "PARTIAL"
left_eye_color = (0, 255, 255)
# Draw eye contour
try:
left_eye_hull = cv2.convexHull(np.array(left_eye_points))
cv2.drawContours(display_frame, [left_eye_hull], -1, left_eye_color, 1)
except:
pass
if len(right_eye_points) == 6:
right_ear = eye_aspect_ratio(right_eye_points)
if right_ear < EYE_CLOSED_THRESHOLD:
right_eye_status = "CLOSED"
right_eye_color = (0, 0, 255)
elif right_ear > EYE_OPEN_THRESHOLD:
right_eye_status = "OPEN"
right_eye_color = (0, 255, 0)
else:
right_eye_status = "PARTIAL"
right_eye_color = (0, 255, 255)
# Draw eye contour
try:
right_eye_hull = cv2.convexHull(np.array(right_eye_points))
cv2.drawContours(display_frame, [right_eye_hull], -1, right_eye_color, 1)
except:
pass
# Calculate average EAR
if len(left_eye_points) == 6 and len(right_eye_points) == 6:
avg_ear = (left_ear + right_ear) / 2.0
# Detect eye state changes
if avg_ear < EYE_CLOSED_THRESHOLD:
if not eyes_closed:
# Eyes just closed - record start time
last_eye_closed_time = current_time
eyes_closed = True
blink_detected = False
else:
# Eyes still closed - check if we should count a blink
if not blink_detected and (current_time - last_eye_closed_time) >= BLINK_DURATION_THRESH:
blink_total += 1
blink_detected = True # Mark this closure as counted
print(f"Blink detected (duration: {current_time - last_eye_closed_time:.1f}s)")
else:
if eyes_closed:
# Eyes just opened
eye_closed_duration = current_time - last_eye_closed_time
# Detect micro-sleep
if eye_closed_duration >= MICRO_SLEEP_THRESH:
drowsy_warning = "SLEEPY!"
drowsy_level = max(drowsy_level, 2)
print(f"Micro-sleep detected: {eye_closed_duration:.2f} seconds")
# Reset eye state
eyes_closed = False
blink_detected = False
# Display eye status (red text, separate lines)
if left_eye_status != "N/A":
cv2.putText(display_frame, f"L-Eye: {left_eye_status}",
(x1, y1 - 30), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 255), 1)
if right_eye_status != "N/A":
cv2.putText(display_frame, f"R-Eye: {right_eye_status}",
(x1, y1 - 50), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 255), 1)
# Drowsiness analysis
elapsed_time = current_time - start_time
# 1. Detect yawns
if last_yawn_time > 0:
yawn_duration = current_time - last_yawn_time
if yawn_duration >= YAWN_DURATION_THRESH and yawn_counter > 0:
drowsy_warning = "SLEEPY!"
drowsy_level = max(drowsy_level, 1)
# 2. Detect consecutive yawns
if yawn_counter >= CONSECUTIVE_YAWN_THRESH:
drowsy_warning = "SLEEPY!"
drowsy_level = 3
# Display drowsiness status
drowsy_status = ""
status_color = (0, 255, 0) # Green
if drowsy_level == 1:
drowsy_status = "Mild Drowsiness"
status_color = (0, 255, 255) # Yellow
elif drowsy_level == 2:
drowsy_status = "Moderate Drowsiness"
status_color = (0, 165, 255) # Orange
elif drowsy_level >= 3:
drowsy_status = "Severe Drowsiness!"
status_color = (0, 0, 255) # Red
# Display "SLEEPY!" warning in large red text
if drowsy_warning:
text_size = cv2.getTextSize(drowsy_warning, cv2.FONT_HERSHEY_SIMPLEX, 2.0, 5)[0]
text_x = (display_frame.shape[1] - text_size[0]) // 2
text_y = (display_frame.shape[0] + text_size[1]) // 2
cv2.putText(display_frame, drowsy_warning,
(text_x, text_y),
cv2.FONT_HERSHEY_SIMPLEX, 2.0, (0, 0, 255), 5)
# Create transparent overlay for status information
overlay = display_frame.copy()
cv2.rectangle(overlay, (10, 50), (250, 150), (0, 0, 0), -1) # Positioned below distance text
alpha = 0.5 # Transparency factor
cv2.addWeighted(overlay, alpha, display_frame, 1 - alpha, 0, display_frame)
# Display status information with red text
cv2.putText(display_frame, f"Status: {drowsy_status}", (15, 70),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, status_color, 1)
cv2.putText(display_frame, f"Blinks: {blink_total}",
(15, 95), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
cv2.putText(display_frame, f"Yawns: {yawn_counter}",
(15, 120), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
# Add reset timer info
reset_in = STATE_RESET_TIME - (current_time - last_reset_time)
cv2.putText(display_frame, f"Reset in: {max(0, reset_in):.0f}s",
(15, 145), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
# Display instructions (red text)
cv2.putText(display_frame, "Press ESC to quit", (display_frame.shape[1] - 200, display_frame.shape[0] - 15),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
# Resize window to be larger
display_width = int(display_frame.shape[1] * SCALE_FACTOR)
display_height = int(display_frame.shape[0] * SCALE_FACTOR)
resized_frame = cv2.resize(display_frame, (display_width, display_height))
# Show frame
cv2.imshow("Drowsiness Detection System", resized_frame)
# Reset warning
drowsy_warning = ""
# Exit on ESC key
if cv2.waitKey(1) == 27:
break
# Release resources
cap.release()
cv2.destroyAllWindows()