Tutoriel 2 : visualisation et options avancées#
Ce tutoriel prolonge le tutoriel 1 avec un peu de visualisation et une démonstration du comportement de quelques options importantes de la CLI.
Ce tutoriel suppose que vous avez installé floodsr comme indiqué dans Tutorial 1 et que vous êtes à l’aise avec les notebooks Python simples. Si vous n’avez jamais utilisé de notebook Jupyter, nous vous recommandons de consulter les notebooks d’introduction du projet Jupyter pour vous familiariser avec l’interface et les fonctionnalités de base.
Il existe trois façons courantes d’exécuter ce tutoriel (autrement dit, trois contextes d’exécution) :
ligne de commande (CLI) : copiez-collez les commandes ci-dessous depuis votre navigateur vers votre terminal. NOTE : dans la plupart des terminaux, il faudra retirer le préfixe
!de chaque commande.carnet local (Jupyter) : utilisez le bouton pour enregistrer ce carnet comme fichier
.ipynbsur votre machine (il faut parfois cliquer sur enregistrer sous), puis ouvrez-le avec votre noyau Jupyter local. Voir Carnet local (Jupyter) pour plus de détails.carnet hébergé (Colab) : utilisez le bouton pour ouvrir ce tutoriel dans Google Colab.
Installer des paquets supplémentaires#
Pour ce tutoriel, nous avons besoin des paquets Python supplémentaires matplotlib et rasterio. Comme pour l’installation de floodsr montrée dans le tutoriel 1, la façon d’obtenir et d’utiliser ces paquets dépend de votre contexte d’exécution :
Les étapes d’installation adaptées dépendent de votre contexte d’exécution, décrit en détail dans Installation de base. Voici le minimum à faire dans chaque cas :
ligne de commande (CLI) : commencez par vérifier que
pipxest installé et disponible dans le PATH, puis exécutezpipx install floodsr. Voir Ligne de commande (CLI) pour plus de détails.carnet local (Jupyter) : même chose. Ensuite, soit vous suivez les étapes supplémentaires de Carnet local (Jupyter) pour configurer proprement votre environnement, soit vous faites au plus simple et vous décommentez la cellule Jupyter ci-dessous avant de l’exécuter.
carnet hébergé (Colab) : décommentez la cellule Colab ci-dessous et exécutez-la. Voir Carnet hébergé (Colab) pour les détails.
# %pip install -q matplotlib rasterio
Vérifier l’installation#
Vérifions maintenant les versions :
import matplotlib
import rasterio
print(f"matplotlib=={matplotlib.__version__}")
print(f"rasterio=={rasterio.__version__}")
matplotlib==3.10.8
rasterio==1.5.0
!floodsr --version
Importations#
Ici, nous importons nos outils et créons une petite fonction d’aide pour lire les données raster
from pathlib import Path
from urllib.request import urlretrieve
import matplotlib.pyplot as plt
import numpy as np
from rasterio.warp import Resampling, calculate_default_transform, reproject
Télécharger les mêmes données de test que dans le tutoriel 1#
Si vous avez déjà téléchargé ces fichiers en suivant le tutoriel 1, vous pouvez passer cette étape.
urlretrieve(
"https://github.com/cefect/floodsr/releases/download/v0.0.3/hires002_dem.tif",
"hires002_dem.tif",
)
urlretrieve(
"https://github.com/cefect/floodsr/releases/download/v0.0.3/lowres032.tif",
"lowres032.tif",
)
('lowres032.tif', <http.client.HTTPMessage at 0x7a4e5d1cd7c0>)
Ici, nous associons les chemins téléchargés à des variables pour plus de commodité (et nous vérifions qu’ils existent)
lowres_fp = Path("lowres032.tif").resolve()
dem_fp = Path("hires002_dem.tif").resolve()
assert lowres_fp.is_file(), f"missing low-res raster\n {lowres_fp}"
assert dem_fp.is_file(), f"missing DEM raster\n {dem_fp}"
Récupérer les poids du modèle#
Vous pouvez ignorer cette étape si vous venez d’exécuter le tutoriel 1, mais relancer la récupération est une bonne pratique et sans danger (si le fichier existe déjà, il ne sera pas retéléchargé).
!floodsr models fetch --no-progress ResUNet_16x_DEM
INFO:floodsr.model_registry:attempting unauthenticated model download from
https://github.com/cefect/floodsr/releases/download/v2026.02.19/model_infer.onnx
version=ResUNet_16x_DEM stored=/tmp/.cache/floodsr/ResUNet_16x_DEM/model_infer.onnx retrieved_from=fetch:http
Tracer les entrées du tutoriel#
Commençons par définir une fonction simple pour nous aider à charger les données raster dans les graphiques
def read_raster_band_1(fp):
"""Read band 1 as float and promote masked nodata pixels to NaN."""
assert Path(fp).is_file(), f"missing raster\n {fp}"
with rasterio.open(fp) as src:
return src.read(1, masked=True).astype(float).filled(np.nan)
Nous créons maintenant un graphique simple des entrées basse résolution et du DEM haute résolution que nous avons téléchargés.
# Read both inputs with masked nodata promoted to NaN for plotting.
lowres_arr = read_raster_band_1(lowres_fp)
dem_arr = read_raster_band_1(dem_fp)
# setup the figure
fig, axes = plt.subplots(1, 2, figsize=(10, 4))
# add the flood raster to the left with a blue colormap, masking nodata values
im0 = axes[0].imshow(np.where(lowres_arr > 0, lowres_arr, np.nan), cmap="Blues")
axes[0].set_title("Low-res flood depth")
fig.colorbar(im0, ax=axes[0])
axes[0].set_axis_off()
# add the DEM raster to the right with a terrain colormap
im1 = axes[1].imshow(dem_arr, cmap="terrain")
axes[1].set_title("High-res DEM")
fig.colorbar(im1, ax=axes[1])
axes[1].set_axis_off()
On voit ici le raster pluvial grossier en 32 m, pas franchement idéal.
Tracer les sorties du tutoriel 1#
Reconstituons maintenant le raster de profondeur d’inondation haute résolution en utilisant la même commande que dans le tutoriel 1, puis traçons le résultat.
# Run the default threshold first so we have a baseline for comparison.
!floodsr -q tohr --in lowres032.tif --dem hires002_dem.tif --out lowres032_default_sr.tif
Et un rapide graphique :
arr = read_raster_band_1("lowres032_default_sr.tif")
fig, ax = plt.subplots(figsize=(5, 5))
im = ax.imshow(arr, cmap="Blues")
ax.set_title("Tutorial 1 high-res flood depth")
fig.colorbar(im, ax=ax)
ax.set_axis_off()
Politiques de SCR#
Ici, nous montrons le comportement de floodsr lorsque les rasters d’entrée ont des informations de SCR incompatibles, et comment utiliser l’option --crs-policy pour contrôler ce comportement.
Examiner le SCR des deux rasters#
Un système de coordonnées de référence (SCR, ou CRS en anglais) indique aux logiciels raster comment les positions des pixels se mappent sur des coordonnées réelles. Idéalement, toutes vos données partagent un SCR commun évident (par exemple NAD83(CSRS) / Canada Atlas Lambert, alias EPSG:3979), mais en pratique vous pouvez rencontrer des rasters avec des informations de SCR manquantes ou incompatibles ; il faut alors indiquer à floodsr comment gérer ces cas.
Avant de provoquer volontairement un décalage de SCR, examinons les métadonnées de SCR des rasters d’origine.
with rasterio.open(lowres_fp) as src:
print(f"{lowres_fp.name}: crs={src.crs} shape={src.shape} res={src.res}")
with rasterio.open(dem_fp) as src:
print(f"{dem_fp.name}: crs={src.crs} shape={src.shape} res={src.res}")
lowres032.tif: crs=EPSG:3979 shape=(32, 32) res=(32.0, 32.0)
hires002_dem.tif: crs=EPSG:3979 shape=(512, 512) res=(2.0, 2.0)
On voit ici que les deux rasters partagent exactement le même SCR.
C’est pratique pour un jeu de données de test simple, mais moins intéressant pour montrer comment floodsr gère une incompatibilité de SCR. Ajoutons un peu de désordre.
Créer volontairement un décalage de SCR#
Pour démontrer --crs-policy, nous reprojetons le raster basse résolution vers 3978 à l’aide de rasterio CLI et l’enregistrons sous forme de nouveau GeoTIFF.
!rio warp lowres032.tif lowres032_epsg3978.tif --dst-crs EPSG:3978 --resampling nearest --co TILED=YES
Exécuter tohr avec un SCR incompatible#
Cette commande devrait échouer parce que le raster basse résolution et le DEM ne partagent plus le même SCR, et nous n’avons pas encore indiqué à floodsr comment gérer cette incompatibilité ; il suppose donc par défaut --crs-policy strict.
!floodsr tohr --in lowres032_epsg3978.tif --dem hires002_dem.tif
INFO:floodsr.cli:loaded ORT model 'model_infer.onnx' with providers=['CPUExecutionProvider'] and scale=16
INFO:floodsr.cli:tohr path selection
requested_window_method=feather
dem_float32_bytes=1,048,576
windowed_io_threshold_bytes=33,554,432
selected_platform_materialization=simple
ERROR:floodsr.cli:CRS mismatch under --crs-policy strict
depth=EPSG:3978
dem=EPSG:3979
À quoi sert --crs-policy#
--crs-policy contrôle la manière dont floodsr gère les incompatibilités de SCR entre le raster de profondeur basse résolution et le DEM. C’est nécessaire, car tohr a besoin que les rasters soient alignés sur une grille projetée commune avant que le prétraitement et l’inférence puissent démarrer, et il n’existe pas de « bonne réponse » évidente quant au SCR à utiliser lorsqu’ils ne correspondent pas.
Dans cet exemple, nous utilisons --crs-policy=use-dem, ce qui indique à floodsr de prendre le SCR du DEM comme SCR cible et de reprojeter le raster de profondeur basse résolution pour s’y conformer. Nous aurions aussi pu choisir --crs-policy=use-lores, qui aurait pris le SCR du raster basse résolution comme cible et reprojeté le DEM pour s’y adapter.
!floodsr tohr --in lowres032_epsg3978.tif --dem hires002_dem.tif --crs-policy=use-dem --out lowres032_epsg3978_use_dem_sr.tif
Tracer le résultat avec la politique de SCR#
Comparons le résultat de --crs-policy=use-dem avec la sortie de référence obtenue lors de l’exécution initiale avec SCR concordants.
default_fp = Path("lowres032_default_sr.tif").resolve()
use_dem_fp = Path("lowres032_epsg3978_use_dem_sr.tif").resolve()
default_arr = read_raster_band_1(default_fp)
use_dem_arr = read_raster_band_1(use_dem_fp)
fig, axes = plt.subplots(1, 2, figsize=(9, 4))
plot_l = [
(axes[0], np.where(default_arr > 0, default_arr, np.nan), "Baseline (`lowres032_default_sr.tif`)"),
(axes[1], np.where(use_dem_arr > 0, use_dem_arr, np.nan), "`--crs-policy=use-dem`")
]
for ax, arr, title in plot_l:
wet_pct = 100.0 * float(np.count_nonzero(np.nan_to_num(arr, nan=0.0) > 0.0)) / float(arr.size)
ax.imshow(arr, cmap="Blues")
ax.set_title(title)
ax.axis("off")
ax.text(0.03, 0.03, f"wet={wet_pct:.1f}%", transform=ax.transAxes, color="black", fontsize=10, bbox={"facecolor": "white", "alpha": 0.8, "edgecolor": "none"})
fig.tight_layout()
Cela me semble identique ! comme prévu…
Consultez FAQ pour en savoir plus sur les politiques de SCR.
Seuil minimal de profondeur#
Examinons maintenant l’argument --min-depth-threshold, qui définit la profondeur prédite minimale conservée dans le raster de sortie. Les valeurs inférieures au seuil sont écrites comme 0.0.
C’est utile parce que de très petites prédictions positives peuvent être bruyantes ou physiquement peu plausibles, ce qui en fait un paramètre important pour ajuster le résultat.
Nous avons déjà exécuté tohr avec le --min-depth-threshold par défaut (0.01) ci-dessus comme référence, alors relançons-le avec un seuil plus élevé de 0.1 pour comparer.
Vous remarquerez que nous avons utilisé l’option -q ou --quiet ici pour supprimer la sortie habituelle de la CLI.
Exécutons maintenant tohr avec un --min-depth-threshold plus élevé, à 0.1.
!floodsr tohr --in lowres032.tif --dem hires002_dem.tif --min-depth-threshold=0.1 --out lowres032_min_depth_01_sr.tif
Tracé#
# Resolve the two outputs we want to compare.
default_fp = Path("lowres032_default_sr.tif").resolve()
threshold_fp = Path("lowres032_min_depth_01_sr.tif").resolve()
default_arr = read_raster_band_1(default_fp)
threshold_arr = read_raster_band_1(threshold_fp)
# Plot the input and both thresholded outputs side by side.
fig, axes = plt.subplots(1, 3, figsize=(13, 4))
plot_l = [
(axes[0], np.where(lowres_arr > 0, lowres_arr, np.nan), "Input low-res"),
(axes[1], np.where(default_arr > 0, default_arr, np.nan), "Default threshold"),
(axes[2], np.where(threshold_arr > 0, threshold_arr, np.nan), "`--min-depth-threshold=0.1`"),
]
for ax, arr, title in plot_l:
wet_pct = 100.0 * float(np.count_nonzero(np.nan_to_num(arr, nan=0.0) > 0.0)) / float(arr.size)
ax.imshow(arr, cmap="Blues")
ax.set_title(title)
ax.axis("off")
ax.text(0.03, 0.03, f"wet={wet_pct:.1f}%", transform=ax.transAxes, color="black", fontsize=10, bbox={"facecolor": "white", "alpha": 0.8, "edgecolor": "none"})
fig.tight_layout()
Suite#
Poursuivez avec le tutoriel 3 pour voir comment floodsr peut fonctionner sur des rasters de grande taille.