Spaces:
Runtime error
Runtime error
Update main.py
Browse files
main.py
CHANGED
|
@@ -819,7 +819,7 @@ class SafeDrivingAssistant:
|
|
| 819 |
self.alert_manager.play_energetic_music()
|
| 820 |
self.add_chat_log("System", "Energetic synthwave music started. Stay alert!")
|
| 821 |
|
| 822 |
-
|
| 823 |
|
| 824 |
def run(self):
|
| 825 |
"""Main camera acquisition loop that drives the safe assistant."""
|
|
@@ -830,46 +830,77 @@ class SafeDrivingAssistant:
|
|
| 830 |
cap.set(cv2.CAP_PROP_FRAME_WIDTH, FRAME_WIDTH)
|
| 831 |
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, FRAME_HEIGHT)
|
| 832 |
|
|
|
|
|
|
|
| 833 |
if not cap.isOpened():
|
| 834 |
-
print("[CoreEngine]
|
| 835 |
-
|
|
|
|
|
|
|
|
|
|
| 836 |
|
| 837 |
-
print("[CoreEngine]
|
| 838 |
-
print("[CoreEngine] Press 'q' in CV window or click Dashboard Reset to quit.")
|
| 839 |
|
| 840 |
prev_time = time.time()
|
| 841 |
|
| 842 |
try:
|
| 843 |
while True:
|
| 844 |
-
|
| 845 |
-
|
| 846 |
-
|
| 847 |
-
|
| 848 |
-
|
| 849 |
-
|
| 850 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 851 |
|
| 852 |
# Check if tracking is active (controlled from Dashboard)
|
| 853 |
with dashboard_state.lock:
|
| 854 |
active = dashboard_state.detection_active
|
| 855 |
|
| 856 |
if active:
|
| 857 |
-
|
| 858 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 859 |
else:
|
| 860 |
processed_frame = frame.copy()
|
| 861 |
cv2.putText(processed_frame, "TRACKING PAUSED", (50, 50),
|
| 862 |
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 165, 255), 2)
|
| 863 |
ear = None
|
| 864 |
|
| 865 |
-
current_time = time.time()
|
| 866 |
-
|
| 867 |
# Calculate processing frame rate (FPS)
|
| 868 |
-
fps = int(1.0 / (current_time - prev_time))
|
| 869 |
prev_time = current_time
|
| 870 |
|
| 871 |
# Drowsiness Logic Decision Engine
|
| 872 |
-
|
| 873 |
if ear is not None and active:
|
| 874 |
if ear < EAR_THRESHOLD:
|
| 875 |
self.consec_closed_frames += 1
|
|
@@ -925,7 +956,7 @@ class SafeDrivingAssistant:
|
|
| 925 |
self.alert_manager.trigger_level3_advisory()
|
| 926 |
self.add_chat_log("System", "FREQUENT DROWSINESS DETECTED. Prompting driver to pull over.")
|
| 927 |
else:
|
| 928 |
-
# Normal recovery
|
| 929 |
current_state = self.get_system_state()
|
| 930 |
if current_state not in ["WAITING_REST_RESPONSE", "WAITING_SONG_RESPONSE"]:
|
| 931 |
self.set_system_state("NORMAL")
|
|
@@ -935,7 +966,6 @@ class SafeDrivingAssistant:
|
|
| 935 |
self.eyes_closed_start_time = None
|
| 936 |
|
| 937 |
# Update Global Telemetry Buffer for Flask Server
|
| 938 |
-
|
| 939 |
with dashboard_state.lock:
|
| 940 |
dashboard_state.latest_frame = processed_frame.copy()
|
| 941 |
if ear is not None:
|
|
@@ -944,25 +974,31 @@ class SafeDrivingAssistant:
|
|
| 944 |
dashboard_state.ear = 0.30 # Default baseline when no face present
|
| 945 |
dashboard_state.fps = fps
|
| 946 |
|
| 947 |
-
# OpenCV display output fallback (
|
| 948 |
-
|
| 949 |
-
|
| 950 |
-
|
| 951 |
-
|
| 952 |
-
|
| 953 |
-
|
| 954 |
-
|
| 955 |
-
|
| 956 |
-
|
|
|
|
|
|
|
| 957 |
|
| 958 |
except KeyboardInterrupt:
|
| 959 |
print("[CoreEngine] Keyboard interrupt. Shutting down.")
|
| 960 |
finally:
|
| 961 |
print("[CoreEngine] Releasing resources...")
|
| 962 |
cap.release()
|
| 963 |
-
|
|
|
|
|
|
|
|
|
|
| 964 |
self.assistant.stop()
|
| 965 |
sys.exit(0)
|
|
|
|
| 966 |
|
| 967 |
if __name__ == "__main__":
|
| 968 |
assistant_app = SafeDrivingAssistant()
|
|
|
|
| 819 |
self.alert_manager.play_energetic_music()
|
| 820 |
self.add_chat_log("System", "Energetic synthwave music started. Stay alert!")
|
| 821 |
|
| 822 |
+
# Core Drowsiness Evaluation & Loop
|
| 823 |
|
| 824 |
def run(self):
|
| 825 |
"""Main camera acquisition loop that drives the safe assistant."""
|
|
|
|
| 830 |
cap.set(cv2.CAP_PROP_FRAME_WIDTH, FRAME_WIDTH)
|
| 831 |
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, FRAME_HEIGHT)
|
| 832 |
|
| 833 |
+
# Detect if we are in a headless cloud environment without a webcam
|
| 834 |
+
use_simulation = False
|
| 835 |
if not cap.isOpened():
|
| 836 |
+
print("[CoreEngine] WARNING: Could not access physical web camera.")
|
| 837 |
+
print("[CoreEngine] Pivoting to Cloud Simulation Mode to keep web HUD alive...")
|
| 838 |
+
use_simulation = True
|
| 839 |
+
else:
|
| 840 |
+
print("[CoreEngine] Camera stream operational. System fully active.")
|
| 841 |
|
| 842 |
+
print("[CoreEngine] System loop running. Use the Web Dashboard to monitor telemetry.")
|
|
|
|
| 843 |
|
| 844 |
prev_time = time.time()
|
| 845 |
|
| 846 |
try:
|
| 847 |
while True:
|
| 848 |
+
current_time = time.time()
|
| 849 |
+
|
| 850 |
+
if use_simulation:
|
| 851 |
+
# Generate an animated cyberpunk grid frame for the headless dashboard
|
| 852 |
+
frame = np.zeros((FRAME_HEIGHT, FRAME_WIDTH, 3), dtype=np.uint8)
|
| 853 |
+
# Create a scrolling scan line
|
| 854 |
+
scan_y = int(current_time * 120) % FRAME_HEIGHT
|
| 855 |
+
cv2.line(frame, (0, scan_y), (FRAME_WIDTH, scan_y), (40, 40, 40), 2)
|
| 856 |
+
cv2.putText(frame, "CLOUD SIMULATION FEED (NO PHYSICAL CAM)", (20, FRAME_HEIGHT - 20),
|
| 857 |
+
cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 255, 0), 1)
|
| 858 |
+
ret = True
|
| 859 |
+
else:
|
| 860 |
+
ret, frame = cap.read()
|
| 861 |
+
if not ret:
|
| 862 |
+
time.sleep(0.01)
|
| 863 |
+
continue
|
| 864 |
+
# Mirror frame for intuitive pilot HUD overlay
|
| 865 |
+
frame = cv2.flip(frame, 1)
|
| 866 |
|
| 867 |
# Check if tracking is active (controlled from Dashboard)
|
| 868 |
with dashboard_state.lock:
|
| 869 |
active = dashboard_state.detection_active
|
| 870 |
|
| 871 |
if active:
|
| 872 |
+
if use_simulation:
|
| 873 |
+
# Cloud Demo Mode: Automatically simulate a drowsy event cycle every 25 seconds
|
| 874 |
+
# to let you test your Flask dashboard overlays and system responses safely!
|
| 875 |
+
cycle = int(current_time) % 25
|
| 876 |
+
if cycle > 18: # Simulate closed eyes for 7 seconds
|
| 877 |
+
ear = 0.16
|
| 878 |
+
cv2.putText(frame, "SIMULATING DROWSINESS (EYES CLOSED)", (FRAME_WIDTH // 2 - 180, FRAME_HEIGHT // 2),
|
| 879 |
+
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
|
| 880 |
+
else:
|
| 881 |
+
ear = 0.28
|
| 882 |
+
|
| 883 |
+
processed_frame = frame.copy()
|
| 884 |
+
# Draw virtual telemetry eye dots onto the matrix background
|
| 885 |
+
cv2.circle(processed_frame, (int(FRAME_WIDTH * 0.4), int(FRAME_HEIGHT * 0.45)), 8, (0, 255, 0) if ear > EAR_THRESHOLD else (0, 0, 255), -1)
|
| 886 |
+
cv2.circle(processed_frame, (int(FRAME_WIDTH * 0.6), int(FRAME_HEIGHT * 0.45)), 8, (0, 255, 0) if ear > EAR_THRESHOLD else (0, 0, 255), -1)
|
| 887 |
+
if ear is not None:
|
| 888 |
+
cv2.putText(processed_frame, f"EAR: {ear:.2f}", (30, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0) if ear > EAR_THRESHOLD else (0, 0, 255), 2)
|
| 889 |
+
landmarks = {}
|
| 890 |
+
else:
|
| 891 |
+
# Calculate EAR and overlay glow contours on frame via physical camera
|
| 892 |
+
ear, landmarks, processed_frame = self.detector.process_frame(frame)
|
| 893 |
else:
|
| 894 |
processed_frame = frame.copy()
|
| 895 |
cv2.putText(processed_frame, "TRACKING PAUSED", (50, 50),
|
| 896 |
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 165, 255), 2)
|
| 897 |
ear = None
|
| 898 |
|
|
|
|
|
|
|
| 899 |
# Calculate processing frame rate (FPS)
|
| 900 |
+
fps = int(1.0 / (current_time - prev_time)) if (current_time - prev_time) > 0 else 30
|
| 901 |
prev_time = current_time
|
| 902 |
|
| 903 |
# Drowsiness Logic Decision Engine
|
|
|
|
| 904 |
if ear is not None and active:
|
| 905 |
if ear < EAR_THRESHOLD:
|
| 906 |
self.consec_closed_frames += 1
|
|
|
|
| 956 |
self.alert_manager.trigger_level3_advisory()
|
| 957 |
self.add_chat_log("System", "FREQUENT DROWSINESS DETECTED. Prompting driver to pull over.")
|
| 958 |
else:
|
| 959 |
+
# Normal recovery
|
| 960 |
current_state = self.get_system_state()
|
| 961 |
if current_state not in ["WAITING_REST_RESPONSE", "WAITING_SONG_RESPONSE"]:
|
| 962 |
self.set_system_state("NORMAL")
|
|
|
|
| 966 |
self.eyes_closed_start_time = None
|
| 967 |
|
| 968 |
# Update Global Telemetry Buffer for Flask Server
|
|
|
|
| 969 |
with dashboard_state.lock:
|
| 970 |
dashboard_state.latest_frame = processed_frame.copy()
|
| 971 |
if ear is not None:
|
|
|
|
| 974 |
dashboard_state.ear = 0.30 # Default baseline when no face present
|
| 975 |
dashboard_state.fps = fps
|
| 976 |
|
| 977 |
+
# OpenCV display output fallback (wrapped safely to prevent headless display context drops)
|
| 978 |
+
try:
|
| 979 |
+
cv2.imshow("DriveSafe HUD AI Console", processed_frame)
|
| 980 |
+
key = cv2.waitKey(1) & 0xFF
|
| 981 |
+
if key == ord('q') or key == 27:
|
| 982 |
+
print("[CoreEngine] Exit key received. Terminating system.")
|
| 983 |
+
break
|
| 984 |
+
elif key == ord('r'):
|
| 985 |
+
self.reset_warnings()
|
| 986 |
+
except Exception:
|
| 987 |
+
# Prevents crashes on platforms where standard desktop window pipelines are fully restricted
|
| 988 |
+
time.sleep(0.03)
|
| 989 |
|
| 990 |
except KeyboardInterrupt:
|
| 991 |
print("[CoreEngine] Keyboard interrupt. Shutting down.")
|
| 992 |
finally:
|
| 993 |
print("[CoreEngine] Releasing resources...")
|
| 994 |
cap.release()
|
| 995 |
+
try:
|
| 996 |
+
cv2.destroyAllWindows()
|
| 997 |
+
except Exception:
|
| 998 |
+
pass
|
| 999 |
self.assistant.stop()
|
| 1000 |
sys.exit(0)
|
| 1001 |
+
|
| 1002 |
|
| 1003 |
if __name__ == "__main__":
|
| 1004 |
assistant_app = SafeDrivingAssistant()
|