Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -26,6 +26,7 @@ from services.operations_maintenance.signage_check import process_signages
|
|
26 |
from services.road_safety.barrier_check import process_barriers
|
27 |
from services.road_safety.lighting_check import process_lighting
|
28 |
from services.road_safety.accident_spot_check import process_accident_spots
|
|
|
29 |
# Plantation services
|
30 |
from services.plantation.plant_count import process_plants
|
31 |
from services.plantation.plant_health import process_plant_health
|
@@ -40,7 +41,7 @@ logging.basicConfig(
|
|
40 |
|
41 |
# Globals
|
42 |
paused = False
|
43 |
-
frame_rate = 0.1
|
44 |
frame_count = 0
|
45 |
log_entries = []
|
46 |
crack_counts = []
|
@@ -48,10 +49,10 @@ crack_severity_all = []
|
|
48 |
last_frame = None
|
49 |
last_detections = {}
|
50 |
last_timestamp = ""
|
51 |
-
last_detected_images = []
|
52 |
gps_coordinates = []
|
53 |
video_loaded = False
|
54 |
-
active_service = None
|
55 |
|
56 |
# Constants
|
57 |
DEFAULT_VIDEO_PATH = "sample.mp4"
|
@@ -62,9 +63,6 @@ os.makedirs(CAPTURED_FRAMES_DIR, exist_ok=True)
|
|
62 |
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
63 |
|
64 |
def initialize_video(video_file=None):
|
65 |
-
"""
|
66 |
-
Initialize the video with the provided file or default path.
|
67 |
-
"""
|
68 |
global video_loaded, log_entries
|
69 |
release_video()
|
70 |
video_path = DEFAULT_VIDEO_PATH
|
@@ -81,11 +79,7 @@ def initialize_video(video_file=None):
|
|
81 |
return status
|
82 |
|
83 |
def set_active_service(service_name, uc_val, om_val, rs_val, pl_val):
|
84 |
-
|
85 |
-
Set the active service category based on toggles.
|
86 |
-
Only one service category can be active at a time.
|
87 |
-
"""
|
88 |
-
global active_service, service_toggles
|
89 |
toggles = {
|
90 |
"under_construction": uc_val,
|
91 |
"operations_maintenance": om_val,
|
@@ -93,14 +87,12 @@ def set_active_service(service_name, uc_val, om_val, rs_val, pl_val):
|
|
93 |
"plantation": pl_val
|
94 |
}
|
95 |
|
96 |
-
# Ensure only one toggle is active
|
97 |
active_count = sum(toggles.values())
|
98 |
if active_count > 1:
|
99 |
log_entries.append("Error: Only one service category can be active at a time.")
|
100 |
logging.error("Multiple service categories enabled simultaneously.")
|
101 |
return None, "Error: Please enable only one service category at a time."
|
102 |
|
103 |
-
# Set active service
|
104 |
for service, enabled in toggles.items():
|
105 |
if enabled:
|
106 |
active_service = service
|
@@ -114,16 +106,12 @@ def set_active_service(service_name, uc_val, om_val, rs_val, pl_val):
|
|
114 |
return None, "No Service Category Enabled"
|
115 |
|
116 |
def monitor_feed():
|
117 |
-
"""
|
118 |
-
Main function to process video frames in real-time.
|
119 |
-
Only the active service category processes the frame.
|
120 |
-
"""
|
121 |
global paused, frame_count, last_frame, last_detections, last_timestamp, gps_coordinates, last_detected_images, video_loaded
|
122 |
|
123 |
if not video_loaded:
|
124 |
log_entries.append("Cannot start streaming: Video not loaded successfully.")
|
125 |
logging.error("Video not loaded successfully.")
|
126 |
-
return None, json.dumps({"error": "Video not loaded. Please upload a video file."}, indent=2), "\n".join(log_entries[-10:]), None, None, last_detected_images
|
127 |
|
128 |
if paused and last_frame is not None:
|
129 |
frame = last_frame.copy()
|
@@ -136,12 +124,10 @@ def monitor_feed():
|
|
136 |
except RuntimeError as e:
|
137 |
log_entries.append(f"Error: {str(e)}")
|
138 |
logging.error(f"Frame retrieval error: {str(e)}")
|
139 |
-
return None, json.dumps(last_detections, indent=2), "\n".join(log_entries[-10:]), None, None, last_detected_images
|
140 |
|
141 |
-
# Initialize detected items list
|
142 |
all_detected_items = []
|
143 |
|
144 |
-
# Process only the active service category
|
145 |
try:
|
146 |
if active_service == "under_construction":
|
147 |
earthwork_dets, frame = process_earthwork(frame)
|
@@ -160,7 +146,8 @@ def monitor_feed():
|
|
160 |
barrier_dets, frame = process_barriers(frame)
|
161 |
lighting_dets, frame = process_lighting(frame)
|
162 |
accident_dets, frame = process_accident_spots(frame)
|
163 |
-
|
|
|
164 |
|
165 |
elif active_service == "plantation":
|
166 |
plant_dets, frame = process_plants(frame)
|
@@ -169,18 +156,15 @@ def monitor_feed():
|
|
169 |
all_detected_items.extend(plant_dets + health_dets + missing_dets)
|
170 |
|
171 |
else:
|
172 |
-
# Fallback: Run generic detection if no service is active
|
173 |
generic_dets, frame = process_generic(frame)
|
174 |
all_detected_items.extend(generic_dets)
|
175 |
|
176 |
-
# Optional: Run shadow detection (affects all modes for better accuracy)
|
177 |
shadow_results = detect_shadows(frame)
|
178 |
shadow_dets = shadow_results["detections"]
|
179 |
frame = shadow_results["frame"]
|
180 |
all_detected_items.extend(shadow_dets)
|
181 |
|
182 |
-
|
183 |
-
if len(frame.shape) == 2: # Grayscale frame (simulating thermal input)
|
184 |
thermal_results = process_thermal(frame)
|
185 |
thermal_dets = thermal_results["detections"]
|
186 |
frame = thermal_results["frame"]
|
@@ -191,7 +175,6 @@ def monitor_feed():
|
|
191 |
logging.error(f"Processing error in {active_service}: {str(e)}")
|
192 |
all_detected_items = []
|
193 |
|
194 |
-
# Save frame with overlays
|
195 |
try:
|
196 |
cv2.imwrite(TEMP_IMAGE_PATH, frame, [int(cv2.IMWRITE_JPEG_QUALITY), 95])
|
197 |
except Exception as e:
|
@@ -200,11 +183,9 @@ def monitor_feed():
|
|
200 |
|
201 |
metrics = update_metrics(all_detected_items)
|
202 |
|
203 |
-
# Simulate GPS coordinates
|
204 |
gps_coord = [17.385044 + random.uniform(-0.001, 0.001), 78.486671 + frame_count * 0.0001]
|
205 |
gps_coordinates.append(gps_coord)
|
206 |
|
207 |
-
# Save frame if there are detections (e.g., cracks, plants, etc.)
|
208 |
detection_types = {item.get("type") for item in all_detected_items if "type" in item}
|
209 |
if detection_types:
|
210 |
try:
|
@@ -217,7 +198,6 @@ def monitor_feed():
|
|
217 |
log_entries.append(f"Error saving captured frame: {str(e)}")
|
218 |
logging.error(f"Error saving captured frame: {str(e)}")
|
219 |
|
220 |
-
# Combine detections for Salesforce
|
221 |
all_detections = {
|
222 |
"items": all_detected_items,
|
223 |
"metrics": metrics,
|
@@ -226,14 +206,12 @@ def monitor_feed():
|
|
226 |
"gps_coordinates": gps_coord
|
227 |
}
|
228 |
|
229 |
-
# Dispatch to Salesforce
|
230 |
try:
|
231 |
dispatch_to_salesforce(all_detections, all_detections["timestamp"])
|
232 |
except Exception as e:
|
233 |
log_entries.append(f"Salesforce Dispatch Error: {str(e)}")
|
234 |
logging.error(f"Salesforce dispatch error: {str(e)}")
|
235 |
|
236 |
-
# Save annotated frame
|
237 |
try:
|
238 |
frame_path = os.path.join(OUTPUT_DIR, f"frame_{frame_count:04d}.jpg")
|
239 |
cv2.imwrite(frame_path, frame)
|
@@ -246,9 +224,8 @@ def monitor_feed():
|
|
246 |
last_frame = frame.copy()
|
247 |
last_detections = metrics
|
248 |
|
249 |
-
|
250 |
-
|
251 |
-
if active_service == "operations_maintenance":
|
252 |
crack_severity_all.extend([
|
253 |
item["severity"]
|
254 |
for item in all_detected_items
|
@@ -269,28 +246,25 @@ def monitor_feed():
|
|
269 |
if len(crack_severity_all) > 500:
|
270 |
crack_severity_all.pop(0)
|
271 |
|
272 |
-
# Add frame count and timestamp to display
|
273 |
frame = cv2.resize(last_frame, (640, 480))
|
274 |
cv2.putText(frame, f"Frame: {frame_count}", (10, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
|
275 |
cv2.putText(frame, f"{last_timestamp}", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
|
276 |
|
277 |
-
# Generate charts (only for operations_maintenance)
|
278 |
line_chart = None
|
279 |
pie_chart = None
|
280 |
-
|
|
|
281 |
line_chart = generate_line_chart()
|
282 |
pie_chart = generate_pie_chart()
|
|
|
283 |
|
284 |
-
return frame[:, :, ::-1], json.dumps(last_detections, indent=2), "\n".join(log_entries[-10:]), line_chart, pie_chart, last_detected_images
|
285 |
|
286 |
def generate_line_chart():
|
287 |
-
"""
|
288 |
-
Generate a line chart for crack counts over time using Chart.js.
|
289 |
-
"""
|
290 |
if not crack_counts:
|
291 |
return None
|
292 |
|
293 |
-
data = crack_counts[-50:]
|
294 |
labels = list(range(len(data)))
|
295 |
|
296 |
return {
|
@@ -300,7 +274,7 @@ def generate_line_chart():
|
|
300 |
"datasets": [{
|
301 |
"label": "Cracks Over Time",
|
302 |
"data": data,
|
303 |
-
"borderColor": "#FF6347",
|
304 |
"backgroundColor": "rgba(255, 99, 71, 0.2)",
|
305 |
"fill": True,
|
306 |
"tension": 0.4
|
@@ -311,7 +285,7 @@ def generate_line_chart():
|
|
311 |
"plugins": {
|
312 |
"title": {
|
313 |
"display": True,
|
314 |
-
"text": "
|
315 |
}
|
316 |
},
|
317 |
"scales": {
|
@@ -333,13 +307,10 @@ def generate_line_chart():
|
|
333 |
}
|
334 |
|
335 |
def generate_pie_chart():
|
336 |
-
"""
|
337 |
-
Generate a pie chart for crack severity distribution using Chart.js.
|
338 |
-
"""
|
339 |
if not crack_severity_all:
|
340 |
return None
|
341 |
|
342 |
-
count = Counter(crack_severity_all[-200:])
|
343 |
labels = list(count.keys())
|
344 |
sizes = list(count.values())
|
345 |
|
@@ -350,9 +321,9 @@ def generate_pie_chart():
|
|
350 |
"datasets": [{
|
351 |
"data": sizes,
|
352 |
"backgroundColor": [
|
353 |
-
"#FF6347",
|
354 |
-
"#4682B4",
|
355 |
-
"#FFD700"
|
356 |
]
|
357 |
}]
|
358 |
},
|
@@ -361,7 +332,7 @@ def generate_pie_chart():
|
|
361 |
"plugins": {
|
362 |
"title": {
|
363 |
"display": True,
|
364 |
-
"text": "Crack Severity
|
365 |
},
|
366 |
"legend": {
|
367 |
"position": "top"
|
@@ -370,6 +341,57 @@ def generate_pie_chart():
|
|
370 |
}
|
371 |
}
|
372 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
373 |
# Gradio UI
|
374 |
with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green")) as app:
|
375 |
gr.Markdown(
|
@@ -379,7 +401,6 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green"))
|
|
379 |
"""
|
380 |
)
|
381 |
|
382 |
-
# Video upload section
|
383 |
with gr.Row():
|
384 |
with gr.Column(scale=3):
|
385 |
video_input = gr.File(label="Upload Video File (e.g., sample.mp4)", file_types=["video"])
|
@@ -391,7 +412,6 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green"))
|
|
391 |
interactive=False
|
392 |
)
|
393 |
|
394 |
-
# Toggles for service categories with status indicators
|
395 |
with gr.Row():
|
396 |
with gr.Column():
|
397 |
uc_toggle = gr.Checkbox(label="Enable Under Construction Services", value=False)
|
@@ -418,8 +438,9 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green"))
|
|
418 |
with gr.Column(scale=2):
|
419 |
logs_output = gr.Textbox(label="Live Logs", lines=8, interactive=False)
|
420 |
with gr.Column(scale=1):
|
421 |
-
chart_output = gr.Plot(label="Crack Trend (Operations Maintenance
|
422 |
-
pie_output = gr.Plot(label="Crack Severity (Operations Maintenance
|
|
|
423 |
|
424 |
with gr.Row():
|
425 |
captured_images = gr.Gallery(label="Detected Frames (Last 100+)", columns=4, rows=25, height="auto")
|
@@ -429,7 +450,6 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green"))
|
|
429 |
resume_btn = gr.Button("▶️ Resume", variant="primary")
|
430 |
frame_slider = gr.Slider(0.05, 1.0, value=0.1, label="Frame Interval (seconds)", step=0.05)
|
431 |
|
432 |
-
# Add some custom CSS for better UX
|
433 |
gr.HTML("""
|
434 |
<style>
|
435 |
#live-feed {
|
@@ -459,7 +479,6 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green"))
|
|
459 |
global frame_rate
|
460 |
frame_rate = val
|
461 |
|
462 |
-
# Initialize video on app load
|
463 |
video_status.value = initialize_video()
|
464 |
|
465 |
load_button.click(
|
@@ -468,7 +487,6 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green"))
|
|
468 |
outputs=[video_status]
|
469 |
)
|
470 |
|
471 |
-
# Toggle change events
|
472 |
def update_toggles(uc_val, om_val, rs_val, pl_val):
|
473 |
active, status_message = set_active_service("toggle", uc_val, om_val, rs_val, pl_val)
|
474 |
uc_status_val = "Enabled" if active == "under_construction" else "Disabled"
|
@@ -493,16 +511,16 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green"))
|
|
493 |
def streaming_loop():
|
494 |
while True:
|
495 |
if not video_loaded:
|
496 |
-
yield None, json.dumps({"error": "Video not loaded. Please upload a video file."}, indent=2), "\n".join(log_entries[-10:]), None, None, last_detected_images
|
497 |
else:
|
498 |
-
frame, detections, logs, line_chart, pie_chart, captured = monitor_feed()
|
499 |
if frame is None:
|
500 |
-
yield None, detections, logs, line_chart, pie_chart, captured
|
501 |
else:
|
502 |
-
yield frame, detections, logs, line_chart, pie_chart, captured
|
503 |
time.sleep(frame_rate)
|
504 |
|
505 |
-
app.load(streaming_loop, outputs=[video_output, detections_output, logs_output, chart_output, pie_output, captured_images])
|
506 |
|
507 |
if __name__ == "__main__":
|
508 |
app.launch(share=True)
|
|
|
26 |
from services.road_safety.barrier_check import process_barriers
|
27 |
from services.road_safety.lighting_check import process_lighting
|
28 |
from services.road_safety.accident_spot_check import process_accident_spots
|
29 |
+
from services.road_safety.pothole_crack_detection import detect_potholes_and_cracks
|
30 |
# Plantation services
|
31 |
from services.plantation.plant_count import process_plants
|
32 |
from services.plantation.plant_health import process_plant_health
|
|
|
41 |
|
42 |
# Globals
|
43 |
paused = False
|
44 |
+
frame_rate = 0.1
|
45 |
frame_count = 0
|
46 |
log_entries = []
|
47 |
crack_counts = []
|
|
|
49 |
last_frame = None
|
50 |
last_detections = {}
|
51 |
last_timestamp = ""
|
52 |
+
last_detected_images = []
|
53 |
gps_coordinates = []
|
54 |
video_loaded = False
|
55 |
+
active_service = None
|
56 |
|
57 |
# Constants
|
58 |
DEFAULT_VIDEO_PATH = "sample.mp4"
|
|
|
63 |
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
64 |
|
65 |
def initialize_video(video_file=None):
|
|
|
|
|
|
|
66 |
global video_loaded, log_entries
|
67 |
release_video()
|
68 |
video_path = DEFAULT_VIDEO_PATH
|
|
|
79 |
return status
|
80 |
|
81 |
def set_active_service(service_name, uc_val, om_val, rs_val, pl_val):
|
82 |
+
global active_service
|
|
|
|
|
|
|
|
|
83 |
toggles = {
|
84 |
"under_construction": uc_val,
|
85 |
"operations_maintenance": om_val,
|
|
|
87 |
"plantation": pl_val
|
88 |
}
|
89 |
|
|
|
90 |
active_count = sum(toggles.values())
|
91 |
if active_count > 1:
|
92 |
log_entries.append("Error: Only one service category can be active at a time.")
|
93 |
logging.error("Multiple service categories enabled simultaneously.")
|
94 |
return None, "Error: Please enable only one service category at a time."
|
95 |
|
|
|
96 |
for service, enabled in toggles.items():
|
97 |
if enabled:
|
98 |
active_service = service
|
|
|
106 |
return None, "No Service Category Enabled"
|
107 |
|
108 |
def monitor_feed():
|
|
|
|
|
|
|
|
|
109 |
global paused, frame_count, last_frame, last_detections, last_timestamp, gps_coordinates, last_detected_images, video_loaded
|
110 |
|
111 |
if not video_loaded:
|
112 |
log_entries.append("Cannot start streaming: Video not loaded successfully.")
|
113 |
logging.error("Video not loaded successfully.")
|
114 |
+
return None, json.dumps({"error": "Video not loaded. Please upload a video file."}, indent=2), "\n".join(log_entries[-10:]), None, None, None, last_detected_images
|
115 |
|
116 |
if paused and last_frame is not None:
|
117 |
frame = last_frame.copy()
|
|
|
124 |
except RuntimeError as e:
|
125 |
log_entries.append(f"Error: {str(e)}")
|
126 |
logging.error(f"Frame retrieval error: {str(e)}")
|
127 |
+
return None, json.dumps(last_detections, indent=2), "\n".join(log_entries[-10:]), None, None, None, last_detected_images
|
128 |
|
|
|
129 |
all_detected_items = []
|
130 |
|
|
|
131 |
try:
|
132 |
if active_service == "under_construction":
|
133 |
earthwork_dets, frame = process_earthwork(frame)
|
|
|
146 |
barrier_dets, frame = process_barriers(frame)
|
147 |
lighting_dets, frame = process_lighting(frame)
|
148 |
accident_dets, frame = process_accident_spots(frame)
|
149 |
+
pothole_crack_dets, frame = detect_potholes_and_cracks(frame)
|
150 |
+
all_detected_items.extend(barrier_dets + lighting_dets + accident_dets + pothole_crack_dets)
|
151 |
|
152 |
elif active_service == "plantation":
|
153 |
plant_dets, frame = process_plants(frame)
|
|
|
156 |
all_detected_items.extend(plant_dets + health_dets + missing_dets)
|
157 |
|
158 |
else:
|
|
|
159 |
generic_dets, frame = process_generic(frame)
|
160 |
all_detected_items.extend(generic_dets)
|
161 |
|
|
|
162 |
shadow_results = detect_shadows(frame)
|
163 |
shadow_dets = shadow_results["detections"]
|
164 |
frame = shadow_results["frame"]
|
165 |
all_detected_items.extend(shadow_dets)
|
166 |
|
167 |
+
if len(frame.shape) == 2:
|
|
|
168 |
thermal_results = process_thermal(frame)
|
169 |
thermal_dets = thermal_results["detections"]
|
170 |
frame = thermal_results["frame"]
|
|
|
175 |
logging.error(f"Processing error in {active_service}: {str(e)}")
|
176 |
all_detected_items = []
|
177 |
|
|
|
178 |
try:
|
179 |
cv2.imwrite(TEMP_IMAGE_PATH, frame, [int(cv2.IMWRITE_JPEG_QUALITY), 95])
|
180 |
except Exception as e:
|
|
|
183 |
|
184 |
metrics = update_metrics(all_detected_items)
|
185 |
|
|
|
186 |
gps_coord = [17.385044 + random.uniform(-0.001, 0.001), 78.486671 + frame_count * 0.0001]
|
187 |
gps_coordinates.append(gps_coord)
|
188 |
|
|
|
189 |
detection_types = {item.get("type") for item in all_detected_items if "type" in item}
|
190 |
if detection_types:
|
191 |
try:
|
|
|
198 |
log_entries.append(f"Error saving captured frame: {str(e)}")
|
199 |
logging.error(f"Error saving captured frame: {str(e)}")
|
200 |
|
|
|
201 |
all_detections = {
|
202 |
"items": all_detected_items,
|
203 |
"metrics": metrics,
|
|
|
206 |
"gps_coordinates": gps_coord
|
207 |
}
|
208 |
|
|
|
209 |
try:
|
210 |
dispatch_to_salesforce(all_detections, all_detections["timestamp"])
|
211 |
except Exception as e:
|
212 |
log_entries.append(f"Salesforce Dispatch Error: {str(e)}")
|
213 |
logging.error(f"Salesforce dispatch error: {str(e)}")
|
214 |
|
|
|
215 |
try:
|
216 |
frame_path = os.path.join(OUTPUT_DIR, f"frame_{frame_count:04d}.jpg")
|
217 |
cv2.imwrite(frame_path, frame)
|
|
|
224 |
last_frame = frame.copy()
|
225 |
last_detections = metrics
|
226 |
|
227 |
+
crack_detected = len([item for item in all_detected_items if item.get("type") == "crack"]) if active_service in ["operations_maintenance", "road_safety"] else 0
|
228 |
+
if active_service in ["operations_maintenance", "road_safety"]:
|
|
|
229 |
crack_severity_all.extend([
|
230 |
item["severity"]
|
231 |
for item in all_detected_items
|
|
|
246 |
if len(crack_severity_all) > 500:
|
247 |
crack_severity_all.pop(0)
|
248 |
|
|
|
249 |
frame = cv2.resize(last_frame, (640, 480))
|
250 |
cv2.putText(frame, f"Frame: {frame_count}", (10, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
|
251 |
cv2.putText(frame, f"{last_timestamp}", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
|
252 |
|
|
|
253 |
line_chart = None
|
254 |
pie_chart = None
|
255 |
+
bar_chart = None
|
256 |
+
if active_service in ["operations_maintenance", "road_safety"]:
|
257 |
line_chart = generate_line_chart()
|
258 |
pie_chart = generate_pie_chart()
|
259 |
+
bar_chart = generate_bar_chart()
|
260 |
|
261 |
+
return frame[:, :, ::-1], json.dumps(last_detections, indent=2), "\n".join(log_entries[-10:]), line_chart, pie_chart, bar_chart, last_detected_images
|
262 |
|
263 |
def generate_line_chart():
|
|
|
|
|
|
|
264 |
if not crack_counts:
|
265 |
return None
|
266 |
|
267 |
+
data = crack_counts[-50:]
|
268 |
labels = list(range(len(data)))
|
269 |
|
270 |
return {
|
|
|
274 |
"datasets": [{
|
275 |
"label": "Cracks Over Time",
|
276 |
"data": data,
|
277 |
+
"borderColor": "#FF6347",
|
278 |
"backgroundColor": "rgba(255, 99, 71, 0.2)",
|
279 |
"fill": True,
|
280 |
"tension": 0.4
|
|
|
285 |
"plugins": {
|
286 |
"title": {
|
287 |
"display": True,
|
288 |
+
"text": "Crack Trend"
|
289 |
}
|
290 |
},
|
291 |
"scales": {
|
|
|
307 |
}
|
308 |
|
309 |
def generate_pie_chart():
|
|
|
|
|
|
|
310 |
if not crack_severity_all:
|
311 |
return None
|
312 |
|
313 |
+
count = Counter(crack_severity_all[-200:])
|
314 |
labels = list(count.keys())
|
315 |
sizes = list(count.values())
|
316 |
|
|
|
321 |
"datasets": [{
|
322 |
"data": sizes,
|
323 |
"backgroundColor": [
|
324 |
+
"#FF6347",
|
325 |
+
"#4682B4",
|
326 |
+
"#FFD700"
|
327 |
]
|
328 |
}]
|
329 |
},
|
|
|
332 |
"plugins": {
|
333 |
"title": {
|
334 |
"display": True,
|
335 |
+
"text": "Crack Severity"
|
336 |
},
|
337 |
"legend": {
|
338 |
"position": "top"
|
|
|
341 |
}
|
342 |
}
|
343 |
|
344 |
+
def generate_bar_chart():
|
345 |
+
if not crack_severity_all:
|
346 |
+
return None
|
347 |
+
|
348 |
+
count = Counter(crack_severity_all[-200:])
|
349 |
+
labels = list(count.keys())
|
350 |
+
sizes = list(count.values())
|
351 |
+
|
352 |
+
return {
|
353 |
+
"type": "bar",
|
354 |
+
"data": {
|
355 |
+
"labels": labels,
|
356 |
+
"datasets": [{
|
357 |
+
"label": "Severity Distribution",
|
358 |
+
"data": sizes,
|
359 |
+
"backgroundColor": [
|
360 |
+
"#FF6347",
|
361 |
+
"#4682B4",
|
362 |
+
"#FFD700"
|
363 |
+
]
|
364 |
+
}]
|
365 |
+
},
|
366 |
+
"options": {
|
367 |
+
"responsive": True,
|
368 |
+
"plugins": {
|
369 |
+
"title": {
|
370 |
+
"display": True,
|
371 |
+
"text": "Severity Distribution"
|
372 |
+
},
|
373 |
+
"legend": {
|
374 |
+
"display": False
|
375 |
+
}
|
376 |
+
},
|
377 |
+
"scales": {
|
378 |
+
"y": {
|
379 |
+
"beginAtZero": True,
|
380 |
+
"title": {
|
381 |
+
"display": True,
|
382 |
+
"text": "Count"
|
383 |
+
}
|
384 |
+
},
|
385 |
+
"x": {
|
386 |
+
"title": {
|
387 |
+
"display": True,
|
388 |
+
"text": "Severity"
|
389 |
+
}
|
390 |
+
}
|
391 |
+
}
|
392 |
+
}
|
393 |
+
}
|
394 |
+
|
395 |
# Gradio UI
|
396 |
with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green")) as app:
|
397 |
gr.Markdown(
|
|
|
401 |
"""
|
402 |
)
|
403 |
|
|
|
404 |
with gr.Row():
|
405 |
with gr.Column(scale=3):
|
406 |
video_input = gr.File(label="Upload Video File (e.g., sample.mp4)", file_types=["video"])
|
|
|
412 |
interactive=False
|
413 |
)
|
414 |
|
|
|
415 |
with gr.Row():
|
416 |
with gr.Column():
|
417 |
uc_toggle = gr.Checkbox(label="Enable Under Construction Services", value=False)
|
|
|
438 |
with gr.Column(scale=2):
|
439 |
logs_output = gr.Textbox(label="Live Logs", lines=8, interactive=False)
|
440 |
with gr.Column(scale=1):
|
441 |
+
chart_output = gr.Plot(label="Crack Trend (Operations Maintenance & Road Safety)")
|
442 |
+
pie_output = gr.Plot(label="Crack Severity (Operations Maintenance & Road Safety)")
|
443 |
+
bar_output = gr.Plot(label="Severity Distribution (Operations Maintenance & Road Safety)")
|
444 |
|
445 |
with gr.Row():
|
446 |
captured_images = gr.Gallery(label="Detected Frames (Last 100+)", columns=4, rows=25, height="auto")
|
|
|
450 |
resume_btn = gr.Button("▶️ Resume", variant="primary")
|
451 |
frame_slider = gr.Slider(0.05, 1.0, value=0.1, label="Frame Interval (seconds)", step=0.05)
|
452 |
|
|
|
453 |
gr.HTML("""
|
454 |
<style>
|
455 |
#live-feed {
|
|
|
479 |
global frame_rate
|
480 |
frame_rate = val
|
481 |
|
|
|
482 |
video_status.value = initialize_video()
|
483 |
|
484 |
load_button.click(
|
|
|
487 |
outputs=[video_status]
|
488 |
)
|
489 |
|
|
|
490 |
def update_toggles(uc_val, om_val, rs_val, pl_val):
|
491 |
active, status_message = set_active_service("toggle", uc_val, om_val, rs_val, pl_val)
|
492 |
uc_status_val = "Enabled" if active == "under_construction" else "Disabled"
|
|
|
511 |
def streaming_loop():
|
512 |
while True:
|
513 |
if not video_loaded:
|
514 |
+
yield None, json.dumps({"error": "Video not loaded. Please upload a video file."}, indent=2), "\n".join(log_entries[-10:]), None, None, None, last_detected_images
|
515 |
else:
|
516 |
+
frame, detections, logs, line_chart, pie_chart, bar_chart, captured = monitor_feed()
|
517 |
if frame is None:
|
518 |
+
yield None, detections, logs, line_chart, pie_chart, bar_chart, captured
|
519 |
else:
|
520 |
+
yield frame, detections, logs, line_chart, pie_chart, bar_chart, captured
|
521 |
time.sleep(frame_rate)
|
522 |
|
523 |
+
app.load(streaming_loop, outputs=[video_output, detections_output, logs_output, chart_output, pie_output, bar_output, captured_images])
|
524 |
|
525 |
if __name__ == "__main__":
|
526 |
app.launch(share=True)
|