PrashanthB461 commited on
Commit
02b45d6
·
verified ·
1 Parent(s): a00ff02

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +44 -20
app.py CHANGED
@@ -42,8 +42,8 @@ FFMPEG_AVAILABLE = check_ffmpeg()
42
  class BYTETracker:
43
  def __init__(self, track_thresh=0.3, track_buffer=90, match_thresh=0.5, frame_rate=30):
44
  self.track_thresh = track_thresh
45
- self.track_buffer = track_buffer # Increased to 90 frames (3 seconds at 30 fps)
46
- self.match_thresh = match_thresh # Lowered to 0.5 for better matching
47
  self.frame_rate = frame_rate
48
  self.next_id = 1
49
  self.tracks = {}
@@ -63,7 +63,6 @@ class BYTETracker:
63
  best_iou = 0
64
  best_track_id = None
65
 
66
- # Try to match with existing tracks
67
  for track_id, track_info in self.tracks.items():
68
  if current_time - track_info['last_seen'] > self.track_buffer / self.frame_rate:
69
  continue
@@ -160,7 +159,7 @@ class BYTETracker:
160
  iou = intersection_area / (box1_area + box2_area - intersection_area)
161
  return iou
162
 
163
- def _is_same_worker(self, pos1, pos2, threshold=300): # Increased to 300 pixels
164
  x1, y1 = pos1
165
  x2, y2 = pos2
166
  distance = np.sqrt((x1 - x2)**2 + (y1 - y2)**2)
@@ -209,14 +208,15 @@ CONFIG = {
209
  "VIOLATION_COOLDOWN": 30.0,
210
  "WORKER_TRACKING_DURATION": 5.0,
211
  "MAX_PROCESSING_TIME": 60,
212
- "FRAME_SKIP": 1, # Reduced to 1 to process every frame
213
- "BATCH_SIZE": 8,
214
  "PARALLEL_WORKERS": max(1, cpu_count() - 1),
215
- "TRACK_BUFFER": 90, # Increased to 90
216
  "TRACK_THRESH": 0.3,
217
- "MATCH_THRESH": 0.5, # Lowered to 0.5
218
  "SNAPSHOT_QUALITY": 95,
219
- "MAX_WORKER_DISTANCE": 300 # Increased to 300
 
220
  }
221
 
222
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
@@ -235,6 +235,9 @@ def load_model():
235
  torch.hub.download_url_to_file('https://github.com/ultralytics/assets/releases/download/v8.3.0/yolov8n.pt', model_path)
236
 
237
  model = YOLO(model_path).to(device)
 
 
 
238
  logger.info(f"Model classes: {model.names}")
239
  return model
240
  except Exception as e:
@@ -245,6 +248,9 @@ model = load_model()
245
 
246
  # ========================== # Helper Functions # ==========================
247
  def preprocess_frame(frame):
 
 
 
248
  frame = cv2.convertScaleAbs(frame, alpha=1.2, beta=20)
249
  return frame
250
 
@@ -542,9 +548,8 @@ def process_video(video_data, temp_dir):
542
  frame_rate=fps
543
  )
544
 
545
- # Modified: Use a single worker ID since we know there's only one worker
546
- worker_id_mapping = {} # Map tracker IDs to a single worker ID
547
- unique_violations = {} # Keyed by violation type to ensure uniqueness
548
  snapshots = []
549
  start_time = time.time()
550
  frame_skip = CONFIG["FRAME_SKIP"]
@@ -579,17 +584,30 @@ def process_video(video_data, temp_dir):
579
  break
580
 
581
  try:
582
- results = model(batch_frames, device=device, conf=0.1, verbose=False)
 
 
 
 
 
 
583
  except Exception as e:
584
  logger.error(f"Model inference failed: {e}")
585
  raise ValueError(f"Failed to process video frames with YOLO model: {str(e)}")
 
 
 
 
 
586
 
587
  for i, (result, frame_idx) in enumerate(zip(results, batch_indices)):
588
  current_time = frame_idx / fps
589
 
590
- if time.time() - start_time > 1.0:
591
  progress = (processed_frames / total_frames) * 100
592
- yield f"Processing video... {progress:.1f}% complete (Frame {processed_frames}/{total_frames})", "", "", "", ""
 
 
593
  start_time = time.time()
594
 
595
  boxes = result.boxes
@@ -631,16 +649,13 @@ def process_video(video_data, temp_dir):
631
  if label is None:
632
  continue
633
 
634
- # Map all tracker IDs to a single worker ID (since we know there's only one worker)
635
  if not worker_id_mapping:
636
- worker_id_mapping[tracker_id] = 1 # First worker ID is 1
637
  else:
638
- # Map all subsequent tracker IDs to the same worker ID
639
  worker_id_mapping[tracker_id] = worker_id_mapping[list(worker_id_mapping.keys())[0]]
640
 
641
  worker_id = worker_id_mapping[tracker_id]
642
 
643
- # Use violation type as key to ensure uniqueness per worker
644
  violation_key = (worker_id, label)
645
 
646
  if violation_key not in unique_violations:
@@ -654,7 +669,8 @@ def process_video(video_data, temp_dir):
654
  "timestamp": current_time
655
  }
656
 
657
- snapshot_frame = batch_frames[i].copy()
 
658
  snapshot_frame = draw_detections(snapshot_frame, [detection])
659
 
660
  cv2.putText(
@@ -687,6 +703,10 @@ def process_video(video_data, temp_dir):
687
 
688
  logger.info(f"Captured snapshot for {label} violation by worker {worker_id} at {current_time:.2f}s")
689
 
 
 
 
 
690
  cap.release()
691
  processing_time = time.time() - start_time
692
  logger.info(f"Processing complete in {processing_time:.2f}s")
@@ -764,6 +784,8 @@ def process_video(video_data, temp_dir):
764
  logger.info(f"Cleaned up temporary video file: {video_path}")
765
  except Exception as e:
766
  logger.error(f"Failed to clean up temporary video file {video_path}: {e}")
 
 
767
 
768
  def gradio_interface(video_file):
769
  temp_dir = None
@@ -808,6 +830,8 @@ def gradio_interface(video_file):
808
  if temp_dir and os.path.exists(temp_dir):
809
  shutil.rmtree(temp_dir, ignore_errors=True)
810
  logger.info(f"Cleaned up temporary directory: {temp_dir}")
 
 
811
 
812
  # ========================== # Gradio Interface # ==========================
813
  interface = gr.Interface(
 
42
  class BYTETracker:
43
  def __init__(self, track_thresh=0.3, track_buffer=90, match_thresh=0.5, frame_rate=30):
44
  self.track_thresh = track_thresh
45
+ self.track_buffer = track_buffer
46
+ self.match_thresh = match_thresh
47
  self.frame_rate = frame_rate
48
  self.next_id = 1
49
  self.tracks = {}
 
63
  best_iou = 0
64
  best_track_id = None
65
 
 
66
  for track_id, track_info in self.tracks.items():
67
  if current_time - track_info['last_seen'] > self.track_buffer / self.frame_rate:
68
  continue
 
159
  iou = intersection_area / (box1_area + box2_area - intersection_area)
160
  return iou
161
 
162
+ def _is_same_worker(self, pos1, pos2, threshold=300):
163
  x1, y1 = pos1
164
  x2, y2 = pos2
165
  distance = np.sqrt((x1 - x2)**2 + (y1 - y2)**2)
 
208
  "VIOLATION_COOLDOWN": 30.0,
209
  "WORKER_TRACKING_DURATION": 5.0,
210
  "MAX_PROCESSING_TIME": 60,
211
+ "FRAME_SKIP": 1,
212
+ "BATCH_SIZE": 4, # Reduced to 4 to lower memory usage
213
  "PARALLEL_WORKERS": max(1, cpu_count() - 1),
214
+ "TRACK_BUFFER": 90,
215
  "TRACK_THRESH": 0.3,
216
+ "MATCH_THRESH": 0.5,
217
  "SNAPSHOT_QUALITY": 95,
218
+ "MAX_WORKER_DISTANCE": 300,
219
+ "TARGET_RESOLUTION": (640, 360) # Added to resize frames
220
  }
221
 
222
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
 
235
  torch.hub.download_url_to_file('https://github.com/ultralytics/assets/releases/download/v8.3.0/yolov8n.pt', model_path)
236
 
237
  model = YOLO(model_path).to(device)
238
+ # Enable FP16 inference if on GPU
239
+ if device.type == "cuda":
240
+ model.model.half()
241
  logger.info(f"Model classes: {model.names}")
242
  return model
243
  except Exception as e:
 
248
 
249
  # ========================== # Helper Functions # ==========================
250
  def preprocess_frame(frame):
251
+ # Resize frame to target resolution
252
+ target_res = CONFIG["TARGET_RESOLUTION"]
253
+ frame = cv2.resize(frame, target_res, interpolation=cv2.INTER_LINEAR)
254
  frame = cv2.convertScaleAbs(frame, alpha=1.2, beta=20)
255
  return frame
256
 
 
548
  frame_rate=fps
549
  )
550
 
551
+ worker_id_mapping = {}
552
+ unique_violations = {}
 
553
  snapshots = []
554
  start_time = time.time()
555
  frame_skip = CONFIG["FRAME_SKIP"]
 
584
  break
585
 
586
  try:
587
+ # Convert frames to tensor and move to device
588
+ batch_frames_tensor = [torch.from_numpy(frame).permute(2, 0, 1).float() / 255.0 for frame in batch_frames]
589
+ batch_frames_tensor = torch.stack(batch_frames_tensor).to(device)
590
+ if device.type == "cuda":
591
+ batch_frames_tensor = batch_frames_tensor.half()
592
+
593
+ results = model(batch_frames_tensor, device=device, conf=0.1, verbose=False)
594
  except Exception as e:
595
  logger.error(f"Model inference failed: {e}")
596
  raise ValueError(f"Failed to process video frames with YOLO model: {str(e)}")
597
+ finally:
598
+ # Clear memory
599
+ batch_frames = [] # Clear the list to free memory
600
+ if device.type == "cuda":
601
+ torch.cuda.empty_cache()
602
 
603
  for i, (result, frame_idx) in enumerate(zip(results, batch_indices)):
604
  current_time = frame_idx / fps
605
 
606
+ if time.time() - start_time > 0.5: # Yield more frequently
607
  progress = (processed_frames / total_frames) * 100
608
+ elapsed_time = time.time() - start_time
609
+ fps_processed = processed_frames / elapsed_time if elapsed_time > 0 else 0
610
+ yield f"Processing video... {progress:.1f}% complete (Frame {processed_frames}/{total_frames}, {fps_processed:.1f} FPS)", "", "", "", ""
611
  start_time = time.time()
612
 
613
  boxes = result.boxes
 
649
  if label is None:
650
  continue
651
 
 
652
  if not worker_id_mapping:
653
+ worker_id_mapping[tracker_id] = 1
654
  else:
 
655
  worker_id_mapping[tracker_id] = worker_id_mapping[list(worker_id_mapping.keys())[0]]
656
 
657
  worker_id = worker_id_mapping[tracker_id]
658
 
 
659
  violation_key = (worker_id, label)
660
 
661
  if violation_key not in unique_violations:
 
669
  "timestamp": current_time
670
  }
671
 
672
+ snapshot_frame = batch_frames_tensor[i].cpu().numpy().transpose(1, 2, 0) * 255
673
+ snapshot_frame = snapshot_frame.astype(np.uint8)
674
  snapshot_frame = draw_detections(snapshot_frame, [detection])
675
 
676
  cv2.putText(
 
703
 
704
  logger.info(f"Captured snapshot for {label} violation by worker {worker_id} at {current_time:.2f}s")
705
 
706
+ # Clear snapshots periodically to reduce memory usage
707
+ if len(snapshots) > 100:
708
+ snapshots = snapshots[-10:] # Keep only the last 10 snapshots in memory
709
+
710
  cap.release()
711
  processing_time = time.time() - start_time
712
  logger.info(f"Processing complete in {processing_time:.2f}s")
 
784
  logger.info(f"Cleaned up temporary video file: {video_path}")
785
  except Exception as e:
786
  logger.error(f"Failed to clean up temporary video file {video_path}: {e}")
787
+ if device.type == "cuda":
788
+ torch.cuda.empty_cache()
789
 
790
  def gradio_interface(video_file):
791
  temp_dir = None
 
830
  if temp_dir and os.path.exists(temp_dir):
831
  shutil.rmtree(temp_dir, ignore_errors=True)
832
  logger.info(f"Cleaned up temporary directory: {temp_dir}")
833
+ if device.type == "cuda":
834
+ torch.cuda.empty_cache()
835
 
836
  # ========================== # Gradio Interface # ==========================
837
  interface = gr.Interface(