Spaces:
Running
Running
File size: 6,785 Bytes
4128971 9ca6575 4128971 8c6d609 4128971 b1b3568 4128971 b1b3568 4128971 9ca6575 b1b3568 9ca6575 4128971 9ca6575 4128971 9ca6575 4128971 b1b3568 4128971 b1b3568 9ca6575 4128971 9ca6575 4128971 9ca6575 4128971 b1b3568 4128971 9ca6575 b1b3568 9ca6575 4128971 b1b3568 9ca6575 b1b3568 4128971 9ca6575 b1b3568 9ca6575 3d5b37b 9ca6575 4128971 9ca6575 b1b3568 9ca6575 b1b3568 9ca6575 b1b3568 3d5b37b 9ca6575 4128971 8c6d609 b1b3568 9ca6575 4128971 9ca6575 4128971 b1b3568 3d5b37b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | import gradio as gr
import cv2
import torch
import torch.nn as nn
import numpy as np
from torchvision import transforms
import os
import time
# --- 1. MODEL ARCHITECTURE ---
class LDobjModel(nn.Module):
def __init__(self):
super(LDobjModel, self).__init__()
self.enc1 = self.conv_block(3, 16); self.pool1 = nn.MaxPool2d(2)
self.enc2 = self.conv_block(16, 32); self.pool2 = nn.MaxPool2d(2)
self.bottleneck = self.conv_block(32, 64)
self.up1 = nn.ConvTranspose2d(64, 32, 2, 2)
self.dec1 = self.conv_block(64, 32)
self.up2 = nn.ConvTranspose2d(32, 16, 2, 2)
self.dec2 = self.conv_block(32, 16)
self.final = nn.Sequential(nn.Conv2d(16, 1, 1), nn.Sigmoid())
def conv_block(self, in_c, out_c):
return nn.Sequential(nn.Conv2d(in_c, out_c, 3, 1, 1), nn.ReLU(),
nn.Conv2d(out_c, out_c, 3, 1, 1), nn.ReLU())
def forward(self, x):
e1 = self.enc1(x); e2 = self.enc2(self.pool1(e1))
b = self.bottleneck(self.pool2(e2))
d1 = torch.cat((e2, self.up1(b)), dim=1); d1 = self.dec1(d1)
d2 = torch.cat((e1, self.up2(d1)), dim=1); d2 = self.dec2(d2)
return self.final(d2)
# --- 2. INITIALIZATION ---
device = torch.device('cpu')
model = LDobjModel().to(device)
if os.path.exists('LDobj_weights.pth'):
model.load_state_dict(torch.load('LDobj_weights.pth', map_location=device))
model.eval()
transform = transforms.Compose([
transforms.ToPILImage(),
transforms.Resize((288, 800)),
transforms.ToTensor()
])
# --- 3. ADVANCED PROCESSING LOGIC (With Progress & Analytics) ---
def analyze_video(input_video_path, sensitivity, progress=gr.Progress()):
if not input_video_path:
return None, "⚠️ Please upload a video first."
start_time = time.time()
cap = cv2.VideoCapture(input_video_path)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
raw_output = "temp_raw.mp4"
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(raw_output, fourcc, fps, (width, height))
morph_kernel = np.ones((5, 5), np.uint8)
drift_threshold = width * (sensitivity / 100.0)
frame_count = 0
alerts_triggered = 0
while cap.isOpened():
ret, frame = cap.read()
if not ret: break
frame_count += 1
if frame_count % 5 == 0:
progress(frame_count / total_frames, desc=f"Processing AI Vision: Frame {frame_count}/{total_frames}")
# AI Prediction
input_img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img_tensor = transform(input_img).unsqueeze(0).to(device)
with torch.no_grad():
pred = model(img_tensor).squeeze().numpy()
# Mask Cleaning
mask = (pred > 0.5).astype(np.uint8)
mask_full = cv2.resize(mask, (width, height), interpolation=cv2.INTER_NEAREST)
mask_full = cv2.morphologyEx(mask_full, cv2.MORPH_OPEN, morph_kernel)
# Departure Alert Logic
moments = cv2.moments(mask_full[int(height*0.75):, :])
if moments["m00"] > 0 and abs(int(moments["m10"] / moments["m00"]) - width // 2) > drift_threshold:
alerts_triggered += 1
overlay = frame.copy()
overlay[mask_full > 0] = (0, 0, 255)
frame = cv2.addWeighted(frame, 0.7, overlay, 0.3, 0)
# Draw sleek UI elements
cv2.rectangle(frame, (0, 0), (width, 120), (0, 0, 0), -1) # Black header bar
cv2.putText(frame, "LANE DEPARTURE DETECTED", (30, 80), cv2.FONT_HERSHEY_DUPLEX, 1.5, (0, 0, 255), 3)
out.write(frame)
cap.release()
out.release()
progress(0.95, desc="Optimizing Video for Web...")
web_output = "ldobj_final.mp4"
os.system(f"ffmpeg -y -i {raw_output} -c:v libx264 -preset fast -pix_fmt yuv420p -movflags +faststart {web_output}")
process_time = time.time() - start_time
avg_fps = frame_count / process_time if process_time > 0 else 0
telemetry_report = (
f"✅ Analysis Complete\n"
f"------------------------\n"
f"⏱️ Processing Time: {process_time:.1f} seconds\n"
f"🎞️ Total Frames: {frame_count}\n"
f"🚀 AI Speed: {avg_fps:.1f} FPS\n"
f"🚨 Alerts Triggered: {alerts_triggered} frames"
)
return web_output, telemetry_report
# --- 4. ULTIMATE FRONTEND DESIGN ---
custom_css = """
#video-in, #video-out { min-height: 450px; border-radius: 10px; border: 1px solid #333; }
.gradio-container { max-width: 1200px !important; margin: auto; }
footer { visibility: hidden; }
.glow-title { color: #ff4a4a; text-shadow: 0px 0px 15px rgba(255, 74, 74, 0.5); text-align: center; margin-bottom: 5px; }
.sub-title { text-align: center; color: #888; margin-top: 0px; margin-bottom: 30px; }
"""
# IMPORTANT: No theme/css parameters inside gr.Blocks() for Gradio 6.0!
with gr.Blocks() as app:
gr.HTML("<h1 class='glow-title'>🛡️ LDobj ADAS Command Center</h1>")
gr.HTML("<h3 class='sub-title'>Advanced Driver Assistance System • Neural Lane Tracking</h3>")
with gr.Group():
with gr.Row():
with gr.Column(scale=4):
gr.Markdown("### 1. Input Source")
video_in = gr.Video(label="Dashcam Feed", elem_id="video-in")
gr.Markdown("### 2. AI Parameters")
sensitivity_slider = gr.Slider(
minimum=5, maximum=25, value=10, step=1,
label="Drift Sensitivity Threshold (%)",
info="Lower % = Stricter alerts. Higher % = Allows more drift before alerting."
)
run_btn = gr.Button("INITIALIZE SCAN", variant="primary", size="lg")
with gr.Column(scale=5):
gr.Markdown("### Live Output Feed")
video_out = gr.Video(label="LDobj Processed Feed", interactive=False, autoplay=True, elem_id="video-out")
gr.Markdown("### System Telemetry")
telemetry_out = gr.Textbox(label="Analytics Console", lines=6, interactive=False)
run_btn.click(
fn=analyze_video,
inputs=[video_in, sensitivity_slider],
outputs=[video_out, telemetry_out]
)
if __name__ == "__main__":
# IMPORTANT: Theme and CSS MUST go inside the launch method!
# Using 'Glass' theme which is natively supported and looks fantastic in Dark Mode.
app.launch(
theme=gr.themes.Glass(primary_hue="red"),
css=custom_css,
footer_links=[] # Hides the Gradio footer cleanly
) |