Remove RRIM and Multi-Hillshade RGB, fix DTM resolution reuse bug, add --init to docker run
- Remove generate_rrim, generate_multi_hillshade, _compute_openness_both - Remove corresponding VIZ_STEPS entries, COLORMAPS, RGB_LEGENDS, and tests - Fix DTM resolution mismatch: existing DTM at different resolution is now regenerated instead of silently reused - Propagate actual DTM resolution to visualizations and rendering - Add --init to docker run commands for proper signal handling on Ctrl+C - Add .playwright-mcp/ to .gitignore Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@ -61,7 +61,7 @@ from .visualizations import (
|
||||
generate_lrm, generate_svf, generate_openness,
|
||||
generate_mslrm, generate_tpi, generate_sailore,
|
||||
generate_roughness, generate_anomalies, generate_wavelet,
|
||||
generate_flow, generate_rrim, generate_multi_hillshade, generate_local_dominance,
|
||||
generate_flow, generate_local_dominance,
|
||||
)
|
||||
from .gpu import gpu_cleanup
|
||||
from .ign import generate_ign_overlay
|
||||
@ -87,8 +87,6 @@ VIZ_STEPS = [
|
||||
('anomalies', generate_anomalies),
|
||||
('wavelet', generate_wavelet),
|
||||
('flow', generate_flow),
|
||||
('rrim', lambda d, b, v, r, shared=None: generate_rrim(d, b, v, r, shared=shared)),
|
||||
('multi_hillshade', lambda d, b, v, r, shared=None: generate_multi_hillshade(d, b, v, r, shared=shared)),
|
||||
('local_dominance', generate_local_dominance),
|
||||
('ortho', lambda d, b, v, r: generate_ign_overlay(
|
||||
d, b, v, r,
|
||||
@ -164,11 +162,14 @@ class LidarArchaeoPipeline:
|
||||
return False
|
||||
return True
|
||||
|
||||
def generate_all_visualizations(self, dtm_file, basename):
|
||||
def generate_all_visualizations(self, dtm_file, basename, resolution=None):
|
||||
"""Generate all archaeological visualizations for one DTM file.
|
||||
|
||||
Returns a dict of {name: tif_path} for successful generations.
|
||||
Args:
|
||||
resolution: Actual resolution from DTM geotransform. If None, uses self.resolution.
|
||||
"""
|
||||
if resolution is None:
|
||||
resolution = self.resolution
|
||||
logger.info(" Génération visualisations:")
|
||||
|
||||
# Create per-file subdirectory
|
||||
@ -178,7 +179,7 @@ class LidarArchaeoPipeline:
|
||||
# Pre-compute shared DEM data (gradient, NaN mask, LRM) once for all visualizations
|
||||
logger.info(" Pré-calcul données partagées (gradient, LRM)...")
|
||||
t_shared = time.time()
|
||||
shared = SharedDEM(dtm_file, self.resolution)
|
||||
shared = SharedDEM(dtm_file, resolution)
|
||||
logger.info(f" ✓ Données partagées prêtes ({time.time()-t_shared:.1f}s)")
|
||||
|
||||
vis_results = {}
|
||||
@ -225,9 +226,9 @@ class LidarArchaeoPipeline:
|
||||
try:
|
||||
# IGN overlays don't use SharedDEM (they download external data)
|
||||
if name in ('ortho', 'topo'):
|
||||
result = func(dtm_file, basename, file_vis_dir, self.resolution)
|
||||
result = func(dtm_file, basename, file_vis_dir, resolution)
|
||||
else:
|
||||
result = func(dtm_file, basename, file_vis_dir, self.resolution, shared=shared)
|
||||
result = func(dtm_file, basename, file_vis_dir, resolution, shared=shared)
|
||||
vis_results[name] = result
|
||||
elapsed = time.time() - t0
|
||||
if result:
|
||||
@ -250,7 +251,7 @@ class LidarArchaeoPipeline:
|
||||
}
|
||||
for name, tif_file in vis_results.items():
|
||||
if tif_file and isinstance(tif_file, Path) and tif_file.suffix == '.tif' and tif_file.exists():
|
||||
webp_file = tif_to_png(tif_file, file_vis_dir, self.resolution, keep_tif=self.keep_tif, source_info=source_info)
|
||||
webp_file = tif_to_png(tif_file, file_vis_dir, resolution, keep_tif=self.keep_tif, source_info=source_info)
|
||||
if webp_file:
|
||||
logger.info(f" ✓ {webp_file.name}")
|
||||
|
||||
@ -271,17 +272,30 @@ class LidarArchaeoPipeline:
|
||||
logger.info(f"FICHIER : {basename}")
|
||||
logger.info("=" * 60)
|
||||
|
||||
# Skip ground classification + DTM if DTM already exists
|
||||
# Skip ground classification + DTM if DTM already exists with matching resolution
|
||||
# --force only affects visualizations/PDF, not classification/DTM
|
||||
# Use --force-classification to force reclassification
|
||||
dtm_path = self.dtm_dir / f"{basename}_dtm.tif"
|
||||
if dtm_path.exists():
|
||||
logger.info("[1/5] Classification du sol — sautée (DTM existant)")
|
||||
logger.info("[2/5] Génération DTM — sautée (DTM existant)")
|
||||
dtm_file = dtm_path
|
||||
t_classif = 0
|
||||
t_dtm = 0
|
||||
else:
|
||||
# Check that existing DTM resolution matches requested resolution
|
||||
import rasterio
|
||||
try:
|
||||
with rasterio.open(dtm_path) as src:
|
||||
existing_res = abs(src.transform.a)
|
||||
if abs(existing_res - self.resolution) > 0.01:
|
||||
logger.info(f"[1/5] DTM existant à {existing_res}m/px — résolution demandée {self.resolution}m/px → régénération")
|
||||
dtm_path.unlink()
|
||||
else:
|
||||
logger.info(f"[1/5] Classification du sol — sautée (DTM existant à {existing_res}m/px)")
|
||||
logger.info("[2/5] Génération DTM — sautée (DTM existant)")
|
||||
dtm_file = dtm_path
|
||||
t_classif = 0
|
||||
t_dtm = 0
|
||||
except Exception:
|
||||
logger.warning(f"Impossible de lire le DTM existant — régénération")
|
||||
dtm_path.unlink()
|
||||
|
||||
if not dtm_path.exists():
|
||||
# Step 1: Ground classification
|
||||
logger.info("[1/5] Classification du sol...")
|
||||
t1 = time.time()
|
||||
@ -302,9 +316,13 @@ class LidarArchaeoPipeline:
|
||||
return False
|
||||
logger.info(f" ✓ DTM terminé ({t_dtm:.1f}s)")
|
||||
|
||||
# Step 3: Visualizations
|
||||
logger.info("[3/5] Visualisations archéologiques...")
|
||||
self.generate_all_visualizations(dtm_file, basename)
|
||||
# Step 3: Visualizations — use actual resolution from DTM
|
||||
import rasterio
|
||||
with rasterio.open(dtm_file) as src:
|
||||
actual_res = abs(src.transform.a)
|
||||
if abs(actual_res - self.resolution) > 0.01:
|
||||
logger.info(f" Résolution DTM: {actual_res}m/px (demandée: {self.resolution}m/px)")
|
||||
self.generate_all_visualizations(dtm_file, basename, actual_res)
|
||||
|
||||
# Step 4: PDF report
|
||||
t_pdf = 0
|
||||
@ -315,7 +333,7 @@ class LidarArchaeoPipeline:
|
||||
else:
|
||||
logger.info("[4/5] Rapport PDF A3...")
|
||||
t4 = time.time()
|
||||
generate_pdf_report(basename, file_vis_dir, self.pdf_dir, self.resolution)
|
||||
generate_pdf_report(basename, file_vis_dir, self.pdf_dir, actual_res)
|
||||
t_pdf = time.time() - t4
|
||||
logger.info(f" ✓ Rapport PDF terminé ({t_pdf:.1f}s)")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user