correct dim for sar window, auto delete older kml files

This commit is contained in:
VALLONGOL 2025-04-09 10:09:12 +02:00
parent d367985d26
commit 713c761521
4 changed files with 137 additions and 21 deletions

12
app.py
View File

@ -20,6 +20,7 @@ import sys
import socket # Required for network setup
from typing import Optional, Tuple, Any, Dict, TYPE_CHECKING
import datetime
import cv2
# --- Third-party imports ---
import tkinter as tk
@ -60,6 +61,7 @@ from utils import (
decimal_to_dms,
generate_sar_kml,
launch_google_earth,
cleanup_old_kml_files
)
from network import create_udp_socket, close_udp_socket
from receiver import UdpReceiver
@ -1390,9 +1392,17 @@ class App:
) # Passa geo_info
if kml_success:
logging.info(
logging.debug(
f"{kml_log_prefix} KML file generated successfully: {kml_output_path}"
)
logging.debug(f"{kml_log_prefix} Calling KML cleanup utility...")
try:
cleanup_old_kml_files(config.KML_OUTPUT_DIRECTORY, config.MAX_KML_FILES)
except Exception as cleanup_e:
# Log error during cleanup but don't stop subsequent actions (like GE launch)
logging.exception(f"{kml_log_prefix} Error during KML cleanup call:")
# Lancia Google Earth se richiesto
if config.AUTO_LAUNCH_GOOGLE_EARTH:
logging.debug(

View File

@ -180,5 +180,11 @@ AUTO_LAUNCH_GOOGLE_EARTH = False # Imposta a True per tentare di aprire automat
# Opzionale: potresti aggiungere un percorso esplicito all'eseguibile di Google Earth se non è nel PATH
# GOOGLE_EARTH_EXECUTABLE_PATH = "C:/Program Files/Google/Google Earth Pro/client/googleearth.exe" # Esempio Windows
# Maximum number of KML files to keep in the output directory.
# Older files will be deleted when a new one is created if the count exceeds this limit.
# Set to 0 or less to disable cleanup.
MAX_KML_FILES = 50
# --- END OF FILE config.py ---

View File

@ -194,40 +194,68 @@ class ImagePipeline:
if not self._app_state.shutting_down:
logging.exception(f"{log_prefix} Error during SAR processing pipeline:")
# Only the modified function _rotate_image is sent.
# The process_sar_for_display function does not need changes for this specific request,
# as it will receive the potentially larger image from the modified _rotate_image
# and pass it correctly to _resize_sar_image.
# Function to be modified: _rotate_image
def _rotate_image(self, img: np.ndarray, angle_rad: float) -> Optional[np.ndarray]:
"""
Helper method to rotate an image using OpenCV.
Helper method to rotate an image using OpenCV, ensuring the entire
rotated image is contained within the output canvas by resizing the canvas
and adding borders as necessary.
Args:
img (np.ndarray): Input image.
img (np.ndarray): Input image (can be grayscale or BGR).
angle_rad (float): Rotation angle in radians.
Returns:
Optional[np.ndarray]: The rotated image, or None on critical error.
Optional[np.ndarray]: The rotated image within an expanded canvas,
or None on critical error.
"""
log_prefix = f"{self._log_prefix} SAR Rotate Helper"
try:
deg = math.degrees(angle_rad)
# 1. Get image dimensions and center
h, w = img.shape[:2]
center = (w // 2, h // 2)
# Get rotation matrix
M = cv2.getRotationMatrix2D(center, deg, 1.0)
# Determine border color (black for BGR, 0 for grayscale)
center_x, center_y = w // 2, h // 2
# 2. Calculate rotation matrix for the original center
deg = math.degrees(angle_rad)
M = cv2.getRotationMatrix2D((center_x, center_y), deg, 1.0)
# 3. Calculate the new bounding box dimensions
cos = np.abs(M[0, 0])
sin = np.abs(M[0, 1])
new_w = int((h * sin) + (w * cos))
new_h = int((h * cos) + (w * sin))
logging.debug(f"{log_prefix} Original dims ({w}x{h}), Rotated BBox dims ({new_w}x{new_h}) for angle {deg:.2f} deg.")
# 4. Adjust the rotation matrix to account for translation
# The matrix needs to shift the image center to the center of the new, larger canvas.
M[0, 2] += (new_w / 2) - center_x
M[1, 2] += (new_h / 2) - center_y
logging.debug(f"{log_prefix} Rotation matrix adjusted for translation.")
# 5. Determine border color (black)
border_color = [0, 0, 0] if img.ndim == 3 else 0
# Perform affine warp
# 6. Perform the affine transformation on the larger canvas
rotated_img = cv2.warpAffine(
img,
M,
(w, h), # Output size same as input
flags=cv2.INTER_LINEAR, # Linear interpolation
(new_w, new_h), # Use the new bounding box dimensions
flags=cv2.INTER_LINEAR,
borderMode=cv2.BORDER_CONSTANT,
borderValue=border_color, # Fill borders with black
borderValue=border_color # Fill borders with black
)
logging.debug(f"{log_prefix} Rotation successful.")
logging.debug(f"{log_prefix} Rotation and warpAffine successful. Output shape: {rotated_img.shape}")
return rotated_img
except Exception as e:
# Log error and return None to indicate failure
logging.exception(f"{log_prefix} Rotation warpAffine error:")
logging.exception(f"{log_prefix} Rotation/warpAffine error:")
return None
def _resize_sar_image(

View File

@ -13,11 +13,12 @@ Uses standardized logging prefixes. Drop counts are now managed within AppState.
import queue
import logging
import math
import os # Aggiunto
import datetime # Aggiunto per timestamp
import sys # Aggiunto per platform check
import subprocess # Aggiunto per lanciare processi
import shutil # Aggiunto per trovare eseguibili (opzionale)
import os
import datetime
import sys
import subprocess
import shutil
from pathlib import Path
# Importa le librerie KML e GEO, gestendo l'ImportError
try:
@ -377,7 +378,7 @@ def generate_sar_kml(geo_info_radians, output_path) -> bool:
# Salva il file KML
logging.debug(f"{log_prefix} Saving KML to: {output_path}")
kml.save(output_path)
logging.info(f"{log_prefix} KML file saved successfully: {output_path}")
logging.debug(f"{log_prefix} KML file saved successfully: {output_path}")
return True
except Exception as e:
@ -436,5 +437,76 @@ def launch_google_earth(kml_path):
except Exception as e:
logging.exception(f"{log_prefix} Unexpected error launching Google Earth:")
def cleanup_old_kml_files(kml_directory: str, max_files_to_keep: int):
"""
Removes the oldest KML files from the specified directory if the total number
of KML files exceeds max_files_to_keep.
Args:
kml_directory (str): The path to the directory containing KML files.
max_files_to_keep (int): The maximum number of KML files to retain.
If 0 or less, cleanup is disabled.
"""
log_prefix = "[Utils KML Cleanup]"
if max_files_to_keep <= 0:
logging.debug(f"{log_prefix} KML cleanup disabled (max_files_to_keep={max_files_to_keep}).")
return
logging.debug(f"{log_prefix} Checking directory '{kml_directory}' for KML files older than the newest {max_files_to_keep}.")
try:
kml_dir_path = Path(kml_directory)
if not kml_dir_path.is_dir():
logging.warning(f"{log_prefix} Directory '{kml_directory}' not found. Cannot perform cleanup.")
return
# 1. List all .kml files with their modification times
kml_files = []
for item in kml_dir_path.glob('*.kml'):
if item.is_file():
try:
# Get modification time
mtime = item.stat().st_mtime
kml_files.append((item, mtime))
except OSError as stat_err:
logging.warning(f"{log_prefix} Could not get modification time for '{item.name}': {stat_err}")
except Exception as stat_e:
logging.exception(f"{log_prefix} Unexpected error getting stat for '{item.name}':")
# 2. Check if cleanup is needed
current_file_count = len(kml_files)
logging.debug(f"{log_prefix} Found {current_file_count} KML files. Max allowed: {max_files_to_keep}.")
if current_file_count <= max_files_to_keep:
logging.debug(f"{log_prefix} File count is within limit. No cleanup needed.")
return
# 3. Sort files by modification time (oldest first)
kml_files.sort(key=lambda x: x[1]) # Sort by the second element (mtime)
# 4. Determine files to delete
num_to_delete = current_file_count - max_files_to_keep
files_to_delete = kml_files[:num_to_delete] # Get the oldest ones
logging.debug(f"{log_prefix} Need to delete {num_to_delete} oldest KML files.")
# 5. Delete the oldest files
deleted_count = 0
for file_path, _ in files_to_delete:
try:
file_path.unlink() # Use unlink() for Path objects (equivalent to os.remove)
logging.debug(f"{log_prefix} Deleted old KML file: {file_path.name}")
deleted_count += 1
except OSError as delete_err:
logging.error(f"{log_prefix} Failed to delete file '{file_path.name}': {delete_err}")
except Exception as delete_e:
logging.exception(f"{log_prefix} Unexpected error deleting file '{file_path.name}':")
logging.debug(f"{log_prefix} Cleanup finished. Deleted {deleted_count}/{num_to_delete} files.")
except Exception as e:
logging.exception(f"{log_prefix} Error during KML cleanup process:")
# --- END OF FILE utils.py ---