Audit: corrections de bugs identifiés

- rendering.py: colorbar cassée quand NaN mask actif — créer un
  ScalarMappable avec le cmap sauvegardé au lieu de rely sur
  l'image RGBA qui n'a plus de cmap
- rendering.py: nettoyage du PNG temporaire avec try/finally et
  missing_ok=True pour éviter les fichiers orphelins
- gpu.py: to_gpu() convertit en float32 au lieu de float64 pour
  réduire la consommation mémoire GPU
- dtm.py: utiliser _file_basename() de pipeline.py au lieu de
  dupliquer la logique d'extraction du basename
- pipeline.py: docstring corrigé (18 visualisations, pas 19)
- cli.py: --file supporte aussi les noms sans .copc
  (recherche .copc.laz et .copc.las en plus de .laz et .las)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jacquin Antoine
2026-05-10 12:11:13 +02:00
parent 47c20a319a
commit e31d3f0e2b
5 changed files with 37 additions and 20 deletions

View File

@ -345,13 +345,19 @@ def tif_to_png(tif_file, vis_dir, resolution):
has_nan_mask = nan_mask is not None and not is_rgb_result
if has_nan_mask:
# data is normalized 0-1 from _apply_colormap; apply cmap to get RGBA
cmap_obj = plt.get_cmap(cmap) if isinstance(cmap, str) else cmap
rgba = cmap_obj(data) # (H, W, 4) float RGBA
# Save the colormap for colorbar before converting to RGBA
saved_cmap = plt.get_cmap(cmap) if isinstance(cmap, str) else cmap
saved_vmin = float(np.nanmin(data)) if not nan_mask.all() else 0
saved_vmax = float(np.nanmax(data)) if not nan_mask.all() else 1
rgba = saved_cmap(data) # (H, W, 4) float RGBA
rgba[nan_mask, 3] = 0.0 # transparent where no data
data = rgba
is_rgba = True
else:
is_rgba = False
saved_cmap = None
saved_vmin = None
saved_vmax = None
# Create figure — adapt width to data resolution for sharp rendering
# At high res (5000+px wide), we need a larger figure to avoid downsampling artifacts
@ -375,7 +381,14 @@ def tif_to_png(tif_file, vis_dir, resolution):
ax.set_title(f"{title}\n{description}", fontsize=15, fontweight='bold', pad=10)
if not is_rgb:
cbar = plt.colorbar(im, ax=ax, pad=0.02, shrink=0.85, aspect=30)
if is_rgba and saved_cmap is not None:
# Create a ScalarMappable for the colorbar from the saved colormap
sm = plt.cm.ScalarMappable(cmap=saved_cmap,
norm=plt.Normalize(vmin=saved_vmin, vmax=saved_vmax))
sm.set_array([])
cbar = plt.colorbar(sm, ax=ax, pad=0.02, shrink=0.85, aspect=30)
else:
cbar = plt.colorbar(im, ax=ax, pad=0.02, shrink=0.85, aspect=30)
cbar.ax.tick_params(labelsize=9, width=1.5)
cbar.outline.set_linewidth(1.5)
cbar.set_label(legend_label, fontsize=10, fontweight='bold')
@ -486,16 +499,18 @@ def tif_to_png(tif_file, vis_dir, resolution):
# Save as PNG then convert to WebP — use higher DPI for large data
save_dpi = 200 if width > 3000 else 150
png_temp = vis_dir / f"{tif_file.stem}_temp.png"
plt.savefig(png_temp, dpi=save_dpi, bbox_inches='tight', pad_inches=0.15,
facecolor='white', format='png')
plt.close()
try:
plt.savefig(png_temp, dpi=save_dpi, bbox_inches='tight', pad_inches=0.15,
facecolor='white', format='png')
finally:
plt.close()
img = PILImage.open(str(png_temp))
img.save(str(webp_file), format='WEBP', lossless=True)
png_temp.unlink()
png_temp.unlink(missing_ok=True)
# Delete source TIFF
tif_file.unlink()
tif_file.unlink(missing_ok=True)
return webp_file