Rendre l'échelle de rugosité jointive entre tuiles

Le z-score par tuile et le vmax au percentile 98 par tuile donnaient une
échelle de couleur non jointive (écart-type variant de 0,05 a 0,58 m selon
la dalle). Références de normalisation figées (médianes mesurées sur 20
dalles réelles) et vmax fixe 3,8 (p98 médian) : même rugosité physique =
même couleur partout.
This commit is contained in:
Antoine Jacquin
2026-09-16 20:33:56 +02:00
parent 6780f2e25b
commit 8d29f03191
3 changed files with 20 additions and 9 deletions

View File

@ -137,7 +137,7 @@ VIZ_LEGENDS = {
},
'roughness': {
'title': 'Rugosité Multi-Échelle (3m + 15m)',
'legend': 'Irrégularité du terrain combinée fine + large\nViolet foncé = Surface lisse (route, mur, sol plat)\nJaune vif = Surface rugueuse (végétation, ruines, pierres)\nCombine rugosité fine 3m (70%) + large 15m (30%)',
'legend': 'Irrégularité du terrain combinée fine + large\nViolet foncé = Surface lisse (route, mur, sol plat)\nJaune vif = Surface rugueuse (végétation, ruines, pierres)\nCombine rugosité fine 3m (70%) + large 15m (30%)\nÉchelle physique commune à toutes les tuiles (références\nfigées mesurées sur dalles réelles) : mosaïque jointive,\nmême valeur = même couleur',
'description': 'Mesure la variabilité locale — surfaces anthropiques lisses vs naturelles rugueuses',
'cmap': 'plasma',
'gradient': ('#0d0887', '#4c02a1', '#7e03a8', '#aa2395', '#cc4778',

View File

@ -128,8 +128,10 @@ COLORMAPS = {
},
'roughness': {
'cmap': 'plasma',
# vmax fixe (p98 médian mesuré sur 20 dalles réelles) : un vmax au
# percentile par tuile rendait l'échelle non jointive entre tuiles.
'vmin_mode': 'fixed', 'vmin_val': 0,
'vmax_mode': 'percentile', 'vmax_pct': 98,
'vmax_mode': 'fixed', 'vmax_val': 3.8,
},
'wavelet': {
'cmap': 'inferno',

View File

@ -880,6 +880,15 @@ def _box_std_from_integral(Sx, Sx2, size):
return xp.sqrt(xp.maximum(mean_sq - mean * mean, 0))
# Références de normalisation de la rugosité (mètres d'écart-type local).
# Médianes inter-tuiles mesurées sur 20 dalles réelles à 0,2 m : la
# normalisation par tuile (z-score) rendait l'échelle non jointive — l'écart
# variait de 0,05 à 0,58 m selon la tuile pour l'échelle fine. References
# FIGÉES : même rugosité physique = même valeur sur toutes les tuiles.
ROUGHNESS_FINE_REF_M = 0.156
ROUGHNESS_BROAD_REF_M = 0.475
def generate_roughness(dem_file, basename, vis_dir, resolution, shared=None):
"""Surface roughness - multi-scale standard deviation (GPU-accelerated).
@ -889,6 +898,9 @@ def generate_roughness(dem_file, basename, vis_dir, resolution, shared=None):
deux échelles, extraction par 4 coins — coût constant quelle que soit
la fenêtre (un uniform_filter coûte proportionnellement à sa taille,
75 px à 0,2 m pour l'échelle large).
Normalisation par références FIXÉES (médianes mesurées) et non par
tuile : les mosaïques sont jointives, même valeur = même couleur.
"""
gpu_tag = " [GPU]" if _gpu_mod.HAS_GPU else ""
logger.info(f" → Rugosité de surface{gpu_tag}...")
@ -930,13 +942,10 @@ def generate_roughness(dem_file, basename, vis_dir, resolution, shared=None):
roughness_fine[nan_mask] = np.nan
roughness_broad[nan_mask] = np.nan
# Std normalization per scale then weighted combination
fine_valid = roughness_fine[~nan_mask]
broad_valid = roughness_broad[~nan_mask]
fine_std = max(np.nanstd(fine_valid), 0.01) if len(fine_valid) > 0 else 0.01
broad_std = max(np.nanstd(broad_valid), 0.01) if len(broad_valid) > 0 else 0.01
roughness = 0.7 * roughness_fine / fine_std + 0.3 * roughness_broad / broad_std
# Combinaison pondérée, échelle physique commune (références fixées :
# jointive entre tuiles — cf. constantes module)
roughness = (0.7 * roughness_fine / ROUGHNESS_FINE_REF_M
+ 0.3 * roughness_broad / ROUGHNESS_BROAD_REF_M)
roughness[nan_mask] = np.nan
_save_tif(output, roughness, transform, crs)