nagasurendra commited on
Commit
78f6b92
·
verified ·
1 Parent(s): 53065c4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +136 -94
app.py CHANGED
@@ -165,142 +165,179 @@ def generate_report(
165
  io_times: List[float]
166
  ) -> str:
167
  log_entries.append("Generating report...")
168
- report_path = os.path.join(OUTPUT_DIR, f"drone_analysis_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md")
169
  timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
170
  report_content = [
171
- "# NHAI Drone Survey Analysis Report",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  "",
173
- "## Project Details",
174
- "- Project Name: NH-44 Delhi-Hyderabad Section (Package XYZ)",
175
- "- Highway Section: Km 100 to Km 150",
176
- "- State: Telangana",
177
- "- Region: South",
178
- f"- Survey Date: {datetime.now().strftime('%Y-%m-%d')}",
179
- "- Drone Service Provider: ABC Drone Services Pvt. Ltd.",
180
- "- Technology Service Provider: XYZ AI Analytics Ltd.",
181
- f"- Work Order Reference: Data Lake WO-{datetime.now().strftime('%Y-%m-%d')}-XYZ",
182
- "- Report Prepared By: Nagasurendra, Data Analyst",
183
- f"- Report Date: {datetime.now().strftime('%Y-%m-%d')}",
 
 
184
  "",
185
- "## 1. Introduction",
186
- "This report consolidates drone survey results for NH-44 (Km 100–150) under Operations & Maintenance, per NHAI Policy Circular No. 18.98/2024, detecting potholes and cracks using YOLOv8 for Monthly Progress Report integration.",
187
  "",
188
- "## 2. Drone Survey Metadata",
189
- "- Drone Speed: 5 m/s",
190
- "- Drone Height: 60 m",
191
- "- Camera Sensor: RGB, 12 MP",
192
- "- Recording Type: JPEG, 90° nadir",
193
- "- Image Overlap: 85%",
194
- "- Flight Pattern: Single lap, ROW centered",
195
- "- Geotagging: Enabled",
196
- "- Satellite Lock: 12 satellites",
197
- "- Terrain Follow Mode: Enabled",
 
 
198
  "",
199
- "## 3. Quality Check Results",
200
- "- Resolution: 1920x1080",
201
- "- Overlap: 85%",
202
- "- Camera Angle: 90° nadir",
203
- "- Drone Speed: ≤ 5 m/s",
204
- "- Geotagging: 100% compliant",
205
- "- QC Status: Passed",
 
 
206
  "",
207
- "## 4. AI/ML Analytics",
208
- f"- Total Frames Processed: {frame_count}",
209
- f"- Detection Frames: {detection_frame_count} ({detection_frame_count/frame_count*100:.1f}%)",
210
- f"- Total Detections: {metrics['total_detections']}",
211
- " - Breakdown:"
 
212
  ]
213
 
214
  for item in metrics.get("items", []):
215
  percentage = (item["count"] / metrics["total_detections"] * 100) if metrics["total_detections"] > 0 else 0
216
- report_content.append(f" - {item['type']}: {item['count']} ({percentage:.1f}%)")
217
  report_content.extend([
218
- f"- Processing Time: {total_time:.1f} seconds",
219
- f"- Average Frame Time: {sum(frame_times)/len(frame_times):.1f} ms" if frame_times else "- Average Frame Time: N/A",
220
- f"- Average Resize Time: {sum(resize_times)/len(resize_times):.1f} ms" if resize_times else "- Average Resize Time: N/A",
221
- f"- Average Inference Time: {sum(inference_times)/len(inference_times):.1f} ms" if inference_times else "- Average Inference Time: N/A",
222
- f"- Average I/O Time: {sum(io_times)/len(io_times):.1f} ms" if io_times else "- Average I/O Time: N/A",
223
- f"- Timestamp: {metrics.get('timestamp', 'N/A')}",
224
- "- Summary: Potholes and cracks detected in high-traffic areas.",
 
225
  "",
226
- "## 5. Output File Structure",
227
- "- ZIP file contains:",
228
- " - `drone_analysis_report_<timestamp>.md`: This report",
229
- " - `outputs/processed_output.mp4`: Processed video with annotations",
230
- " - `outputs/chart_<timestamp>.png`: Detection trend chart",
231
- " - `outputs/map_<timestamp>.png`: Issue locations map",
232
- " - `captured_frames/detected_<frame>.jpg`: Geotagged images for detected issues",
233
- " - `flight_logs/flight_log_<frame>.csv`: Flight logs matching image frames",
234
- "- Note: Images and logs share frame numbers (e.g., `detected_000001.jpg` corresponds to `flight_log_000001.csv`).",
 
 
235
  "",
236
- "## 6. Geotagged Images",
237
- f"- Total Images: {len(detected_issues)}",
238
- f"- Storage: Data Lake `/project_xyz/images/{datetime.now().strftime('%Y%m%d')}`",
239
  "",
240
- "| Frame | Issue Type | GPS (Lat, Lon) | Timestamp | Confidence | Image Path |",
241
- "|-------|------------|----------------|-----------|------------|------------|"
242
  ])
243
 
244
  for detection in all_detections[:100]:
245
  report_content.append(
246
- f"| {detection['frame']:06d} | {detection['label']} | ({detection['gps'][0]:.6f}, {detection['gps'][1]:.6f}) | {detection['timestamp']} | {detection['conf']:.1f} | captured_frames/{os.path.basename(detection['path'])} |"
247
  )
248
 
249
  report_content.extend([
 
250
  "",
251
- "## 7. Flight Logs",
252
- f"- Total Logs: {len(detected_issues)}",
253
- f"- Storage: Data Lake `/project_xyz/flight_logs/{datetime.now().strftime('%Y%m%d')}`",
254
  "",
255
- "| Frame | Timestamp | Latitude | Longitude | Speed (m/s) | Satellites | Altitude (m) | Log Path |",
256
- "|-------|-----------|----------|-----------|-------------|------------|--------------|----------|"
257
  ])
258
 
259
  for detection in all_detections[:100]:
260
  log_path = f"flight_logs/flight_log_{detection['frame']:06d}.csv"
261
  report_content.append(
262
- f"| {detection['frame']:06d} | {detection['timestamp']} | {detection['gps'][0]:.6f} | {detection['gps'][1]:.6f} | 5.0 | 12 | 60 | {log_path} |"
263
  )
264
 
265
  report_content.extend([
 
266
  "",
267
- "## 8. Processed Video",
268
- f"- Path: outputs/processed_output.mp4",
269
- f"- Frames: {output_frames}",
270
- f"- FPS: {output_fps:.1f}",
271
- f"- Duration: {output_duration:.1f} seconds",
272
  "",
273
- "## 9. Visualizations",
274
- f"- Detection Trend Chart: outputs/chart_{timestamp}.png",
275
- f"- Issue Locations Map: outputs/map_{timestamp}.png",
276
  "",
277
- "## 10. Processing Timestamps",
278
- f"- Total Processing Time: {total_time:.1f} seconds",
279
- "- Log Entries (Last 10):"
 
280
  ])
281
 
282
  for entry in log_entries[-10:]:
283
- report_content.append(f" - {entry}")
284
 
285
  report_content.extend([
 
286
  "",
287
- "## 11. Stakeholder Validation",
288
- "- AE/IE Comments: [Pending]",
289
- "- PD/RO Comments: [Pending]",
 
 
290
  "",
291
- "## 12. Recommendations",
292
- "- Repair potholes in high-traffic areas.",
293
- "- Seal cracks to prevent further degradation.",
294
- "- Schedule a follow-up survey.",
 
 
295
  "",
296
- "## 13. Data Lake References",
297
- f"- Images: `/project_xyz/images/{datetime.now().strftime('%Y%m%d')}`",
298
- f"- Flight Logs: `/project_xyz/flight_logs/{datetime.now().strftime('%Y%m%d')}`",
299
- f"- Video: `/project_xyz/videos/processed_output_{timestamp}.mp4`",
300
- f"- DAMS Dashboard: `/project_xyz/dams/{datetime.now().strftime('%Y%m%d')}`",
 
 
301
  "",
302
- "## 14. Captured Images",
303
- "Below are the embedded images from the captured frames directory showing detected issues:",
304
  ""
305
  ])
306
 
@@ -310,12 +347,17 @@ def generate_report(
310
  try:
311
  with open(image_path, "rb") as image_file:
312
  base64_string = base64.b64encode(image_file.read()).decode('utf-8')
313
- report_content.append(f"![{image_name}](data:image/jpeg;base64,{base64_string})")
314
- report_content.append(f"**Image: {image_name}**")
315
  report_content.append("")
316
  except Exception as e:
317
  log_entries.append(f"Error: Failed to encode image {image_name} to base64: {str(e)}")
318
 
 
 
 
 
 
319
  try:
320
  with open(report_path, 'w') as f:
321
  f.write("\n".join(report_content))
 
165
  io_times: List[float]
166
  ) -> str:
167
  log_entries.append("Generating report...")
168
+ report_path = os.path.join(OUTPUT_DIR, f"drone_analysis_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.html")
169
  timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
170
  report_content = [
171
+ "<!DOCTYPE html>",
172
+ "<html lang='en'>",
173
+ "<head>",
174
+ "<meta charset='UTF-8'>",
175
+ "<title>NHAI Drone Survey Analysis Report</title>",
176
+ "<style>",
177
+ "body { font-family: Arial, sans-serif; margin: 40px; }",
178
+ "h1, h2, h3 { color: #333; }",
179
+ "ul { margin-left: 20px; }",
180
+ "table { border-collapse: collapse; width: 100%; margin: 10px 0; }",
181
+ "th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }",
182
+ "th { background-color: #f2f2f2; }",
183
+ "img { max-width: 600px; height: auto; margin: 10px 0; }",
184
+ "p.caption { font-weight: bold; margin: 5px 0; }",
185
+ "</style>",
186
+ "</head>",
187
+ "<body>",
188
+ "<h1>NHAI Drone Survey Analysis Report</h1>",
189
  "",
190
+ "<h2>Project Details</h2>",
191
+ "<ul>",
192
+ "<li><strong>Project Name:</strong> NH-44 Delhi-Hyderabad Section (Package XYZ)</li>",
193
+ "<li><strong>Highway Section:</strong> Km 100 to Km 150</li>",
194
+ "<li><strong>State:</strong> Telangana</li>",
195
+ "<li><strong>Region:</strong> South</li>",
196
+ f"<li><strong>Survey Date:</strong> {datetime.now().strftime('%Y-%m-%d')}</li>",
197
+ "<li><strong>Drone Service Provider:</strong> ABC Drone Services Pvt. Ltd.</li>",
198
+ "<li><strong>Technology Service Provider:</strong> XYZ AI Analytics Ltd.</li>",
199
+ f"<li><strong>Work Order Reference:</strong> Data Lake WO-{datetime.now().strftime('%Y-%m-%d')}-XYZ</li>",
200
+ "<li><strong>Report Prepared By:</strong> Nagasurendra, Data Analyst</li>",
201
+ f"<li><strong>Report Date:</strong> {datetime.now().strftime('%Y-%m-%d')}</li>",
202
+ "</ul>",
203
  "",
204
+ "<h2>1. Introduction</h2>",
205
+ "<p>This report consolidates drone survey results for NH-44 (Km 100–150) under Operations & Maintenance, per NHAI Policy Circular No. 18.98/2024, detecting potholes and cracks using YOLOv8 for Monthly Progress Report integration.</p>",
206
  "",
207
+ "<h2>2. Drone Survey Metadata</h2>",
208
+ "<ul>",
209
+ "<li><strong>Drone Speed:</strong> 5 m/s</li>",
210
+ "<li><strong>Drone Height:</strong> 60 m</li>",
211
+ "<li><strong>Camera Sensor:</strong> RGB, 12 MP</li>",
212
+ "<li><strong>Recording Type:</strong> JPEG, 90° nadir</li>",
213
+ "<li><strong>Image Overlap:</strong> 85%</li>",
214
+ "<li><strong>Flight Pattern:</strong> Single lap, ROW centered</li>",
215
+ "<li><strong>Geotagging:</strong> Enabled</li>",
216
+ "<li><strong>Satellite Lock:</strong> 12 satellites</li>",
217
+ "<li><strong>Terrain Follow Mode:</strong> Enabled</li>",
218
+ "</ul>",
219
  "",
220
+ "<h2>3. Quality Check Results</h2>",
221
+ "<ul>",
222
+ "<li><strong>Resolution:</strong> 1920x1080</li>",
223
+ "<li><strong>Overlap:</strong> 85%</li>",
224
+ "<li><strong>Camera Angle:</strong> 90° nadir</li>",
225
+ "<li><strong>Drone Speed:</strong> 5 m/s</li>",
226
+ "<li><strong>Geotagging:</strong> 100% compliant</li>",
227
+ "<li><strong>QC Status:</strong> Passed</li>",
228
+ "</ul>",
229
  "",
230
+ "<h2>4. AI/ML Analytics</h2>",
231
+ f"<p><strong>Total Frames Processed:</strong> {frame_count}</p>",
232
+ f"<p><strong>Detection Frames:</strong> {detection_frame_count} ({detection_frame_count/frame_count*100:.1f}%)</p>",
233
+ f"<p><strong>Total Detections:</strong> {metrics['total_detections']}</p>",
234
+ "<p><strong>Breakdown:</strong></p>",
235
+ "<ul>"
236
  ]
237
 
238
  for item in metrics.get("items", []):
239
  percentage = (item["count"] / metrics["total_detections"] * 100) if metrics["total_detections"] > 0 else 0
240
+ report_content.append(f"<li>{item['type']}: {item['count']} ({percentage:.1f}%)</li>")
241
  report_content.extend([
242
+ "</ul>",
243
+ f"<p><strong>Processing Time:</strong> {total_time:.1f} seconds</p>",
244
+ f"<p><strong>Average Frame Time:</strong> {sum(frame_times)/len(frame_times):.1f} ms</p>" if frame_times else "<p><strong>Average Frame Time:</strong> N/A</p>",
245
+ f"<p><strong>Average Resize Time:</strong> {sum(resize_times)/len(resize_times):.1f} ms</p>" if resize_times else "<p><strong>Average Resize Time:</strong> N/A</p>",
246
+ f"<p><strong>Average Inference Time:</strong> {sum(inference_times)/len(inference_times):.1f} ms</p>" if inference_times else "<p><strong>Average Inference Time:</strong> N/A</p>",
247
+ f"<p><strong>Average I/O Time:</strong> {sum(io_times)/len(io_times):.1f} ms</p>" if io_times else "<p><strong>Average I/O Time:</strong> N/A</p>",
248
+ f"<p><strong>Timestamp:</strong> {metrics.get('timestamp', 'N/A')}</p>",
249
+ "<p><strong>Summary:</strong> Potholes and cracks detected in high-traffic areas.</p>",
250
  "",
251
+ "<h2>5. Output File Structure</h2>",
252
+ "<p>ZIP file contains:</p>",
253
+ "<ul>",
254
+ f"<li><code>drone_analysis_report_{timestamp}.html</code>: This report</li>",
255
+ "<li><code>outputs/processed_output.mp4</code>: Processed video with annotations</li>",
256
+ f"<li><code>outputs/chart_{timestamp}.png</code>: Detection trend chart</li>",
257
+ f"<li><code>outputs/map_{timestamp}.png</code>: Issue locations map</li>",
258
+ "<li><code>captured_frames/detected_&lt;frame&gt;.jpg</code>: Geotagged images for detected issues</li>",
259
+ "<li><code>flight_logs/flight_log_&lt;frame&gt;.csv</code>: Flight logs matching image frames</li>",
260
+ "</ul>",
261
+ "<p><strong>Note:</strong> Images and logs share frame numbers (e.g., <code>detected_000001.jpg</code> corresponds to <code>flight_log_000001.csv</code>).</p>",
262
  "",
263
+ "<h2>6. Geotagged Images</h2>",
264
+ f"<p><strong>Total Images:</strong> {len(detected_issues)}</p>",
265
+ f"<p><strong>Storage:</strong> Data Lake <code>/project_xyz/images/{datetime.now().strftime('%Y%m%d')}</code></p>",
266
  "",
267
+ "<table>",
268
+ "<tr><th>Frame</th><th>Issue Type</th><th>GPS (Lat, Lon)</th><th>Timestamp</th><th>Confidence</th><th>Image Path</th></tr>"
269
  ])
270
 
271
  for detection in all_detections[:100]:
272
  report_content.append(
273
+ f"<tr><td>{detection['frame']:06d}</td><td>{detection['label']}</td><td>({detection['gps'][0]:.6f}, {detection['gps'][1]:.6f})</td><td>{detection['timestamp']}</td><td>{detection['conf']:.1f}</td><td>captured_frames/{os.path.basename(detection['path'])}</td></tr>"
274
  )
275
 
276
  report_content.extend([
277
+ "</table>",
278
  "",
279
+ "<h2>7. Flight Logs</h2>",
280
+ f"<p><strong>Total Logs:</strong> {len(detected_issues)}</p>",
281
+ f"<p><strong>Storage:</strong> Data Lake <code>/project_xyz/flight_logs/{datetime.now().strftime('%Y%m%d')}</code></p>",
282
  "",
283
+ "<table>",
284
+ "<tr><th>Frame</th><th>Timestamp</th><th>Latitude</th><th>Longitude</th><th>Speed (m/s)</th><th>Satellites</th><th>Altitude (m)</th><th>Log Path</th></tr>"
285
  ])
286
 
287
  for detection in all_detections[:100]:
288
  log_path = f"flight_logs/flight_log_{detection['frame']:06d}.csv"
289
  report_content.append(
290
+ f"<tr><td>{detection['frame']:06d}</td><td>{detection['timestamp']}</td><td>{detection['gps'][0]:.6f}</td><td>{detection['gps'][1]:.6f}</td><td>5.0</td><td>12</td><td>60</td><td>{log_path}</td></tr>"
291
  )
292
 
293
  report_content.extend([
294
+ "</table>",
295
  "",
296
+ "<h2>8. Processed Video</h2>",
297
+ f"<p><strong>Path:</strong> outputs/processed_output.mp4</p>",
298
+ f"<p><strong>Frames:</strong> {output_frames}</p>",
299
+ f"<p><strong>FPS:</strong> {output_fps:.1f}</p>",
300
+ f"<p><strong>Duration:</strong> {output_duration:.1f} seconds</p>",
301
  "",
302
+ "<h2>9. Visualizations</h2>",
303
+ f"<p><strong>Detection Trend Chart:</strong> outputs/chart_{timestamp}.png</p>",
304
+ f"<p><strong>Issue Locations Map:</strong> outputs/map_{timestamp}.png</p>",
305
  "",
306
+ "<h2>10. Processing Timestamps</h2>",
307
+ f"<p><strong>Total Processing Time:</strong> {total_time:.1f} seconds</p>",
308
+ "<p><strong>Log Entries (Last 10):</strong></p>",
309
+ "<ul>"
310
  ])
311
 
312
  for entry in log_entries[-10:]:
313
+ report_content.append(f"<li>{entry}</li>")
314
 
315
  report_content.extend([
316
+ "</ul>",
317
  "",
318
+ "<h2>11. Stakeholder Validation</h2>",
319
+ "<ul>",
320
+ "<li><strong>AE/IE Comments:</strong> [Pending]</li>",
321
+ "<li><strong>PD/RO Comments:</strong> [Pending]</li>",
322
+ "</ul>",
323
  "",
324
+ "<h2>12. Recommendations</h2>",
325
+ "<ul>",
326
+ "<li>Repair potholes in high-traffic areas.</li>",
327
+ "<li>Seal cracks to prevent further degradation.</li>",
328
+ "<li>Schedule a follow-up survey.</li>",
329
+ "</ul>",
330
  "",
331
+ "<h2>13. Data Lake References</h2>",
332
+ "<ul>",
333
+ f"<li><strong>Images:</strong> <code>/project_xyz/images/{datetime.now().strftime('%Y%m%d')}</code></li>",
334
+ f"<li><strong>Flight Logs:</strong> <code>/project_xyz/flight_logs/{datetime.now().strftime('%Y%m%d')}</code></li>",
335
+ f"<li><strong>Video:</strong> <code>/project_xyz/videos/processed_output_{timestamp}.mp4</code></li>",
336
+ f"<li><strong>DAMS Dashboard:</strong> <code>/project_xyz/dams/{datetime.now().strftime('%Y%m%d')}</code></li>",
337
+ "</ul>",
338
  "",
339
+ "<h2>14. Captured Images</h2>",
340
+ "<p>Below are the embedded images from the captured frames directory showing detected issues:</p>",
341
  ""
342
  ])
343
 
 
347
  try:
348
  with open(image_path, "rb") as image_file:
349
  base64_string = base64.b64encode(image_file.read()).decode('utf-8')
350
+ report_content.append(f"<img src='data:image/jpeg;base64,{base64_string}' alt='{image_name}'>")
351
+ report_content.append(f"<p class='caption'>Image: {image_name}</p>")
352
  report_content.append("")
353
  except Exception as e:
354
  log_entries.append(f"Error: Failed to encode image {image_name} to base64: {str(e)}")
355
 
356
+ report_content.extend([
357
+ "</body>",
358
+ "</html>"
359
+ ])
360
+
361
  try:
362
  with open(report_path, 'w') as f:
363
  f.write("\n".join(report_content))