Spaces:
Running
on
Zero
Running
on
Zero
import threading | |
import cv2 | |
import numpy as np | |
from queue import Queue, Empty | |
from typing import Tuple | |
# TODO: | |
# currently, the following error is raised due to running cv2 not in the main thread: | |
# QObject::killTimer: Timers cannot be stopped from another thread | |
# QObject::~QObject: Timers cannot be stopped from another thread | |
class ImageViewer: | |
""" | |
Example usage: | |
viewer = ImageViewer(window_name="Test Viewer", refresh_rate=0.02) | |
while viewer.running: | |
image = np.random.randint(0, 255, (480, 640, 3), dtype=np.uint8) | |
viewer.update_image(image) | |
viewer.stop() | |
""" | |
def __init__(self, | |
window_size: Tuple[int, int] = (512, 512), | |
window_name: str = "Simulator Viewer", | |
refresh_rate: float = 0.02 | |
): | |
self.window_name = window_name | |
self.refresh_rate = refresh_rate | |
self.image_queue = Queue() | |
self.running = True | |
self.current_image = None | |
self.window_size = window_size | |
# Start the thread | |
self.viewer_thread = threading.Thread(target=self._run_viewer, daemon=True) | |
self.viewer_thread.start() | |
def _run_viewer(self): | |
cv2.namedWindow(self.window_name) | |
while self.running: | |
try: | |
# Get the latest image from the queue, with a small timeout to avoid blocking forever | |
self.current_image = self.image_queue.get(timeout=self.refresh_rate) | |
except Empty: | |
# If no new image is available, continue displaying the current image | |
pass | |
if self.current_image is not None: | |
# Resize image to fit window | |
self.current_image = cv2.resize(self.current_image, self.window_size) | |
cv2.imshow(self.window_name, self.current_image) | |
# Break the loop if 'q' is pressed | |
if cv2.waitKey(int(self.refresh_rate * 1000)) & 0xFF == ord('q'): | |
self.running = False | |
# Close window when done | |
cv2.destroyWindow(self.window_name) | |
def update_image(self, image: np.ndarray): | |
if not isinstance(image, np.ndarray): | |
raise ValueError("Image must be a numpy array.") | |
self.image_queue.put(image) | |
def stop(self): | |
self.running = False | |
self.viewer_thread.join() | |