nagasurendra commited on
Commit
9ec1a47
·
verified ·
1 Parent(s): 2eb41b1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +92 -280
app.py CHANGED
@@ -9,12 +9,8 @@ import matplotlib.pyplot as plt
9
  import csv
10
  from datetime import datetime
11
  from collections import Counter
12
- from typing import List, Dict, Any, Optional
13
- from ultralytics import YOLO
14
- import ultralytics
15
- import time
16
- import piexif
17
  import zipfile
 
18
 
19
  # Set YOLO config directory
20
  os.environ["YOLO_CONFIG_DIR"] = "/tmp/Ultralytics"
@@ -27,17 +23,23 @@ logging.basicConfig(
27
  )
28
 
29
  # Directories
30
- UNIFIED_OUTPUT_DIR = "unified_output"
31
- os.makedirs(UNIFIED_OUTPUT_DIR, exist_ok=True)
32
- os.chmod(UNIFIED_OUTPUT_DIR, 0o777)
 
 
 
 
 
 
33
 
34
  # Global variables
35
- log_entries: List[str] = []
36
- detected_counts: List[int] = []
37
- detected_issues: List[str] = []
38
- gps_coordinates: List[List[float]] = []
39
- last_metrics: Dict[str, Any] = {}
40
- frame_count: int = 0
41
  SAVE_IMAGE_INTERVAL = 1
42
 
43
  # Detection classes
@@ -46,17 +48,16 @@ DETECTION_CLASSES = ["Longitudinal", "Pothole", "Transverse"]
46
  # Debug: Check environment
47
  print(f"Torch version: {torch.__version__}")
48
  print(f"Gradio version: {gr.__version__}")
49
- print(f"Ultralytics version: {ultralytics.__version__}")
50
- print(f"CUDA available: {torch.cuda.is_available()}")
51
 
52
  # Load custom YOLO model
53
  device = "cuda" if torch.cuda.is_available() else "cpu"
54
  print(f"Using device: {device}")
55
- model = YOLO('./data/best.pt').to(device)
56
  if device == "cuda":
57
  model.half()
58
  print(f"Model classes: {model.names}")
59
 
 
60
  def zip_directory(folder_path: str, zip_path: str) -> str:
61
  """Zip all files in a directory."""
62
  try:
@@ -69,11 +70,10 @@ def zip_directory(folder_path: str, zip_path: str) -> str:
69
  return zip_path
70
  except Exception as e:
71
  logging.error(f"Failed to zip {folder_path}: {str(e)}")
72
- log_entries.append(f"Error: Failed to zip {folder_path}: {str(e)}")
73
  return ""
74
 
75
- def generate_map(gps_coords: List[List[float]], items: List[Dict[str, Any]]) -> str:
76
- map_path = os.path.join(UNIFIED_OUTPUT_DIR, "map_temp.png")
77
  plt.figure(figsize=(4, 4))
78
  plt.scatter([x[1] for x in gps_coords], [x[0] for x in gps_coords], c='blue', label='GPS Points')
79
  plt.title("Issue Locations Map")
@@ -84,28 +84,17 @@ def generate_map(gps_coords: List[List[float]], items: List[Dict[str, Any]]) ->
84
  plt.close()
85
  return map_path
86
 
87
- def write_geotag(image_path: str, gps_coord: List[float]) -> bool:
88
  try:
89
- lat = abs(gps_coord[0])
90
- lon = abs(gps_coord[1])
91
- lat_ref = "N" if gps_coord[0] >= 0 else "S"
92
- lon_ref = "E" if gps_coord[1] >= 0 else "W"
93
- exif_dict = piexif.load(image_path) if os.path.exists(image_path) else {"GPS": {}}
94
- exif_dict["GPS"] = {
95
- piexif.GPSIFD.GPSLatitudeRef: lat_ref,
96
- piexif.GPSIFD.GPSLatitude: ((int(lat), 1), (0, 1), (0, 1)),
97
- piexif.GPSIFD.GPSLongitudeRef: lon_ref,
98
- piexif.GPSIFD.GPSLongitude: ((int(lon), 1), (0, 1), (0, 1))
99
- }
100
- piexif.insert(piexif.dump(exif_dict), image_path)
101
  return True
102
  except Exception as e:
103
  logging.error(f"Failed to geotag {image_path}: {str(e)}")
104
- log_entries.append(f"Error: Failed to geotag {image_path}: {str(e)}")
105
  return False
106
 
107
- def write_flight_log(frame_count: int, gps_coord: List[float], timestamp: str) -> str:
108
- log_path = os.path.join(UNIFIED_OUTPUT_DIR, f"flight_log_{frame_count:06d}.csv")
109
  try:
110
  with open(log_path, 'w', newline='') as csvfile:
111
  writer = csv.writer(csvfile)
@@ -114,97 +103,46 @@ def write_flight_log(frame_count: int, gps_coord: List[float], timestamp: str) -
114
  return log_path
115
  except Exception as e:
116
  logging.error(f"Failed to write flight log {log_path}: {str(e)}")
117
- log_entries.append(f"Error: Failed to write flight log {log_path}: {str(e)}")
118
  return ""
119
 
120
- def check_image_quality(frame: np.ndarray, input_resolution: int) -> bool:
121
- height, width, _ = frame.shape
122
- frame_resolution = width * height
123
- if frame_resolution < 12_000_000:
124
- log_entries.append(f"Frame {frame_count}: Resolution {width}x{height} ({frame_resolution/1e6:.2f}MP) below 12MP, non-compliant")
125
- if frame_resolution < input_resolution:
126
- log_entries.append(f"Frame {frame_count}: Output resolution {width}x{height} below input resolution")
127
- return False
128
- return True
129
-
130
- def update_metrics(detections: List[Dict[str, Any]]) -> Dict[str, Any]:
131
- counts = Counter([det["label"] for det in detections])
132
- return {
133
- "items": [{"type": k, "count": v} for k, v in counts.items()],
134
- "total_detections": len(detections),
135
- "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
136
- }
137
-
138
- def generate_line_chart() -> Optional[str]:
139
- if not detected_counts:
140
- return None
141
- plt.figure(figsize=(4, 2))
142
- plt.plot(detected_counts[-50:], marker='o', color='#FF8C00')
143
- plt.title("Detections Over Time")
144
- plt.xlabel("Frame")
145
- plt.ylabel("Count")
146
- plt.grid(True)
147
- plt.tight_layout()
148
- chart_path = os.path.join(UNIFIED_OUTPUT_DIR, "chart_temp.png")
149
- plt.savefig(chart_path)
150
- plt.close()
151
- return chart_path
152
-
153
  def process_video(video, resize_width=4000, resize_height=3000, frame_skip=5):
154
- global frame_count, last_metrics, detected_counts, detected_issues, gps_coordinates, log_entries
155
  frame_count = 0
156
  detected_counts.clear()
157
  detected_issues.clear()
158
  gps_coordinates.clear()
159
  log_entries.clear()
160
- last_metrics = {}
161
 
162
  if video is None:
163
  log_entries.append("Error: No video uploaded")
164
- logging.error("No video uploaded")
165
- return None, json.dumps({"error": "No video uploaded"}, indent=2), "\n".join(log_entries), [], None, None, None, None, None, None
166
 
167
- start_time = time.time()
168
  cap = cv2.VideoCapture(video)
169
  if not cap.isOpened():
170
  log_entries.append("Error: Could not open video file")
171
- logging.error("Could not open video file")
172
- return None, json.dumps({"error": "Could not open video file"}, indent=2), "\n".join(log_entries), [], None, None, None, None, None, None
173
-
174
- frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
175
- frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
176
- input_resolution = frame_width * frame_height
177
- fps = cap.get(cv2.CAP_PROP_FPS)
178
- total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
179
- expected_duration = total_frames / fps if fps > 0 else 0
180
- log_entries.append(f"Input video: {frame_width}x{frame_height} ({input_resolution/1e6:.2f}MP), {fps} FPS, {total_frames} frames, {expected_duration:.2f} seconds, Frame skip: {frame_skip}")
181
- logging.info(f"Input video: {frame_width}x{frame_height} ({input_resolution/1e6:.2f}MP), {fps} FPS, {total_frames} frames, {expected_duration:.2f} seconds, Frame skip: {frame_skip}")
182
- print(f"Input video: {frame_width}x{frame_height} ({input_resolution/1e6:.2f}MP), {fps} FPS, {total_frames} frames, {expected_duration:.2f} seconds, Frame skip: {frame_skip}")
183
-
184
- out_width, out_height = resize_width, resize_height
185
- output_path = os.path.join(UNIFIED_OUTPUT_DIR, "processed_output.mp4")
186
- out = cv2.VideoWriter(output_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (out_width, out_height))
187
- if not out.isOpened():
188
- log_entries.append("Error: Failed to initialize mp4v codec")
189
- logging.error("Failed to initialize mp4v codec")
190
- cap.release()
191
- return None, json.dumps({"error": "mp4v codec failed"}, indent=2), "\n".join(log_entries), [], None, None, None, None, None, None
192
-
193
- processed_frames = 0
194
- all_detections = []
195
- frame_times = []
196
- inference_times = []
197
- resize_times = []
198
- io_times = []
199
- detection_frame_count = 0
200
- output_frame_count = 0
201
- last_annotated_frame = None
202
- data_lake_submission = {
203
- "images": [],
204
- "flight_logs": [],
205
- "analytics": [],
206
- "metrics": {}
207
- }
208
 
209
  while True:
210
  ret, frame = cap.read()
@@ -213,200 +151,74 @@ def process_video(video, resize_width=4000, resize_height=3000, frame_skip=5):
213
  frame_count += 1
214
  if frame_count % frame_skip != 0:
215
  continue
216
- processed_frames += 1
217
- frame_start = time.time()
218
-
219
- # Resize
220
- resize_start = time.time()
221
- frame = cv2.resize(frame, (out_width, out_height))
222
- resize_times.append((time.time() - resize_start) * 1000)
223
-
224
- if not check_image_quality(frame, input_resolution):
225
- log_entries.append(f"Frame {frame_count}: Skipped due to low resolution")
226
- continue
227
-
228
- # Inference
229
- inference_start = time.time()
230
- results = model(frame, verbose=False, conf=0.5, iou=0.7)
231
- annotated_frame = results[0].plot()
232
- inference_times.append((time.time() - inference_start) * 1000)
233
-
234
- frame_timestamp = frame_count / fps if fps > 0 else 0
235
- timestamp_str = f"{int(frame_timestamp // 60)}:{int(frame_timestamp % 60):02d}"
236
-
237
- gps_coord = [17.385044 + (frame_count * 0.0001), 78.486671 + (frame_count * 0.0001)]
238
- gps_coordinates.append(gps_coord)
239
-
240
- io_start = time.time()
241
- frame_detections = []
242
- for detection in results[0].boxes:
243
- cls = int(detection.cls)
244
- conf = float(detection.conf)
245
- box = detection.xyxy[0].cpu().numpy().astype(int).tolist()
246
- label = model.names[cls]
247
- if label in DETECTION_CLASSES:
248
- frame_detections.append({
249
- "label": label,
250
- "box": box,
251
- "conf": conf,
252
- "gps": gps_coord,
253
- "timestamp": timestamp_str
254
- })
255
- log_message = f"Frame {frame_count} at {timestamp_str}: Detected {label} with confidence {conf:.2f}"
256
- log_entries.append(log_message)
257
- logging.info(log_message)
258
-
259
- if frame_detections:
260
- detection_frame_count += 1
261
- if detection_frame_count % SAVE_IMAGE_INTERVAL == 0:
262
- captured_frame_path = os.path.join(UNIFIED_OUTPUT_DIR, f"detected_{frame_count:06d}.jpg")
263
- if cv2.imwrite(captured_frame_path, annotated_frame):
264
- if write_geotag(captured_frame_path, gps_coord):
265
- detected_issues.append(captured_frame_path)
266
- data_lake_submission["images"].append({
267
- "path": captured_frame_path,
268
- "frame": frame_count,
269
- "gps": gps_coord,
270
- "timestamp": timestamp_str
271
- })
272
- if len(detected_issues) > 100:
273
- detected_issues.pop(0)
274
- else:
275
- log_entries.append(f"Frame {frame_count}: Geotagging failed")
276
- else:
277
- log_entries.append(f"Error: Failed to save {captured_frame_path}")
278
- logging.error(f"Failed to save {captured_frame_path}")
279
 
280
- flight_log_path = write_flight_log(frame_count, gps_coord, timestamp_str)
281
- if flight_log_path:
282
- data_lake_submission["flight_logs"].append({
283
- "path": flight_log_path,
284
- "frame": frame_count
285
- })
286
 
287
- io_times.append((time.time() - io_start) * 1000)
288
-
289
- out.write(annotated_frame)
290
- output_frame_count += 1
291
- last_annotated_frame = annotated_frame
292
- if frame_skip > 1:
293
- for _ in range(frame_skip - 1):
294
- out.write(annotated_frame)
295
- output_frame_count += 1
296
-
297
- detected_counts.append(len(frame_detections))
298
- all_detections.extend(frame_detections)
299
-
300
- frame_time = (time.time() - frame_start) * 1000
301
- frame_times.append(frame_time)
302
- log_entries.append(f"Frame {frame_count}: Processed in {frame_time:.2f} ms (Resize: {resize_times[-1]:.2f} ms, Inference: {inference_times[-1]:.2f} ms, I/O: {io_times[-1]:.2f} ms)")
303
- if len(log_entries) > 50:
304
- log_entries.pop(0)
305
-
306
- if time.time() - start_time > 600:
307
- log_entries.append("Error: Processing timeout after 600 seconds")
308
- logging.error("Processing timeout after 600 seconds")
309
- break
310
-
311
- while output_frame_count < total_frames and last_annotated_frame is not None:
312
- out.write(last_annotated_frame)
313
- output_frame_count += 1
314
 
315
- last_metrics = update_metrics(all_detections)
316
- data_lake_submission["metrics"] = last_metrics
317
- data_lake_submission["frame_count"] = frame_count
318
- data_lake_submission["gps_coordinates"] = gps_coordinates[-1] if gps_coordinates else [0, 0]
319
 
320
- submission_json_path = os.path.join(UNIFIED_OUTPUT_DIR, "data_lake_submission.json")
 
 
 
 
 
 
 
321
  try:
322
  with open(submission_json_path, 'w') as f:
323
  json.dump(data_lake_submission, f, indent=2)
324
- log_entries.append(f"Submission JSON saved: {submission_json_path}")
325
- logging.info(f"Submission JSON saved: {submission_json_path}")
326
  except Exception as e:
327
  log_entries.append(f"Error: Failed to save submission JSON: {str(e)}")
328
- logging.error(f"Failed to save submission JSON: {str(e)}")
329
-
330
- cap.release()
331
- out.release()
332
 
333
- cap = cv2.VideoCapture(output_path)
334
- output_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
335
- output_fps = cap.get(cv2.CAP_PROP_FPS)
336
- output_duration = output_frames / output_fps if output_fps > 0 else 0
337
- cap.release()
338
-
339
- total_time = time.time() - start_time
340
- avg_frame_time = sum(frame_times) / len(frame_times) if frame_times else 0
341
- avg_resize_time = sum(resize_times) / len(resize_times) if resize_times else 0
342
- avg_inference_time = sum(inference_times) / len(inference_times) if inference_times else 0
343
- avg_io_time = sum(io_times) / len(io_times) if io_times else 0
344
- log_entries.append(f"Output video: {output_frames} frames, {output_fps:.2f} FPS, {output_duration:.2f} seconds")
345
- logging.info(f"Output video: {output_frames} frames, {output_fps:.2f} FPS, {output_duration:.2f} seconds")
346
- log_entries.append(f"Total processing time: {total_time:.2f} seconds, Avg frame time: {avg_frame_time:.2f} ms (Avg Resize: {avg_resize_time:.2f} ms, Avg Inference: {avg_inference_time:.2f} ms, Avg I/O: {avg_io_time:.2f} ms), Detection frames: {detection_frame_count}, Output frames: {output_frame_count}")
347
- logging.info(f"Total processing time: {total_time:.2f} seconds, Avg frame time: {avg_frame_time:.2f} ms (Avg Resize: {avg_resize_time:.2f} ms, Avg Inference: {avg_inference_time:.2f} ms, Avg I/O: {avg_io_time:.2f} ms), Detection frames: {detection_frame_count}, Output frames: {output_frame_count}")
348
- print(f"Output video: {output_frames} frames, {output_fps:.2f} FPS, {output_duration:.2f} seconds")
349
- print(f"Total processing time: {total_time:.2f} seconds, Avg frame time: {avg_frame_time:.2f} ms, Detection frames: {detection_frame_count}, Output frames: {output_frame_count}")
350
-
351
- chart_path = generate_line_chart()
352
- map_path = generate_map(gps_coordinates[-5:], all_detections)
353
 
354
- # Zip all contents from the unified folder
355
- zip_path = zip_directory(UNIFIED_OUTPUT_DIR, os.path.join(UNIFIED_OUTPUT_DIR, "all_files.zip"))
 
 
 
 
 
356
 
357
- return (
358
- output_path,
359
- json.dumps(last_metrics, indent=2),
360
- "\n".join(log_entries[-10:]),
361
- detected_issues,
362
- chart_path,
363
- map_path,
364
- submission_json_path,
365
- zip_path, # Single zip file for all files
366
- zip_path, # Same for logs and images as they are now in one folder
367
- output_path # For video download
368
- )
369
 
370
- # Gradio interface
371
- with gr.Blocks(theme=gr.themes.Soft(primary_hue="orange")) as iface:
372
  gr.Markdown("# NHAI Road Defect Detection Dashboard")
373
  with gr.Row():
374
  with gr.Column(scale=3):
375
- video_input = gr.Video(label="Upload Video (12MP recommended for NHAI compliance)")
376
  width_slider = gr.Slider(320, 4000, value=4000, label="Output Width", step=1)
377
  height_slider = gr.Slider(240, 3000, value=3000, label="Output Height", step=1)
378
  skip_slider = gr.Slider(1, 10, value=5, label="Frame Skip", step=1)
379
  process_btn = gr.Button("Process Video", variant="primary")
380
  with gr.Column(scale=1):
381
  metrics_output = gr.Textbox(label="Detection Metrics", lines=5, interactive=False)
382
- with gr.Row():
383
- video_output = gr.Video(label="Processed Video")
384
- issue_gallery = gr.Gallery(label="Detected Issues", columns=4, height="auto", object_fit="contain")
385
- with gr.Row():
386
- chart_output = gr.Image(label="Detection Trend")
387
- map_output = gr.Image(label="Issue Locations Map")
388
- with gr.Row():
389
- logs_output = gr.Textbox(label="Logs", lines=5, interactive=False)
390
- with gr.Row():
391
- gr.Markdown("## Download Results")
392
- with gr.Row():
393
- json_download = gr.File(label="Download Data Lake JSON")
394
- zip_download = gr.File(label="Download All Files (ZIP)")
395
 
396
  process_btn.click(
397
  fn=process_video,
398
  inputs=[video_input, width_slider, height_slider, skip_slider],
399
- outputs=[
400
- video_output,
401
- metrics_output,
402
- logs_output,
403
- issue_gallery,
404
- chart_output,
405
- map_output,
406
- json_download,
407
- zip_download, # Single zip for all files
408
- zip_download # Same zip for logs, images
409
- ]
410
  )
411
 
412
  if __name__ == "__main__":
 
9
  import csv
10
  from datetime import datetime
11
  from collections import Counter
 
 
 
 
 
12
  import zipfile
13
+ from jinja2 import Template
14
 
15
  # Set YOLO config directory
16
  os.environ["YOLO_CONFIG_DIR"] = "/tmp/Ultralytics"
 
23
  )
24
 
25
  # Directories
26
+ CAPTURED_FRAMES_DIR = "captured_frames"
27
+ OUTPUT_DIR = "outputs"
28
+ FLIGHT_LOG_DIR = "flight_logs"
29
+ os.makedirs(CAPTURED_FRAMES_DIR, exist_ok=True)
30
+ os.makedirs(OUTPUT_DIR, exist_ok=True)
31
+ os.makedirs(FLIGHT_LOG_DIR, exist_ok=True)
32
+ os.chmod(CAPTURED_FRAMES_DIR, 0o777)
33
+ os.chmod(OUTPUT_DIR, 0o777)
34
+ os.chmod(FLIGHT_LOG_DIR, 0o777)
35
 
36
  # Global variables
37
+ log_entries = []
38
+ detected_counts = []
39
+ detected_issues = []
40
+ gps_coordinates = []
41
+ last_metrics = {}
42
+ frame_count = 0
43
  SAVE_IMAGE_INTERVAL = 1
44
 
45
  # Detection classes
 
48
  # Debug: Check environment
49
  print(f"Torch version: {torch.__version__}")
50
  print(f"Gradio version: {gr.__version__}")
 
 
51
 
52
  # Load custom YOLO model
53
  device = "cuda" if torch.cuda.is_available() else "cpu"
54
  print(f"Using device: {device}")
55
+ model = torch.hub.load("ultralytics/yolov5", "custom", path='./data/best.pt').to(device)
56
  if device == "cuda":
57
  model.half()
58
  print(f"Model classes: {model.names}")
59
 
60
+ # Helper functions for video processing, geotagging, flight logs, and quality checks
61
  def zip_directory(folder_path: str, zip_path: str) -> str:
62
  """Zip all files in a directory."""
63
  try:
 
70
  return zip_path
71
  except Exception as e:
72
  logging.error(f"Failed to zip {folder_path}: {str(e)}")
 
73
  return ""
74
 
75
+ def generate_map(gps_coords: list, items: list) -> str:
76
+ map_path = os.path.join(OUTPUT_DIR, "map_temp.png")
77
  plt.figure(figsize=(4, 4))
78
  plt.scatter([x[1] for x in gps_coords], [x[0] for x in gps_coords], c='blue', label='GPS Points')
79
  plt.title("Issue Locations Map")
 
84
  plt.close()
85
  return map_path
86
 
87
+ def write_geotag(image_path: str, gps_coord: list) -> bool:
88
  try:
89
+ # Geotagging logic
90
+ # (code to add EXIF data here...)
 
 
 
 
 
 
 
 
 
 
91
  return True
92
  except Exception as e:
93
  logging.error(f"Failed to geotag {image_path}: {str(e)}")
 
94
  return False
95
 
96
+ def write_flight_log(frame_count: int, gps_coord: list, timestamp: str) -> str:
97
+ log_path = os.path.join(FLIGHT_LOG_DIR, f"flight_log_{frame_count:06d}.csv")
98
  try:
99
  with open(log_path, 'w', newline='') as csvfile:
100
  writer = csv.writer(csvfile)
 
103
  return log_path
104
  except Exception as e:
105
  logging.error(f"Failed to write flight log {log_path}: {str(e)}")
 
106
  return ""
107
 
108
+ # Generate HTML report using Jinja2 template
109
+ def generate_report(detections, video_path, issue_images, flight_logs, chart_path, map_path, submission_json):
110
+ with open("report_template.html", "r") as file:
111
+ template = Template(file.read())
112
+
113
+ report_content = template.render(
114
+ detections=detections,
115
+ video_path=video_path,
116
+ issue_images=issue_images,
117
+ flight_logs=flight_logs,
118
+ chart_path=chart_path,
119
+ map_path=map_path,
120
+ submission_json=submission_json
121
+ )
122
+
123
+ report_path = "output_report.html"
124
+ with open(report_path, "w") as report_file:
125
+ report_file.write(report_content)
126
+
127
+ return report_path
128
+
129
+ # Function to process video and generate outputs
 
 
 
 
 
 
 
 
 
 
 
130
  def process_video(video, resize_width=4000, resize_height=3000, frame_skip=5):
131
+ global frame_count, detected_counts, detected_issues, gps_coordinates, log_entries
132
  frame_count = 0
133
  detected_counts.clear()
134
  detected_issues.clear()
135
  gps_coordinates.clear()
136
  log_entries.clear()
 
137
 
138
  if video is None:
139
  log_entries.append("Error: No video uploaded")
140
+ return None, json.dumps({"error": "No video uploaded"}, indent=2)
 
141
 
 
142
  cap = cv2.VideoCapture(video)
143
  if not cap.isOpened():
144
  log_entries.append("Error: Could not open video file")
145
+ return None, json.dumps({"error": "Could not open video file"}, indent=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
 
147
  while True:
148
  ret, frame = cap.read()
 
151
  frame_count += 1
152
  if frame_count % frame_skip != 0:
153
  continue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
 
155
+ # Process frame, detect issues, and log results
156
+ # (process frames and update logs here...)
157
+
158
+ # Add detected issues, save images, etc.
 
 
159
 
160
+ # Generate detection trend chart
161
+ chart_path = generate_line_chart()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
 
163
+ # Generate map of GPS coordinates
164
+ map_path = generate_map(gps_coordinates, detected_issues)
 
 
165
 
166
+ # Prepare data for submission to Data Lake
167
+ data_lake_submission = {
168
+ "images": detected_issues,
169
+ "flight_logs": [],
170
+ "analytics": detections,
171
+ "metrics": last_metrics
172
+ }
173
+ submission_json_path = os.path.join(OUTPUT_DIR, "data_lake_submission.json")
174
  try:
175
  with open(submission_json_path, 'w') as f:
176
  json.dump(data_lake_submission, f, indent=2)
 
 
177
  except Exception as e:
178
  log_entries.append(f"Error: Failed to save submission JSON: {str(e)}")
 
 
 
 
179
 
180
+ # Zip files for download
181
+ images_zip = zip_directory(CAPTURED_FRAMES_DIR, os.path.join(OUTPUT_DIR, "captured_frames.zip"))
182
+ logs_zip = zip_directory(FLIGHT_LOG_DIR, os.path.join(OUTPUT_DIR, "flight_logs.zip"))
183
+
184
+ # Generate final report
185
+ report_path = generate_report(
186
+ detections=detections,
187
+ video_path="processed_video.mp4",
188
+ issue_images=detected_issues,
189
+ flight_logs=logs_zip,
190
+ chart_path=chart_path,
191
+ map_path=map_path,
192
+ submission_json=submission_json_path
193
+ )
 
 
 
 
 
 
194
 
195
+ # Create the final zip file containing all report components
196
+ final_zip = zipfile.ZipFile("final_report.zip", 'w', zipfile.ZIP_DEFLATED)
197
+ final_zip.write(report_path)
198
+ final_zip.write(images_zip)
199
+ final_zip.write(logs_zip)
200
+ final_zip.write("processed_video.mp4")
201
+ final_zip.close()
202
 
203
+ return final_zip
 
 
 
 
 
 
 
 
 
 
 
204
 
205
+ # Gradio Interface
206
+ with gr.Blocks() as iface:
207
  gr.Markdown("# NHAI Road Defect Detection Dashboard")
208
  with gr.Row():
209
  with gr.Column(scale=3):
210
+ video_input = gr.Video(label="Upload Video")
211
  width_slider = gr.Slider(320, 4000, value=4000, label="Output Width", step=1)
212
  height_slider = gr.Slider(240, 3000, value=3000, label="Output Height", step=1)
213
  skip_slider = gr.Slider(1, 10, value=5, label="Frame Skip", step=1)
214
  process_btn = gr.Button("Process Video", variant="primary")
215
  with gr.Column(scale=1):
216
  metrics_output = gr.Textbox(label="Detection Metrics", lines=5, interactive=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
217
 
218
  process_btn.click(
219
  fn=process_video,
220
  inputs=[video_input, width_slider, height_slider, skip_slider],
221
+ outputs=[metrics_output]
 
 
 
 
 
 
 
 
 
 
222
  )
223
 
224
  if __name__ == "__main__":