# display.py """ This module manages the display of images using OpenCV. It handles window creation, image updates, and mouse event callbacks. """ import cv2 import logging import numpy as np import config # Import the config module import queue # Import the queue module class DisplayManager: """ A class to manage the display of images using OpenCV. """ def __init__(self, app, sar_queue, mouse_queue, sar_x, sar_y, mfd_x, mfd_y): """ Initializes the DisplayManager. Args: app (App): The main application instance. sar_queue (queue.Queue): The queue for SAR images. mouse_queue (queue.Queue): The queue for mouse coordinates. sar_x (int): The x-coordinate of the SAR window. sar_y (int): The y-coordinate of the SAR window. mfd_x (int): The x-coordinate of the MFD window. mfd_y (int): The y-coordinate of the MFD window. """ self.app = app self.sar_queue = sar_queue self.mouse_queue = mouse_queue self.sar_x = sar_x self.sar_y = sar_y self.mfd_x = mfd_x self.mfd_y = mfd_y self.sar_window_initialized = False self.mfd_window_initialized = False self.sar_mouse_callback_set = False # Flag to track if the callback has been set self.last_mouse_update = 0 # Last time the mouse position was updated def show_mfd_image(self, image): """ Displays the MFD image in an OpenCV window. Args: image (numpy.ndarray): The MFD image to display. """ try: # Create and move window only once if not self.mfd_window_initialized: cv2.imshow("MFD", image) try: cv2.moveWindow("MFD", self.mfd_x, self.mfd_y) self.mfd_window_initialized = True except cv2.error as e: print(f"Error moving MFD window on initialization: {e}") logging.error(f"Error moving MFD window on initialization: {e}") else: cv2.imshow("MFD", image) # Just update the image except Exception as e: print(f"Error displaying MFD image: {e}") logging.exception(f"Error displaying MFD image: {e}") def show_sar_image(self, image): """ Displays the SAR image in an OpenCV window. Args: image (numpy.ndarray): The SAR image to display. """ if image is None or not isinstance(image, np.ndarray) or image.size == 0 or image.shape[0] == 0 or image.shape[1] == 0: print("Error: Invalid SAR image dimensions. Skipping display.") logging.error("Error: Invalid SAR image dimensions. Skipping display.") return # Skip try: # Create and move window only once if not self.sar_window_initialized: cv2.imshow("SAR", image) try: cv2.moveWindow("SAR", self.sar_x, self.sar_y) self.sar_window_initialized = True except cv2.error as e: print(f"Error moving SAR window on initialization: {e}") logging.error(f"Error moving SAR window on initialization: {e}") # Set mouse callback *after* the window is created cv2.setMouseCallback("SAR", self.sar_mouse_callback) self.sar_mouse_callback_set = True else: cv2.imshow("SAR", image) # Just update the image except Exception as e: print(f"Error displaying SAR image: {e}") logging.exception(f"Error displaying SAR image: {e}") def sar_mouse_callback(self, event, x, y, flags, param): """ Callback function for mouse events on the SAR window. Calculates the latitude and longitude based on the mouse coordinates and puts them in the queue. Args: event (int): The type of mouse event. x (int): The x-coordinate of the mouse pointer. y (int): The y-coordinate of the mouse pointer. flags (int): Any flags passed by the event. param (None): Any extra parameters passed by the event. """ if event == cv2.EVENT_MOUSEMOVE: # Convert pixel coordinates to normalized coordinates (0.0 - 1.0) normalized_x = x / self.app.sar_display_width normalized_y = y / self.app.sar_display_height # Convert normalized coordinates to kilometers from the center km_x = (normalized_x - 0.5) * config.SAR_IMAGE_SIZE_KM km_y = (0.5 - normalized_y) * config.SAR_IMAGE_SIZE_KM # Y axis is inverted # Convert kilometers to latitude and longitude offset lat_offset = km_y / 111.0 # Approximate km to latitude conversion lon_offset = km_x / (111.0 * np.cos(np.radians(config.SAR_CENTER_LAT))) # Approximate km to longitude # Calculate latitude and longitude latitude = config.SAR_CENTER_LAT + lat_offset longitude = config.SAR_CENTER_LON + lon_offset # Put the coordinates in the queue try: self.sar_queue.put((latitude, longitude), block=False) except queue.Full: pass # Drop value def process_sar_queue(self): """ This function get the new Sar image from queue and displays """ try: image = self.sar_queue.get(block=False) if isinstance(image, np.ndarray): self.show_sar_image(image) except queue.Empty: pass def process_mouse_queue(self): """Processes the mouse coordinate queue and updates the Tkinter label.""" try: latitude, longitude = self.mouse_queue.get(block=False) # Limit the update rate to 10 times per second (100 ms interval) current_time = time.time() if current_time - self.last_mouse_update >= 0.1: self.app.update_mouse_latlon_label(latitude, longitude) self.last_mouse_update = current_time except queue.Empty: pass