Files
lidar_rendu/run.sh
Antoine Jacquin 053eb2f529 Ajouter une carte à tuiles XYZ (image lidar-maps) réutilisable dans OSM
L'ancienne carte n'est pas une carte à tuiles : une div Leaflet par dalle,
rotée en CSS pour coller la grille Lambert 93 sur le Web Mercator, trois
paliers d'images choisis à la main, un plafond d'images pleine résolution et
une mosaïque d'overview pour boucher les trous au dézoom. Des centaines de
nœuds DOM, des AVIF de 2500² à 5000² décodés dans le navigateur, un LOD
maison — et rien de réutilisable hors de cette page.

Nouvelle image légère (Pillow + pyproj, ni GDAL ni PDAL, port 8975) servant
une pyramide XYZ EPSG:3857 au schéma OpenStreetMap, rendue à la demande
depuis les dalles et mise en cache dans output/index_xyz/ :

- tiles.py : grille XYZ, reprojection par transformation projective dalle par
  dalle (calage mesuré < 1 px), choix du palier source parmi ceux que le
  pipeline produit déjà (vignette, intermédiaire, quadrant, dalle), cache
  périmé dès qu'une dalle contributrice est plus récente, marqueur .empty
  pour les zones sans donnée, cache d'images sources à budget mémoire ;
- mapserve.py : /tiles/{couche}/{z}/{x}/{y}.png (256 px canonique) et
  @2x.webp (512 px, interface), TileJSON, WMTS, josm.imagery.xml, CORS —
  les rendus deviennent un fond d'imagerie pour JOSM, iD, QGIS, uMap ;
- mapui.py : une L.tileLayer par couche dans un pane isolé — LOD, cache et
  animation natifs de Leaflet ; pile réordonnable (glisser avec barre
  d'insertion, ou boutons ▲▼ au doigt), modes de fusion CSS par couche,
  configuration figeable comme défaut de tous les navigateurs.

Deux amonts pour les déploiements en deux machines : LIDAR_SOURCE_URL
(webapp du pipeline — inventaire complet, dalles rapatriées à la demande) et
LIDAR_MAPS_URL (autre instance carte). Charge bornée et réglable, taillée
par défaut pour une petite machine : 2 rendus et 2 téléchargements
simultanés, 192 Mo de cache de sources.

Mesuré sur 849 dalles réelles : première tuile d'une zone 0,9–3,2 s
(téléchargement compris), ~1 ms ensuite ; un chemin OSM se superpose
exactement à la trace du rendu de pente, et les coutures entre tuiles
restent sous le bruit naturel du terrain.

L'interface historique (port 8973) n'est pas touchée : génération et export
y restent, les deux cartes coexistent.
2026-09-23 14:47:38 +02:00

472 lines
22 KiB
Bash
Executable File

#!/bin/bash
# Pipeline LiDAR Archéologique
# Utilisation: ./run.sh [options]
#
# Options:
# -r RESOLUTION Résolution en m/px, ou multiples séparées par virgules (défaut: 0.5, ex: 0.5,0.2)
# -w WORKERS Nombre de workers parallèles (défaut: 1)
# -g [LISTE] Sélectionner le(s) GPU(s) : -g (auto), -g 0, -g 0,2, -g all
# -v Mode verbeux
# --debug Mode debug
# -f / --force Régénérer tous les fichiers
# --keep-tif Conserver les fichiers TIFF
# --force-classification
# --ground-classification {auto,ign,smrf,csf}
# --ign-classes CLASSES
# Classes LAS pour le MNT IGN (ex: sol,unclassified ; défaut: sol)
# --quality N Qualité image 1-100 (défaut: 98)
# --lossless Compression lossless
# --format FMT Format de sortie : avif (défaut) ou webp
# --only VIZ... Générer uniquement ces visualisations
# --skip VIZ... Exclure ces visualisations
# --file NOM... Traiter un ou plusieurs fichiers LAZ
# --test Exécuter les tests unitaires
# --serve [PORT] Carte + API de génération (image complète, défaut: 8973)
# --serve-webapp [PORT]
# Conteneur webapp seul (image légère) : carte servie depuis
# le cache local de tuiles, génération déléguée à la machine
# de traitement (LIDAR_GENERATION_URL), tuiles à la demande
# -h Afficher l'aide complète
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
INPUT_DIR="${SCRIPT_DIR}/input"
OUTPUT_DIR="${SCRIPT_DIR}/output"
IMAGE_NAME="lidar-lidar"
# Afficher l'aide si aucun argument
if [ $# -eq 0 ]; then
echo "Pipeline LiDAR Archéologique"
echo ""
echo "Usage: $0 [options]"
echo ""
echo "Options:"
echo " -r RESOLUTION Résolution en m/px, ou multiples (défaut: 0.5, ex: 0.5,0.2)"
echo " -w WORKERS Nombre de workers CPU parallèles (défaut: 1)"
echo " -g [LISTE] Sélectionner le(s) GPU(s) : -g (auto), -g 0, -g 0,2, -g all"
echo " -v Mode verbeux (timestamps + niveaux)"
echo " --debug Mode debug (détails internes fichier:ligne)"
echo " -f / --force Régénérer tous les fichiers même si les AVIF existent"
echo " --force-classification"
echo " Reclassifier le sol même si le fichier .las existe"
echo " --keep-tif Conserver les TIFF pour régénérer les AVIF"
echo " --ground-classification {auto,ign,smrf,csf}"
echo " Méthode de classification du sol (défaut: auto = pré-classification IGN)"
echo " --ign-classes CLASSES"
echo " Classes LAS pour le MNT IGN : sol,unclassified,eau,virtuel,pont,sursol"
echo " ou codes (ex: 2,1). Mode pur, aucune retouche. (défaut: sol)"
echo " --quality N Qualité image 1-100 (défaut: 98, 100=lossless)"
echo " --lossless Compression lossless (équivalent à --quality 100)"
echo " --format FMT Format de sortie : avif (défaut) ou webp"
echo " --only VIZ... Générer uniquement ces visualisations"
echo " --skip VIZ... Exclure ces visualisations"
echo " --file NOM... Traiter un ou plusieurs fichiers LAZ (nom complet sans .laz/.las)"
echo " --test Exécuter les tests unitaires"
echo " -h Afficher cette aide"
echo ""
echo "Visualisations disponibles:"
echo " hillshade slope mslrm sailore pos_open neg_open"
echo " svf aniso_open roughness wavelet flow_acc"
echo " ortho topo"
echo ""
echo "Exemples:"
echo " $0 -g # GPU auto (premier disponible)"
echo " $0 -g 0 # GPU index 0"
echo " $0 -g 0,2 # GPUs 0 et 2"
echo " $0 -g all # Tous les GPUs"
echo " $0 -g -w 4 # GPU + 4 workers"
echo " $0 -g -r 0.2 # Haute résolution"
echo " $0 -g -r 0.5,0.2 # Multi-résolution (0.5m + 0.2m)"
echo " $0 -g --force # Régénérer AVIF (DTM conservé si --keep-tif)"
echo " $0 -g --force-classification # Reclassifier le sol seulement"
echo " $0 -g --ground-classification csf # Forcer CSF (terrain complexe)"
echo " $0 -g --file LHD_...IGN69.copc # Un fichier"
exit 0
fi
RESOLUTION=0.5
WORKERS=1
GPU_FLAG=""
GPU_ARG=""
VERBOSE_FLAG=""
FORCE_FLAG=""
FILE_ARGS=""
GROUND_METHOD=""
IGN_CLASSES_FLAG=""
FORCE_CLASSIFY_FLAG=""
KEEP_TIF_FLAG=""
QUALITY=""
FORMAT_FLAG=""
ONLY_FLAG=""
SKIP_FLAG=""
TEST_FLAG=0
REBUILD_INDEX_FLAG=""
NO_INDEX_FLAG=""
FETCH_TILES_ARGS=""
SERVE_FLAG=0
SERVE_PORT=8973
WEBAPP_FLAG=0
WEBAPP_SERVE_PORT=8973
WEBAPP_IMAGE="lidar-webapp"
MAPS_FLAG=0
MAPS_SERVE_PORT=8975
MAPS_IMAGE="lidar-maps"
# Parse arguments manually (more robust than getopts for mixed short/long options)
while [ $# -gt 0 ]; do
case "$1" in
-r) RESOLUTION="$2"; shift 2 ;;
-w) WORKERS="$2"; shift 2 ;;
-g)
GPU_FLAG="--gpus all"
# Check if next arg is a GPU selector (not another flag)
if [ $# -gt 1 ] && [[ ! "$2" =~ ^- ]]; then
GPU_ARG="$2"
GPU_FLAG="--gpus all"
shift 2
else
shift
fi
;;
-v) VERBOSE_FLAG="-v"; shift ;;
-f) FORCE_FLAG="--force"; shift ;;
--debug) VERBOSE_FLAG="--debug"; shift ;;
--force) FORCE_FLAG="--force"; shift ;;
--force-classification) FORCE_CLASSIFY_FLAG="--force-classification"; shift ;;
--keep-tif) KEEP_TIF_FLAG="--keep-tif"; shift ;;
--ground-classification) GROUND_METHOD="$2"; shift 2 ;;
--ground-classification=*) GROUND_METHOD="${1#--ground-classification=}"; shift ;;
--ign-classes) IGN_CLASSES_FLAG="--ign-classes $2"; shift 2 ;;
--ign-classes=*) IGN_CLASSES_FLAG="--ign-classes=${1#--ign-classes=}"; shift ;;
--quality) QUALITY="--quality $2"; shift 2 ;;
--lossless) QUALITY="--lossless"; shift ;;
--format) FORMAT_FLAG="--format $2"; shift 2 ;;
--only) shift; ONLY_FLAG="--only"; while [ $# -gt 0 ] && [[ ! "$1" =~ ^- ]]; do ONLY_FLAG="$ONLY_FLAG $1"; shift; done ;;
--skip) shift; SKIP_FLAG="--skip"; while [ $# -gt 0 ] && [[ ! "$1" =~ ^- ]]; do SKIP_FLAG="$SKIP_FLAG $1"; shift; done ;;
--file) shift; while [ $# -gt 0 ] && [[ ! "$1" =~ ^- ]]; do FILE_ARGS="$FILE_ARGS $1"; shift; done ;;
--rebuild-index) REBUILD_INDEX_FLAG="--rebuild-index"; shift ;;
--no-index) NO_INDEX_FLAG="--no-index"; shift ;;
--fetch-tiles) shift; while [ $# -gt 0 ] && [[ ! "$1" =~ ^- ]]; do FETCH_TILES_ARGS="$FETCH_TILES_ARGS $1"; shift; done ;;
--test) TEST_FLAG=1; shift ;;
--serve)
SERVE_FLAG=1; shift
if [ $# -gt 0 ] && [[ ! "$1" =~ ^- ]]; then SERVE_PORT="$1"; shift; fi
;;
--serve-webapp)
WEBAPP_FLAG=1; shift
if [ $# -gt 0 ] && [[ ! "$1" =~ ^- ]]; then WEBAPP_SERVE_PORT="$1"; shift; fi
;;
--serve-maps)
MAPS_FLAG=1; shift
if [ $# -gt 0 ] && [[ ! "$1" =~ ^- ]]; then MAPS_SERVE_PORT="$1"; shift; fi
;;
-h|--help|-help)
echo "Pipeline LiDAR Archéologique"
echo ""
echo "Usage: $0 [options]"
echo ""
echo "Options:"
echo " -r RESOLUTION Résolution en m/px (défaut: 0.5)"
echo " -w WORKERS Nombre de workers CPU parallèles (défaut: 1)"
echo " -g [LISTE] Sélectionner le(s) GPU(s) : -g (auto), -g 0, -g 0,2, -g all"
echo " -v Mode verbeux (timestamps + niveaux)"
echo " --debug Mode debug (détails internes fichier:ligne)"
echo " -f / --force Régénérer tous les fichiers même si les AVIF existent"
echo " --force-classification"
echo " Reclassifier le sol même si le fichier .las existe"
echo " --keep-tif Conserver les TIFF pour régénérer les AVIF"
echo " --ground-classification {auto,ign,smrf,csf}"
echo " Méthode de classification du sol (défaut: auto = pré-classification IGN)"
echo " --ign-classes CLASSES"
echo " Classes LAS pour le MNT IGN : sol,unclassified,eau,virtuel,pont,sursol"
echo " ou codes (ex: 2,1). Mode pur, aucune retouche. (défaut: sol)"
echo " --quality N Qualité image 1-100 (défaut: 98, 100=lossless)"
echo " --lossless Compression lossless (équivalent à --quality 100)"
echo " --format FMT Format de sortie : avif (défaut) ou webp"
echo " --only VIZ... Générer uniquement ces visualisations"
echo " --skip VIZ... Exclure ces visualisations"
echo " --file NOM... Traiter un ou plusieurs fichiers LAZ"
echo " --fetch-tiles COL,ROW..."
echo " Télécharger ces dalles depuis l'IGN puis les traiter"
echo " --serve [PORT] Servir la carte + API de génération de zones (défaut: 8973)"
echo " --serve-webapp [PORT]"
echo " Conteneur webapp seul (image légère, sans PDAL/GPU) :"
echo " carte servie depuis le cache local de tuiles, génération"
echo " déléguée via LIDAR_GENERATION_URL (tuiles à la demande)"
echo " (cf. docs/DEPLOY_WEBAPP.md)"
echo " --serve-maps [PORT]"
echo " Carte à tuiles XYZ (image légère lidar-maps, défaut 8975) :"
echo " schéma OpenStreetMap, réutilisable dans JOSM/QGIS/iD"
echo " (cf. docs/MAPS.md)"
echo " --test Exécuter les tests unitaires"
echo " -h Afficher cette aide"
echo ""
echo "Visualisations disponibles:"
echo " hillshade slope mslrm sailore pos_open neg_open"
echo " svf aniso_open roughness wavelet flow_acc"
echo " ortho topo"
echo ""
echo "Exemples:"
echo " $0 -g # GPU auto (premier disponible)"
echo " $0 -g 0 # GPU index 0"
echo " $0 -g 0,2 # GPUs 0 et 2"
echo " $0 -g all # Tous les GPUs"
echo " $0 -g -w 4 # GPU + 4 workers"
echo " $0 -g -v # GPU + verbeux"
echo " $0 -g -r 0.2 # Haute résolution"
echo " $0 -g -r 0.5,0.2 # Multi-résolution (0.5m + 0.2m)"
echo " $0 -g --force # Régénérer AVIF"
echo " $0 -g --only hillshade svf # Seulement 2 visualisations"
echo " $0 -g --skip ortho topo # Sans les overlays IGN"
echo " $0 -g --lossless # AVIF lossless"
echo " $0 -g --quality 90 # AVIF qualité 90"
echo " $0 -g --ground-classification csf # Forcer CSF (terrain complexe)"
echo " $0 -g --file LHD_...IGN69.copc # Un fichier"
exit 0
;;
*) echo "Option invalide: $1" >&2; exit 1 ;;
esac
done
# Trim FILE_ARGS whitespace
FILE_ARGS=$(echo "$FILE_ARGS" | xargs)
FETCH_TILES_ARGS=$(echo "$FETCH_TILES_ARGS" | xargs)
# input/ en lecture seule sauf si --fetch-tiles (téléchargement IGN dans input/)
INPUT_RO=":ro"
if [ -n "$FETCH_TILES_ARGS" ]; then
INPUT_RO=""
fi
# Build systématique de l'image avant tout docker run. Le cache Docker rend
# l'opération quasi instantanée si le code n'a pas changé ; en cas d'échec,
# le journal complet est affiché. Ça évite de lancer tests/serveur/pipeline
# sur une image périmée (code baké à la dernière édition).
build_image() {
local log="/tmp/lidar_build_$$.log"
echo "Mise à jour de l'image Docker (cache)..."
if ! docker build -t "$IMAGE_NAME" "$SCRIPT_DIR" >"$log" 2>&1; then
cat "$log" >&2
echo "Échec du build de l'image (journal : $log)" >&2
exit 1
fi
rm -f "$log"
}
# Image webapp légère (conteneur webapp seul — cf. Dockerfile.webapp)
build_webapp_image() {
local log="/tmp/lidar_webapp_build_$$.log"
echo "Mise à jour de l'image Docker webapp (cache)..."
if ! docker build -f Dockerfile.webapp -t "$WEBAPP_IMAGE" "$SCRIPT_DIR" >"$log" 2>&1; then
cat "$log" >&2
echo "Échec du build de l'image webapp (journal : $log)" >&2
exit 1
fi
}
# Image carte à tuiles XYZ (cf. Dockerfile.maps)
build_maps_image() {
local log="/tmp/lidar_maps_build_$$.log"
echo "Mise à jour de l'image Docker carte (cache)..."
if ! docker build -f Dockerfile.maps -t "$MAPS_IMAGE" "$SCRIPT_DIR" >"$log" 2>&1; then
cat "$log" >&2
echo "Échec du build de l'image carte (journal : $log)" >&2
exit 1
fi
rm -f "$log"
}
# Check for --test flag first
if [ "$TEST_FLAG" -eq 1 ]; then
build_image
echo "============================================"
echo " Tests unitaires LiDAR Pipeline"
echo "============================================"
docker run --rm --init $GPU_FLAG \
"$IMAGE_NAME" \
python3 -m pytest -v --pyargs lidar_pipeline.tests
exit $?
fi
build_image
# Créer les répertoires s'ils n'existent pas
mkdir -p "$INPUT_DIR" "$OUTPUT_DIR"
# Mode --serve : carte + API de génération (input/ en écriture)
if [ "$SERVE_FLAG" -eq 1 ]; then
echo "============================================"
echo " Carte LiDAR + API de génération"
echo "============================================"
echo " http://127.0.0.1:${SERVE_PORT}/"
echo " GPU : $([ -n "$GPU_FLAG" ] && echo 'OUI' || echo 'non')"
echo " Bouton « + Zone » : dessiner un rectangle → téléchargement IGN + rendu"
echo "============================================"
GPU_ENV_FLAG=""
[ -n "$GPU_FLAG" ] && GPU_ENV_FLAG="-e LIDAR_GPU=1"
if [ -n "$GPU_ARG" ] && [ "$GPU_ARG" != "all" ]; then
GPU_ENV_FLAG="-e LIDAR_GPU=1 -e CUDA_VISIBLE_DEVICES=${GPU_ARG} --gpus '""device=${GPU_ARG}""'"
fi
# Réseau autorisé à lancer les générations (/api/generate) : la valeur
# vient de l'environnement hôte LIDAR_REGEN_CIDR ; sans elle, le défaut
# de la webapp s'applique (localhost + RFC1918). Chaîne VIDE pour lever
# complètement la restriction.
REGEN_ENV_FLAG="-e LIDAR_REGEN_CIDR=${LIDAR_REGEN_CIDR-127.0.0.0/8,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16}"
exec docker run --rm --init $GPU_FLAG \
--user 1000:1000 \
-p "${SERVE_PORT}:8973" \
-v "${INPUT_DIR}:/data/input" \
-v "${OUTPUT_DIR}:/data/output" \
-e LIDAR_INPUT_DIR=/data/input -e LIDAR_OUTPUT_DIR=/data/output \
$GPU_ENV_FLAG $REGEN_ENV_FLAG \
"$IMAGE_NAME" \
python3 -m uvicorn lidar_pipeline.webapp:app --host 0.0.0.0 --port 8973
fi
# Mode --serve-maps : carte à tuiles XYZ (image légère lidar-maps).
# Les tuiles suivent le schéma OpenStreetMap ({z}/{x}/{y}.png) : la carte est
# consultable ici et les mêmes URLs servent de fond d'imagerie dans JOSM, iD,
# QGIS ou uMap. Variables optionnelles depuis l'environnement hôte :
# LIDAR_MAPS_URL serveur de tuiles amont (carte déportée)
# LIDAR_ATTRIBUTION mention d'attribution servie aux clients
if [ "$MAPS_FLAG" -eq 1 ]; then
build_maps_image
mkdir -p "$OUTPUT_DIR"
echo "============================================"
echo " Carte LiDAR — tuiles XYZ (image légère)"
echo "============================================"
echo " Carte : http://127.0.0.1:${MAPS_SERVE_PORT}/"
echo " Tuiles XYZ : http://127.0.0.1:${MAPS_SERVE_PORT}/tiles/{couche}/{z}/{x}/{y}.png"
echo " JOSM / QGIS : /tiles/josm.imagery.xml, /tiles/wmts.xml"
echo " Amont : ${LIDAR_MAPS_URL:-aucun (rendu local)}"
echo "============================================"
MAPS_ENV=()
[ -n "${LIDAR_MAPS_URL:-}" ] && MAPS_ENV+=(-e LIDAR_MAPS_URL="$LIDAR_MAPS_URL")
[ -n "${LIDAR_ATTRIBUTION:-}" ] && MAPS_ENV+=(-e LIDAR_ATTRIBUTION="$LIDAR_ATTRIBUTION")
exec docker run --rm --init \
--user 1000:1000 \
-p "${MAPS_SERVE_PORT}:8975" \
-v "${OUTPUT_DIR}:/data/output" \
-e LIDAR_OUTPUT_DIR=/data/output \
"${MAPS_ENV[@]}" \
"$MAPS_IMAGE"
fi
# Mode --serve-webapp : conteneur webapp SEUL (image légère, sans PDAL/GPU).
# La carte est servie depuis le cache local de tuiles (output/) ; la
# génération est déléguée à la machine de traitement et les tuiles sont
# servies à la demande depuis LIDAR_GENERATION_URL (plus de rsync).
# Variables passées telles quelles depuis l'environnement hôte :
# LIDAR_GENERATION_URL machine de traitement (ex: http://192.168.1.50:8973)
# LIDAR_REMOTE_TOKEN jeton si la machine exige LIDAR_API_TOKEN
# LIDAR_REGEN_CIDR réseau autorisé à lancer les générations
# (défaut 192.168.1.0/24, vide = restriction levée)
if [ "$WEBAPP_FLAG" -eq 1 ]; then
build_webapp_image
mkdir -p "$OUTPUT_DIR"
echo "============================================"
echo " Carte LiDAR — webapp seule (image légère)"
echo "============================================"
echo " http://127.0.0.1:${WEBAPP_SERVE_PORT}/"
echo " Génération distante : ${LIDAR_GENERATION_URL:-non configurée (LIDAR_GENERATION_URL)}"
echo " Cache local tuiles : à la demande (LIDAR_GENERATION_URL)"
echo "============================================"
WEBAPP_ENV=()
[ -n "$LIDAR_GENERATION_URL" ] && WEBAPP_ENV+=(-e LIDAR_GENERATION_URL="$LIDAR_GENERATION_URL")
[ -n "$LIDAR_REMOTE_TOKEN" ] && WEBAPP_ENV+=(-e LIDAR_REMOTE_TOKEN="$LIDAR_REMOTE_TOKEN")
[ -n "$LIDAR_API_TOKEN" ] && WEBAPP_ENV+=(-e LIDAR_API_TOKEN="$LIDAR_API_TOKEN")
[ -n "${LIDAR_REGEN_CIDR:-}" ] && WEBAPP_ENV+=(-e LIDAR_REGEN_CIDR="$LIDAR_REGEN_CIDR")
# Clé SSH du hôte (déploiement, git pull distant) : montée en lecture seule
# si présente. LIDAR_MOUNT_SSH=0 pour ne PAS l'exposer au conteneur.
WEBAPP_SSH=()
[ "${LIDAR_MOUNT_SSH:-1}" = "1" ] && [ -d "${HOME}/.ssh" ] && WEBAPP_SSH+=(-v "${HOME}/.ssh:/home/lidar/.ssh:ro")
exec docker run --rm --init \
--user 1000:1000 \
-p "${WEBAPP_SERVE_PORT}:8973" \
-v "${OUTPUT_DIR}:/data/output" \
"${WEBAPP_SSH[@]}" \
-e LIDAR_OUTPUT_DIR=/data/output \
"${WEBAPP_ENV[@]}" \
"$WEBAPP_IMAGE"
fi
# Lancer le pipeline
echo "============================================"
echo " Pipeline LiDAR Archéologique"
echo "============================================"
echo " Résolution : ${RESOLUTION}m/px"
echo " Workers : ${WORKERS}"
echo " GPU : $([ -n "$GPU_FLAG" ] && echo "OUI${GPU_ARG:+ ($GPU_ARG)}" || echo 'non')"
echo " Verbeux : $([ -n "$VERBOSE_FLAG" ] && echo 'OUI' || echo 'non')"
echo " Force : $([ -n "$FORCE_FLAG" ] && echo 'OUI' || echo 'non')"
echo " Force classif.: $([ -n "$FORCE_CLASSIFY_FLAG" ] && echo 'OUI' || echo 'non')"
echo " Keep TIFF : $([ -n "$KEEP_TIF_FLAG" ] && echo 'OUI' || echo 'non')"
echo " Qualité image : $([ -n "$QUALITY" ] && echo "$QUALITY" || echo '98')"
echo " Format : $([ -n "$FORMAT_FLAG" ] && echo "${FORMAT_FLAG#--format }" || echo 'avif')"
echo " Classification sol : $([ -n "$GROUND_METHOD" ] && echo "$GROUND_METHOD" || echo 'auto')$([ -n "$IGN_CLASSES_FLAG" ] && echo " ${IGN_CLASSES_FLAG#--ign-classes }")"
if [ -n "$ONLY_FLAG" ]; then
echo " Visualisations: uniquement${ONLY_FLAG#--only}"
elif [ -n "$SKIP_FLAG" ]; then
echo " Visualisations: tout sauf${SKIP_FLAG#--skip}"
fi
if [ -n "$FILE_ARGS" ]; then
echo " Fichiers :${FILE_ARGS}"
fi
if [ -n "$FETCH_TILES_ARGS" ]; then
echo " Dalles IGN :${FETCH_TILES_ARGS} (input/ monté en écriture)"
fi
echo "============================================"
CMD_ARGS="-o /data/output -r $RESOLUTION -w $WORKERS $VERBOSE_FLAG $FORCE_FLAG $FORCE_CLASSIFY_FLAG $KEEP_TIF_FLAG $QUALITY $FORMAT_FLAG"
if [ -n "$GPU_ARG" ]; then
CMD_ARGS="$CMD_ARGS -g $GPU_ARG"
fi
if [ -z "$GPU_ARG" ] && [ -n "$GPU_FLAG" ]; then
CMD_ARGS="$CMD_ARGS -g"
fi
if [ -n "$GROUND_METHOD" ]; then
CMD_ARGS="$CMD_ARGS --ground-classification $GROUND_METHOD"
fi
if [ -n "$IGN_CLASSES_FLAG" ]; then
CMD_ARGS="$CMD_ARGS $IGN_CLASSES_FLAG"
fi
if [ -n "$ONLY_FLAG" ]; then
CMD_ARGS="$CMD_ARGS $ONLY_FLAG"
fi
if [ -n "$SKIP_FLAG" ]; then
CMD_ARGS="$CMD_ARGS $SKIP_FLAG"
fi
if [ -n "$FILE_ARGS" ]; then
CMD_ARGS="$CMD_ARGS --file $FILE_ARGS"
fi
if [ -n "$REBUILD_INDEX_FLAG" ]; then
CMD_ARGS="$CMD_ARGS $REBUILD_INDEX_FLAG"
fi
if [ -n "$NO_INDEX_FLAG" ]; then
CMD_ARGS="$CMD_ARGS $NO_INDEX_FLAG"
fi
if [ -n "$FETCH_TILES_ARGS" ]; then
CMD_ARGS="$CMD_ARGS --fetch-tiles $FETCH_TILES_ARGS"
fi
# Build CUDA_VISIBLE_DEVICES env var from GPU_ARG
CUDA_ENV_FLAG=""
if [ -n "$GPU_ARG" ]; then
# Convert GPU_ARG (e.g. "0,2" or "1" or "all") to CUDA_VISIBLE_DEVICES
if [ "$GPU_ARG" = "all" ]; then
CUDA_VISIBLE="0,1,2,3"
else
CUDA_VISIBLE="$GPU_ARG"
fi
CUDA_ENV_FLAG="-e CUDA_VISIBLE_DEVICES=${CUDA_VISIBLE}"
fi
docker run --rm --init $GPU_FLAG $CUDA_ENV_FLAG \
--user 1000:1000 \
-v "${INPUT_DIR}:/data/input${INPUT_RO}" \
-v "${OUTPUT_DIR}:/data/output" \
"$IMAGE_NAME" \
python3 -m lidar_pipeline /data/input \
$CMD_ARGS