hma / sim /viewer.py
LeroyWaa's picture
draft
246c106
raw
history blame
2.38 kB
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()