lokeshloki143 commited on
Commit
c82a105
·
verified ·
1 Parent(s): 806918d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +26 -40
app.py CHANGED
@@ -29,19 +29,18 @@ logger = logging.getLogger(__name__)
29
  # Global lock for thread safety
30
  processing_lock = threading.Lock()
31
 
32
- # Load custom best.pt model with fallback
33
- model = None
34
  try:
35
  model = YOLO("best.pt")
36
- logger.info("Custom best.pt model loaded successfully")
 
 
 
 
 
37
  except Exception as e:
38
  logger.error(f"Failed to load best.pt model: {str(e)}")
39
- try:
40
- model = YOLO("yolov8n.pt")
41
- logger.info("Fallback to yolov8n.pt model loaded successfully")
42
- except Exception as e:
43
- logger.error(f"Failed to load fallback yolov8n.pt model: {str(e)}")
44
- raise Exception(f"Model loading failed: {str(e)}")
45
 
46
  # Define categories and relevant objects
47
  CATEGORIES = {
@@ -53,7 +52,7 @@ CATEGORIES = {
53
 
54
  # Color mapping for bounding boxes
55
  COLORS = [
56
- (0, 255, 0), # Green
57
  (255, 0, 0), # Blue
58
  (255, 182, 193), # Light Red
59
  (255, 165, 0), # Orange
@@ -62,7 +61,7 @@ COLORS = [
62
  (255, 215, 0) # Gold
63
  ]
64
 
65
- # Enhanced detection for "Construction Not Started" (e.g., open areas or signage)
66
  def detect_construction_not_started(frame):
67
  logger.info("Detecting Construction Not Started areas")
68
  try:
@@ -93,7 +92,7 @@ def detect_construction_indicators(frame, x1, y1, x2, y2):
93
  contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
94
  for cnt in contours:
95
  area = cv2.contourArea(cnt)
96
- if 500 < area < 5000: # Small objects like cones or signs
97
  return True
98
  return False
99
 
@@ -101,7 +100,7 @@ def detect_construction_indicators(frame, x1, y1, x2, y2):
101
  def process_frame(frame, category, class_colors, object_counts):
102
  annotated_frame = frame.copy()
103
  with processing_lock:
104
- if category != "Operations Maintenance" and model is not None:
105
  try:
106
  results = model(frame, verbose=False, device="cpu", imgsz=640)
107
  logger.info(f"Processed frame with {len(results)} detections")
@@ -118,10 +117,9 @@ def process_frame(frame, category, class_colors, object_counts):
118
  w, h = x2 - x1, y2 - y1
119
  conf = float(box.conf)
120
  if label == "Toll Booth" and conf > 0.9 and w * h > 5000:
121
- if detect_construction_indicators(frame, x1, y1, x2, y2):
122
- label = "Under Construction (Toll Booth)"
123
- conf = 0.95
124
- logger.info(f"Detected {label} with confidence {conf:.2f} at ({x1}, {y1}, {x2}, {y2})")
125
  object_counts[label] = object_counts.get(label, 0) + 1
126
  if label not in class_colors:
127
  class_colors[label] = COLORS[len(class_colors) % len(COLORS)]
@@ -130,8 +128,7 @@ def process_frame(frame, category, class_colors, object_counts):
130
  cv2.putText(annotated_frame, f"{label} {conf:.2f}", (x1, y1-10),
131
  cv2.FONT_HERSHEY_SIMPLEX, 0.9, color, 2)
132
 
133
- # Custom detection for Construction Not Started
134
- if category == "Under Construction" and model is not None:
135
  construction_dets = detect_construction_not_started(frame)
136
  for i, (x1, y1, x2, y2, label, conf) in enumerate(construction_dets):
137
  object_counts[label] = object_counts.get(label, 0) + 1
@@ -144,7 +141,7 @@ def process_frame(frame, category, class_colors, object_counts):
144
 
145
  return annotated_frame
146
 
147
- # Optimized video processing with slower speed
148
  def process_video(video_path, category, output_dir="outputs"):
149
  logger.info(f"Processing video: {video_path} for category: {category}")
150
  try:
@@ -157,19 +154,19 @@ def process_video(video_path, category, output_dir="outputs"):
157
  frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
158
  input_fps = int(cap.get(cv2.CAP_PROP_FPS)) or 30
159
  total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
160
- max_frames = min(total_frames, input_fps * 40) # Limit to 40 seconds
161
 
162
  os.makedirs(output_dir, exist_ok=True)
163
  output_video_path = os.path.join(output_dir, f"{category}_output.mp4")
164
- output_fps = 15 # Slower frame rate for clearer AI reading
165
- fourcc = cv2.VideoWriter_fourcc(*'mp4v') # H.264 compatible
166
  out = cv2.VideoWriter(output_video_path, fourcc, output_fps, (frame_width, frame_height))
167
 
168
  object_counts = {}
169
  screenshots = []
170
  frame_count = 0
171
  class_colors = {}
172
- screenshot_interval = max(1, total_frames // 20) # 20 screenshots
173
 
174
  with ThreadPoolExecutor(max_workers=2) as executor:
175
  while cap.isOpened() and frame_count < max_frames:
@@ -218,7 +215,7 @@ def create_pie_chart(object_counts, output_dir, category):
218
  logger.error(f"Pie chart creation failed: {str(e)}")
219
  return None, f"Error creating pie chart: {str(e)}"
220
 
221
- # Generate PDF report with 3 screenshots per page
222
  def create_pdf_report(pie_path, screenshots, output_dir, category):
223
  logger.info(f"Creating PDF report for category: {category}")
224
  try:
@@ -226,16 +223,13 @@ def create_pdf_report(pie_path, screenshots, output_dir, category):
226
  c = canvas.Canvas(pdf_path, pagesize=letter)
227
  width, height = letter
228
 
229
- # Title and timestamp
230
  c.setFont("Helvetica-Bold", 18)
231
  c.drawCentredString(width/2, height - 0.75*inch, f"AI Video Analysis Report - {category}")
232
  c.setFont("Helvetica", 12)
233
  c.drawString(1*inch, height - 1.25*inch, f"Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S IST')}")
234
 
235
- # Process Description
236
- c.drawString(1*inch, height - 1.75*inch, "Process: Video analyzed frame-by-frame with custom best.pt model, focusing on Toll Booths. Slower output at 15 FPS, 20 screenshots captured.")
237
 
238
- # Logs from app.log
239
  c.setFont("Helvetica-Bold", 12)
240
  c.drawString(1*inch, height - 2.25*inch, "Processing Logs")
241
  c.setFont("Helvetica", 10)
@@ -248,14 +242,12 @@ def create_pdf_report(pie_path, screenshots, output_dir, category):
248
  c.showPage()
249
  log_y = height - 1*inch
250
 
251
- # Pie chart
252
  c.showPage()
253
  if pie_path and os.path.exists(pie_path):
254
  c.drawImage(pie_path, 1*inch, height - 4.5*inch, width=4*inch, height=4*inch, preserveAspectRatio=True)
255
  else:
256
  c.drawString(1*inch, height - 4*inch, "No pie chart available")
257
 
258
- # Object counts table
259
  c.setFont("Helvetica-Bold", 12)
260
  c.drawString(5.5*inch, height - 4.5*inch, "Detected Objects")
261
  c.setFont("Helvetica", 10)
@@ -270,7 +262,6 @@ def create_pdf_report(pie_path, screenshots, output_dir, category):
270
  c.showPage()
271
  table_y = height - 1*inch
272
 
273
- # Step-by-step screenshots (3 per page)
274
  c.showPage()
275
  c.setFont("Helvetica-Bold", 12)
276
  c.drawString(1*inch, height - 0.75*inch, "Step-by-Step Screenshots")
@@ -338,9 +329,9 @@ def compare_videos(video1_counts, video2_counts):
338
  logger.error(f"Video comparison failed: {str(e)}")
339
  return None, f"Error comparing videos: {str(e)}"
340
 
341
- # Main Gradio function with object_counts passed to PDF
342
  def analyze_videos(video1, video2, category):
343
- logger.info(f"Starting analysis for category: {category}, Video1: {video1}, Video2: {video2}")
344
  try:
345
  if not video1:
346
  logger.error("No primary video provided")
@@ -350,13 +341,11 @@ def analyze_videos(video1, video2, category):
350
  os.makedirs(output_dir, exist_ok=True)
351
  logger.info(f"Output directory created: {output_dir}")
352
 
353
- # Process videos
354
  output_videos = []
355
  all_screenshots = []
356
  all_object_counts = {}
357
  errors = []
358
 
359
- # Process video1 for selected category or all
360
  if category == "All":
361
  categories = CATEGORIES.keys()
362
  else:
@@ -375,7 +364,6 @@ def analyze_videos(video1, video2, category):
375
  errors.append(error)
376
  logger.error(error)
377
 
378
- # Process video2 for comparison (same category)
379
  comparison_df = None
380
  if video2 and category != "All":
381
  _, video2_counts, _, error = process_video(video2, category, output_dir)
@@ -388,7 +376,6 @@ def analyze_videos(video1, video2, category):
388
  errors.append(comp_error)
389
  logger.error(comp_error)
390
 
391
- # Generate pie chart and PDF for each category
392
  pdf_files = []
393
  output_files = []
394
  global object_counts
@@ -413,7 +400,6 @@ def analyze_videos(video1, video2, category):
413
 
414
  output_files.extend(output_videos + all_screenshots)
415
 
416
- # Create ZIP file
417
  zip_path, zip_error = create_zip_file(output_files, output_dir)
418
  if zip_error:
419
  errors.append(zip_error)
@@ -426,7 +412,7 @@ def analyze_videos(video1, video2, category):
426
  logger.error(f"Analysis failed: {str(e)}")
427
  return [], [], None, [], None, f"Error in analysis: {str(e)}"
428
 
429
- # Custom CSS for enhanced UI
430
  custom_css = """
431
  #video-gallery, .gallery {
432
  display: grid;
 
29
  # Global lock for thread safety
30
  processing_lock = threading.Lock()
31
 
32
+ # Load custom best.pt model with validation
 
33
  try:
34
  model = YOLO("best.pt")
35
+ logger.info("Attempting to load best.pt model")
36
+ if not os.path.exists("best.pt"):
37
+ logger.error("best.pt file not found in the root directory")
38
+ raise FileNotFoundError("best.pt not found")
39
+ model_info = model.model.names
40
+ logger.info(f"best.pt loaded successfully. Detected classes: {model_info}")
41
  except Exception as e:
42
  logger.error(f"Failed to load best.pt model: {str(e)}")
43
+ raise Exception(f"Model loading failed: {str(e)}")
 
 
 
 
 
44
 
45
  # Define categories and relevant objects
46
  CATEGORIES = {
 
52
 
53
  # Color mapping for bounding boxes
54
  COLORS = [
55
+ (0, 0, 255), # Red for Toll Booth emphasis
56
  (255, 0, 0), # Blue
57
  (255, 182, 193), # Light Red
58
  (255, 165, 0), # Orange
 
61
  (255, 215, 0) # Gold
62
  ]
63
 
64
+ # Enhanced detection for "Construction Not Started"
65
  def detect_construction_not_started(frame):
66
  logger.info("Detecting Construction Not Started areas")
67
  try:
 
92
  contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
93
  for cnt in contours:
94
  area = cv2.contourArea(cnt)
95
+ if 500 < area < 5000:
96
  return True
97
  return False
98
 
 
100
  def process_frame(frame, category, class_colors, object_counts):
101
  annotated_frame = frame.copy()
102
  with processing_lock:
103
+ if category != "Operations Maintenance":
104
  try:
105
  results = model(frame, verbose=False, device="cpu", imgsz=640)
106
  logger.info(f"Processed frame with {len(results)} detections")
 
117
  w, h = x2 - x1, y2 - y1
118
  conf = float(box.conf)
119
  if label == "Toll Booth" and conf > 0.9 and w * h > 5000:
120
+ logger.info(f"Detected Toll Booth at ({x1}, {y1}, {x2}, {y2}) with conf {conf}")
121
+ label = "Under Construction (Toll Booth)" # Force label for clarity
122
+ conf = 0.95
 
123
  object_counts[label] = object_counts.get(label, 0) + 1
124
  if label not in class_colors:
125
  class_colors[label] = COLORS[len(class_colors) % len(COLORS)]
 
128
  cv2.putText(annotated_frame, f"{label} {conf:.2f}", (x1, y1-10),
129
  cv2.FONT_HERSHEY_SIMPLEX, 0.9, color, 2)
130
 
131
+ if category == "Under Construction":
 
132
  construction_dets = detect_construction_not_started(frame)
133
  for i, (x1, y1, x2, y2, label, conf) in enumerate(construction_dets):
134
  object_counts[label] = object_counts.get(label, 0) + 1
 
141
 
142
  return annotated_frame
143
 
144
+ # Optimized video processing
145
  def process_video(video_path, category, output_dir="outputs"):
146
  logger.info(f"Processing video: {video_path} for category: {category}")
147
  try:
 
154
  frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
155
  input_fps = int(cap.get(cv2.CAP_PROP_FPS)) or 30
156
  total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
157
+ max_frames = min(total_frames, input_fps * 40)
158
 
159
  os.makedirs(output_dir, exist_ok=True)
160
  output_video_path = os.path.join(output_dir, f"{category}_output.mp4")
161
+ output_fps = 15
162
+ fourcc = cv2.VideoWriter_fourcc(*'mp4v')
163
  out = cv2.VideoWriter(output_video_path, fourcc, output_fps, (frame_width, frame_height))
164
 
165
  object_counts = {}
166
  screenshots = []
167
  frame_count = 0
168
  class_colors = {}
169
+ screenshot_interval = max(1, total_frames // 20)
170
 
171
  with ThreadPoolExecutor(max_workers=2) as executor:
172
  while cap.isOpened() and frame_count < max_frames:
 
215
  logger.error(f"Pie chart creation failed: {str(e)}")
216
  return None, f"Error creating pie chart: {str(e)}"
217
 
218
+ # Generate PDF report
219
  def create_pdf_report(pie_path, screenshots, output_dir, category):
220
  logger.info(f"Creating PDF report for category: {category}")
221
  try:
 
223
  c = canvas.Canvas(pdf_path, pagesize=letter)
224
  width, height = letter
225
 
 
226
  c.setFont("Helvetica-Bold", 18)
227
  c.drawCentredString(width/2, height - 0.75*inch, f"AI Video Analysis Report - {category}")
228
  c.setFont("Helvetica", 12)
229
  c.drawString(1*inch, height - 1.25*inch, f"Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S IST')}")
230
 
231
+ c.drawString(1*inch, height - 1.75*inch, "Process: Video analyzed with best.pt, focusing on Toll Booths with 'Under Construction' indicators. 15 FPS, 20 screenshots.")
 
232
 
 
233
  c.setFont("Helvetica-Bold", 12)
234
  c.drawString(1*inch, height - 2.25*inch, "Processing Logs")
235
  c.setFont("Helvetica", 10)
 
242
  c.showPage()
243
  log_y = height - 1*inch
244
 
 
245
  c.showPage()
246
  if pie_path and os.path.exists(pie_path):
247
  c.drawImage(pie_path, 1*inch, height - 4.5*inch, width=4*inch, height=4*inch, preserveAspectRatio=True)
248
  else:
249
  c.drawString(1*inch, height - 4*inch, "No pie chart available")
250
 
 
251
  c.setFont("Helvetica-Bold", 12)
252
  c.drawString(5.5*inch, height - 4.5*inch, "Detected Objects")
253
  c.setFont("Helvetica", 10)
 
262
  c.showPage()
263
  table_y = height - 1*inch
264
 
 
265
  c.showPage()
266
  c.setFont("Helvetica-Bold", 12)
267
  c.drawString(1*inch, height - 0.75*inch, "Step-by-Step Screenshots")
 
329
  logger.error(f"Video comparison failed: {str(e)}")
330
  return None, f"Error comparing videos: {str(e)}"
331
 
332
+ # Main Gradio function
333
  def analyze_videos(video1, video2, category):
334
+ logger.info(f"Starting analysis at {datetime.now().strftime('%Y-%m-%d %H:%M:%S IST')} for category: {category}, Video1: {video1}, Video2: {video2}")
335
  try:
336
  if not video1:
337
  logger.error("No primary video provided")
 
341
  os.makedirs(output_dir, exist_ok=True)
342
  logger.info(f"Output directory created: {output_dir}")
343
 
 
344
  output_videos = []
345
  all_screenshots = []
346
  all_object_counts = {}
347
  errors = []
348
 
 
349
  if category == "All":
350
  categories = CATEGORIES.keys()
351
  else:
 
364
  errors.append(error)
365
  logger.error(error)
366
 
 
367
  comparison_df = None
368
  if video2 and category != "All":
369
  _, video2_counts, _, error = process_video(video2, category, output_dir)
 
376
  errors.append(comp_error)
377
  logger.error(comp_error)
378
 
 
379
  pdf_files = []
380
  output_files = []
381
  global object_counts
 
400
 
401
  output_files.extend(output_videos + all_screenshots)
402
 
 
403
  zip_path, zip_error = create_zip_file(output_files, output_dir)
404
  if zip_error:
405
  errors.append(zip_error)
 
412
  logger.error(f"Analysis failed: {str(e)}")
413
  return [], [], None, [], None, f"Error in analysis: {str(e)}"
414
 
415
+ # Custom CSS
416
  custom_css = """
417
  #video-gallery, .gallery {
418
  display: grid;