diff --git a/services/stream_connection_manager.py b/services/stream_connection_manager.py index cabbad7..b86cd18 100644 --- a/services/stream_connection_manager.py +++ b/services/stream_connection_manager.py @@ -222,7 +222,17 @@ class StreamConnection: # The frame in result["frame"] is preprocessed (resized, normalized) # We need the original frame for visualization frame_ref = result["metadata"].get("frame_ref") - frame_tensor = frame_ref.rgb_tensor if frame_ref else None + + # CRITICAL: Clone the frame tensor BEFORE freeing frame_ref + # The frame_ref will be freed at the end, so we need a copy + if frame_ref: + frame_tensor = frame_ref.rgb_tensor.clone() + logger.debug( + f"Cloned frame tensor for {self.stream_id}: {frame_tensor.shape}" + ) + else: + frame_tensor = None + logger.warning(f"No frame_ref in metadata for {self.stream_id}") # Create tracking result tracking_result = TrackingResult( @@ -231,7 +241,7 @@ class StreamConnection: tracked_objects=tracked_objects, detections=detections, frame_shape=result["metadata"].get("shape"), - frame_tensor=frame_tensor, # Original frame, not preprocessed + frame_tensor=frame_tensor, # Cloned original frame metadata=result["metadata"], ) diff --git a/test_tracking_realtime.py b/test_tracking_realtime.py index 8c0e58e..abedee5 100644 --- a/test_tracking_realtime.py +++ b/test_tracking_realtime.py @@ -109,6 +109,10 @@ def main_multi_stream(): start_time = time.time() stats_lock = threading.Lock() + # Buffer for latest frames (for display in main thread) + latest_frames = {} + frames_lock = threading.Lock() + # Create windows for each stream if display enabled if ENABLE_DISPLAY: for stream_id, _ in camera_urls: @@ -121,13 +125,6 @@ def main_multi_stream(): """Callback for tracking results - called automatically per stream""" nonlocal total_results - # Debug: Check if we have frame tensor - has_frame = result.frame_tensor is not None - frame_shape = result.frame_tensor.shape if has_frame else None - print( - f"[CALLBACK] Got result for {result.stream_id}, has_frame={has_frame}, shape={frame_shape}, detections={len(result.detections)}" - ) - with stats_lock: total_results += 1 stream_id = result.stream_id @@ -203,8 +200,9 @@ def main_multi_stream(): 2, ) - # Display - cv2.imshow(stream_id, frame_bgr) + # Store frame for display in main thread (OpenCV requires this) + with frames_lock: + latest_frames[stream_id] = frame_bgr # Connect all streams in parallel using threads print(f"\n[3/3] Connecting {len(camera_urls)} streams in parallel...") @@ -259,6 +257,11 @@ def main_multi_stream(): # Keep main thread alive and process OpenCV events while True: if ENABLE_DISPLAY: + # Display latest frames from all streams + with frames_lock: + for stream_id, frame_bgr in latest_frames.items(): + cv2.imshow(stream_id, frame_bgr) + # Process OpenCV events to keep windows responsive if cv2.waitKey(1) & 0xFF == ord("q"): break