asrcoddeploy commited on
Commit
b1b3568
·
verified ·
1 Parent(s): 4128971

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +51 -60
app.py CHANGED
@@ -6,7 +6,7 @@ import numpy as np
6
  from torchvision import transforms
7
  import os
8
 
9
- # --- 1. MODEL ARCHITECTURE ---
10
  class LDobjModel(nn.Module):
11
  def __init__(self):
12
  super(LDobjModel, self).__init__()
@@ -30,11 +30,11 @@ class LDobjModel(nn.Module):
30
  d2 = torch.cat((e1, self.up2(d1)), dim=1); d2 = self.dec2(d2)
31
  return self.final(d2)
32
 
33
- # --- 2. LOAD AI ON STARTUP ---
34
- device = torch.device('cpu') # Hugging Face Free Tier uses CPU
35
  model = LDobjModel().to(device)
36
- # Load weights (Make sure the filename matches exactly what you uploaded)
37
- model.load_state_dict(torch.load('LDobj_weights.pth', map_location=device))
38
  model.eval()
39
 
40
  transform = transforms.Compose([
@@ -43,91 +43,82 @@ transform = transforms.Compose([
43
  transforms.ToTensor()
44
  ])
45
 
46
- # --- 3. VIDEO PROCESSING LOGIC ---
47
  def analyze_video(input_video_path):
48
- if input_video_path is None:
49
  return None
50
 
51
  cap = cv2.VideoCapture(input_video_path)
52
-
53
- # Get video specs
54
  width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
55
  height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
56
  fps = cap.get(cv2.CAP_PROP_FPS)
57
 
58
- # Setup output writer
59
- raw_output = "raw_output.mp4"
60
  fourcc = cv2.VideoWriter_fourcc(*'mp4v')
61
  out = cv2.VideoWriter(raw_output, fourcc, fps, (width, height))
62
 
 
 
63
  while cap.isOpened():
64
  ret, frame = cap.read()
65
  if not ret: break
66
 
67
- # Pre-process frame
68
  input_img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
69
  img_tensor = transform(input_img).unsqueeze(0).to(device)
70
-
71
- # AI Prediction
72
  with torch.no_grad():
73
  pred = model(img_tensor).squeeze().numpy()
74
 
75
- # Binary Mask
76
  mask = (pred > 0.5).astype(np.uint8)
77
- mask_full = cv2.resize(mask, (width, height))
78
-
79
- # Departure Logic
80
- moments = cv2.moments(mask_full[int(height*0.8):, :])
81
- alert_triggered = False
82
-
83
- if moments["m00"] > 0:
84
- lane_center_x = int(moments["m10"] / moments["m00"])
85
- car_center_x = width // 2
86
-
87
- # If car drifts > 10% of screen width
88
- if abs(lane_center_x - car_center_x) > (width * 0.1):
89
- alert_triggered = True
90
 
91
- # ONLY MODIFY FRAME IF ALERT IS HAPPENING
92
- if alert_triggered:
93
- status_color = (0, 0, 255) # Red BGR
94
  overlay = frame.copy()
95
- overlay[mask_full > 0] = status_color
96
-
97
- # Add UI Text
98
- cv2.putText(frame, "WARNING: LANE DEPARTURE!", (width//10, 100),
99
- cv2.FONT_HERSHEY_SIMPLEX, 1.5, status_color, 4)
100
-
101
- # Blend frame with red lanes
102
- final_frame = cv2.addWeighted(frame, 0.7, overlay, 0.3, 0)
103
- out.write(final_frame)
104
- else:
105
- # Normal driving: return the clean, untouched dashcam footage
106
- out.write(frame)
107
 
108
  cap.release()
109
- out.write(frame)
110
  out.release()
111
 
112
- # Convert to standard H264 for web browsers (Gradio requires this)
113
- web_output = "final_output.mp4"
114
- os.system(f"ffmpeg -y -i {raw_output} -vcodec libx264 {web_output}")
115
 
116
  return web_output
117
 
118
- # --- 4. GRADIO WEB INTERFACE ---
119
- with gr.Blocks(theme=gr.themes.Monochrome()) as app:
120
- gr.Markdown("# 🚗 LDobj: AI Lane Departure Alert System")
121
- gr.Markdown("Upload a dashcam video. The AI will analyze the footage and **only overlay an alert** during actual lane departures.")
 
 
 
 
 
 
 
122
 
123
- with gr.Row():
124
- with gr.Column():
125
- video_input = gr.Video(label="Upload Dashcam Video (.mp4)")
126
- submit_btn = gr.Button("Analyze Video", variant="primary")
127
-
128
- with gr.Column():
129
- video_output = gr.Video(label="AI Analyzed Output")
130
 
131
- submit_btn.click(fn=analyze_video, inputs=video_input, outputs=video_output)
 
 
 
 
 
 
 
132
 
133
- app.launch()
 
 
6
  from torchvision import transforms
7
  import os
8
 
9
+ # --- 1. MODEL ARCHITECTURE (Hidden from UI) ---
10
  class LDobjModel(nn.Module):
11
  def __init__(self):
12
  super(LDobjModel, self).__init__()
 
30
  d2 = torch.cat((e1, self.up2(d1)), dim=1); d2 = self.dec2(d2)
31
  return self.final(d2)
32
 
33
+ # --- 2. INITIALIZATION ---
34
+ device = torch.device('cpu')
35
  model = LDobjModel().to(device)
36
+ if os.path.exists('LDobj_weights.pth'):
37
+ model.load_state_dict(torch.load('LDobj_weights.pth', map_location=device))
38
  model.eval()
39
 
40
  transform = transforms.Compose([
 
43
  transforms.ToTensor()
44
  ])
45
 
46
+ # --- 3. CORE LOGIC (With Anti-Glitch Processing) ---
47
  def analyze_video(input_video_path):
48
+ if not input_video_path:
49
  return None
50
 
51
  cap = cv2.VideoCapture(input_video_path)
 
 
52
  width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
53
  height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
54
  fps = cap.get(cv2.CAP_PROP_FPS)
55
 
56
+ raw_output = "temp_raw.mp4"
 
57
  fourcc = cv2.VideoWriter_fourcc(*'mp4v')
58
  out = cv2.VideoWriter(raw_output, fourcc, fps, (width, height))
59
 
60
+ morph_kernel = np.ones((5, 5), np.uint8)
61
+
62
  while cap.isOpened():
63
  ret, frame = cap.read()
64
  if not ret: break
65
 
66
+ # AI Prediction
67
  input_img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
68
  img_tensor = transform(input_img).unsqueeze(0).to(device)
 
 
69
  with torch.no_grad():
70
  pred = model(img_tensor).squeeze().numpy()
71
 
72
+ # Mask Cleaning
73
  mask = (pred > 0.5).astype(np.uint8)
74
+ mask_full = cv2.resize(mask, (width, height), interpolation=cv2.INTER_NEAREST)
75
+ mask_full = cv2.morphologyEx(mask_full, cv2.MORPH_OPEN, morph_kernel)
 
 
 
 
 
 
 
 
 
 
 
76
 
77
+ # Departure Alert Logic
78
+ moments = cv2.moments(mask_full[int(height*0.75):, :])
79
+ if moments["m00"] > 0 and abs(int(moments["m10"] / moments["m00"]) - width // 2) > (width * 0.1):
80
  overlay = frame.copy()
81
+ overlay[mask_full > 0] = (0, 0, 255)
82
+ frame = cv2.addWeighted(frame, 0.7, overlay, 0.3, 0)
83
+ cv2.putText(frame, "LANE DEPARTURE", (width//10, 80), cv2.FONT_HERSHEY_DUPLEX, 1.5, (0, 0, 255), 3)
84
+
85
+ out.write(frame)
 
 
 
 
 
 
 
86
 
87
  cap.release()
 
88
  out.release()
89
 
90
+ # WEB OPTIMIZATION: Convert to H.264 with FastStart for smooth web playback
91
+ web_output = "ldobj_final.mp4"
92
+ os.system(f"ffmpeg -y -i {raw_output} -c:v libx264 -pix_fmt yuv420p -movflags +faststart {web_output}")
93
 
94
  return web_output
95
 
96
+ # --- 4. PERFECTED FRONTEND DESIGN ---
97
+ # Custom CSS to lock heights and prevent the "screen flicker" during loading
98
+ custom_css = """
99
+ #video-container { min-height: 400px; }
100
+ .gradio-container { background-color: #f7f9fc; }
101
+ footer { visibility: hidden; }
102
+ """
103
+
104
+ with gr.Blocks(css=custom_css, theme=gr.themes.Default(primary_hue="red")) as app:
105
+ gr.HTML("<h1 style='text-align: center; color: #d32f2f;'>🚗 LDobj Safety Interface</h1>")
106
+ gr.HTML("<p style='text-align: center;'>AI-Powered Lane Departure Detection & Alert System</p>")
107
 
108
+ with gr.Group(): # Groups components to prevent them from jumping around
109
+ with gr.Row():
110
+ with gr.Column(scale=1):
111
+ video_in = gr.Video(label="Source Dashcam Feed", mirror_webcam=False)
112
+ run_btn = gr.Button("START AI ANALYSIS", variant="primary")
 
 
113
 
114
+ with gr.Column(scale=1):
115
+ # We set interactive=False to make it a dedicated player
116
+ video_out = gr.Video(label="LDobj Alert Output", interactive=False, autoplay=True)
117
+
118
+ gr.Markdown("---")
119
+ gr.Markdown("### How it works\n1. **Invisible Monitor:** Under normal conditions, the video remains clean.\n2. **Active Alert:** If the car drifts, the system highlights the lanes in red and triggers an on-screen warning.")
120
+
121
+ run_btn.click(fn=analyze_video, inputs=video_in, outputs=video_out)
122
 
123
+ if __name__ == "__main__":
124
+ app.launch()