199 lines
5.9 KiB
Python
199 lines
5.9 KiB
Python
# visualizer.py
|
|
|
|
import logging
|
|
import os
|
|
from typing import Optional, Union
|
|
|
|
# Rimuovi import cv2 se non serve più ad altro
|
|
# try:
|
|
# import cv2
|
|
# import numpy as np # OpenCV richiede numpy
|
|
# OPENCV_AVAILABLE = True
|
|
# except ImportError:
|
|
# OPENCV_AVAILABLE = False
|
|
# class np: pass
|
|
# logging.warning("OpenCV (cv2) or NumPy not found. OpenCV visualization disabled.")
|
|
|
|
try:
|
|
import matplotlib.pyplot as plt
|
|
from mpl_toolkits.mplot3d import Axes3D # Per 3D
|
|
import numpy as np # Matplotlib richiede numpy
|
|
|
|
MATPLOTLIB_AVAILABLE = True
|
|
except ImportError:
|
|
MATPLOTLIB_AVAILABLE = False
|
|
|
|
class np:
|
|
pass
|
|
|
|
class plt: # Dummy class
|
|
def figure(self, figsize):
|
|
return self
|
|
|
|
def add_subplot(self, *args, **kwargs):
|
|
return self
|
|
|
|
def plot_surface(self, *args, **kwargs):
|
|
return self
|
|
|
|
def set_xlabel(self, *args):
|
|
pass
|
|
|
|
def set_ylabel(self, *args):
|
|
pass
|
|
|
|
def set_zlabel(self, *args):
|
|
pass
|
|
|
|
def set_title(self, *args):
|
|
pass
|
|
|
|
def set_zlim(self, *args):
|
|
pass
|
|
|
|
def colorbar(self, *args, **kwargs):
|
|
pass
|
|
|
|
def show(self):
|
|
pass
|
|
|
|
def subplots(self):
|
|
return self, self # Dummy fig, ax
|
|
|
|
def imshow(self, *args):
|
|
pass
|
|
|
|
def axis(self, *args):
|
|
pass
|
|
|
|
logging.warning("Matplotlib not found. 2D/3D plot visualization will be disabled.")
|
|
|
|
try:
|
|
from PIL import Image
|
|
|
|
PIL_AVAILABLE_VIS = True
|
|
except ImportError:
|
|
PIL_AVAILABLE_VIS = False
|
|
|
|
class Image:
|
|
pass # Dummy
|
|
|
|
|
|
# === RIMOSSA: show_image_cv2 ===
|
|
|
|
|
|
# === NUOVA FUNZIONE: show_image_matplotlib ===
|
|
def show_image_matplotlib(
|
|
image_source: Union[str, np.ndarray, Image.Image], title: str = "Image Preview"
|
|
):
|
|
"""
|
|
Displays an image (from path, NumPy array, or PIL Image) in a separate
|
|
Matplotlib window with interactive zoom/pan.
|
|
Requires Matplotlib and NumPy. PIL is needed if input is PIL Image or path.
|
|
"""
|
|
if not MATPLOTLIB_AVAILABLE:
|
|
logging.error("Cannot display image: Matplotlib not available.")
|
|
return
|
|
if not PIL_AVAILABLE_VIS and isinstance(image_source, (str, Image.Image)):
|
|
logging.error(
|
|
"Cannot display image: Pillow (PIL) not available for loading/conversion."
|
|
)
|
|
return
|
|
|
|
img_display_np = None
|
|
try:
|
|
if isinstance(image_source, str): # Path
|
|
if not os.path.exists(image_source):
|
|
logging.error(
|
|
f"Matplotlib display: Image path not found: {image_source}"
|
|
)
|
|
return
|
|
with Image.open(image_source) as img_pil:
|
|
# Converti in NumPy array (Matplotlib preferisce NumPy)
|
|
img_display_np = np.array(img_pil)
|
|
elif isinstance(image_source, np.ndarray): # NumPy array
|
|
img_display_np = (
|
|
image_source.copy()
|
|
) # Usa direttamente (o copia per sicurezza)
|
|
elif PIL_AVAILABLE_VIS and isinstance(image_source, Image.Image): # PIL Image
|
|
img_display_np = np.array(image_source)
|
|
else:
|
|
logging.error(
|
|
f"Matplotlib display: Unsupported image source type: {type(image_source)}"
|
|
)
|
|
return
|
|
|
|
if img_display_np is None:
|
|
logging.error("Failed to load or convert image to NumPy array.")
|
|
return
|
|
|
|
# Crea figura e asse
|
|
fig, ax = plt.subplots(figsize=(8, 8)) # Puoi aggiustare figsize
|
|
ax.imshow(img_display_np)
|
|
|
|
# Abbellimenti opzionali
|
|
ax.set_title(title)
|
|
ax.axis("off") # Nasconde assi numerici e tick
|
|
|
|
# Mostra la finestra interattiva (BLOCCANTE)
|
|
# La GUI chiamante deve gestire l'esecuzione in un thread.
|
|
plt.show()
|
|
|
|
except Exception as e:
|
|
logging.error(
|
|
f"Error displaying image with Matplotlib ('{title}'): {e}", exc_info=True
|
|
)
|
|
|
|
|
|
# === Funzione show_3d_matplotlib rimane invariata ===
|
|
def show_3d_matplotlib(
|
|
hgt_array: Optional[np.ndarray],
|
|
title: str = "3D Elevation View",
|
|
subsample: int = 5,
|
|
):
|
|
"""Displays HGT data as a 3D surface plot using Matplotlib."""
|
|
if not MATPLOTLIB_AVAILABLE:
|
|
logging.error("Cannot display 3D plot: Matplotlib not available.")
|
|
return
|
|
if hgt_array is None or hgt_array.size == 0:
|
|
logging.error("Cannot display 3D view: Input data array is None or empty.")
|
|
return
|
|
|
|
try:
|
|
# ... (implementazione 3D come prima) ...
|
|
logging.info(
|
|
f"Generating 3D plot for data shape: {hgt_array.shape} with subsampling={subsample}"
|
|
)
|
|
rows, cols = hgt_array.shape
|
|
x = np.arange(0, cols, subsample)
|
|
y = np.arange(0, rows, subsample)
|
|
X, Y = np.meshgrid(x, y)
|
|
Z = hgt_array[::subsample, ::subsample].astype(float)
|
|
common_nodata = -32768
|
|
Z[Z == common_nodata] = np.nan
|
|
fig = plt.figure(figsize=(10, 7))
|
|
ax = fig.add_subplot(111, projection="3d")
|
|
z_min, z_max = np.nanmin(Z), np.nanmax(Z)
|
|
if np.isnan(z_min) or np.isnan(z_max):
|
|
z_min, z_max = 0, 100 # Fallback
|
|
surf = ax.plot_surface(
|
|
X,
|
|
Y,
|
|
Z,
|
|
cmap="terrain",
|
|
linewidth=0,
|
|
antialiased=False,
|
|
vmin=z_min,
|
|
vmax=z_max,
|
|
)
|
|
ax.set_xlabel("Pixel Col Index (Subsampled)")
|
|
ax.set_ylabel("Pixel Row Index (Subsampled)")
|
|
ax.set_zlabel("Elevation (m)")
|
|
ax.set_title(title)
|
|
ax.set_zlim(z_min - (z_max - z_min) * 0.1, z_max + (z_max - z_min) * 0.1)
|
|
fig.colorbar(surf, shrink=0.6, aspect=10, label="Elevation (m)")
|
|
plt.show() # BLOCCANTE
|
|
|
|
except Exception as e:
|
|
logging.error(f"Error generating 3D plot ('{title}'): {e}", exc_info=True)
|