Refactor pipeline en modules + logging verbose/debug + options CLI
- Découpage du monolithe process_lidar.py (~2750 lignes) en package lidar_pipeline/ avec 9 modules (gpu, dtm, visualizations, ign, rendering, pipeline, cli, __init__, __main__) - Logging configurable: -v (verbose avec timestamps) et --debug (détails internes fichier:ligne) - Option --force pour régénérer tous les fichiers (par défaut skip les WebP existants) - Option --file NOM pour traiter un seul fichier LAZ (tests rapides) - ProcessPoolExecutor avec répertoires temporaires uniques par worker - Suppression du code mort (geomorphons, hillshade_ne, nodata_mask) - Aucun fichier TIFF résiduel après conversion WebP - setup.py pour installation pip, stub process_lidar.py compatible Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
73
lidar_pipeline/gpu.py
Normal file
73
lidar_pipeline/gpu.py
Normal file
@ -0,0 +1,73 @@
|
||||
"""GPU acceleration helpers for LiDAR pipeline.
|
||||
|
||||
Provides CuPy/numpy abstraction layer. If CuPy is available and a CUDA GPU
|
||||
is detected, array operations are accelerated on the GPU. Otherwise, all
|
||||
operations fall back to numpy/scipy on CPU.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import numpy as np
|
||||
from scipy import ndimage
|
||||
|
||||
logger = logging.getLogger("lidar")
|
||||
|
||||
# GPU detection - must happen at import time
|
||||
HAS_GPU = False
|
||||
_gpu_name = None
|
||||
_gpu_mem_gb = 0
|
||||
_xp = np # Default: CPU
|
||||
|
||||
try:
|
||||
import cupy as cp
|
||||
import cupyx.scipy.ndimage as cp_ndimage
|
||||
|
||||
_gpu_info = cp.cuda.runtime.getDeviceProperties(0)
|
||||
_gpu_name = _gpu_info['name'].decode() if isinstance(_gpu_info['name'], bytes) else str(_gpu_info['name'])
|
||||
_gpu_mem_gb = _gpu_info['totalGlobalMem'] // (1024 ** 3)
|
||||
HAS_GPU = True
|
||||
_xp = cp
|
||||
except (ImportError, Exception):
|
||||
pass
|
||||
|
||||
|
||||
def log_gpu_status():
|
||||
"""Log GPU detection result. Called after logging is configured."""
|
||||
if HAS_GPU:
|
||||
logger.info(f"GPU détectée: {_gpu_name} ({_gpu_mem_gb} Go VRAM)")
|
||||
else:
|
||||
logger.info("Pas de GPU — mode CPU uniquement")
|
||||
|
||||
|
||||
def to_gpu(arr):
|
||||
"""Send array to GPU if available, otherwise return as float64 numpy."""
|
||||
if HAS_GPU:
|
||||
return cp.asarray(arr.astype(np.float64))
|
||||
return arr.astype(np.float64)
|
||||
|
||||
|
||||
def to_cpu(arr):
|
||||
"""Bring array back to CPU (numpy). No-op if already on CPU."""
|
||||
if HAS_GPU and isinstance(arr, cp.ndarray):
|
||||
return cp.asnumpy(arr)
|
||||
return arr
|
||||
|
||||
|
||||
def xp_gaussian_filter(arr, sigma):
|
||||
"""Gaussian filter — uses GPU if array is on GPU, CPU otherwise."""
|
||||
if HAS_GPU and isinstance(arr, cp.ndarray):
|
||||
return cp_ndimage.gaussian_filter(arr, sigma)
|
||||
return ndimage.gaussian_filter(arr, sigma)
|
||||
|
||||
|
||||
def xp_uniform_filter(arr, size):
|
||||
"""Uniform filter — uses GPU if array is on GPU, CPU otherwise."""
|
||||
if HAS_GPU and isinstance(arr, cp.ndarray):
|
||||
return cp_ndimage.uniform_filter(arr, size)
|
||||
return ndimage.uniform_filter(arr, size)
|
||||
|
||||
|
||||
def xp_minimum_filter(arr, footprint=None, size=None):
|
||||
"""Minimum filter — uses GPU if array is on GPU, CPU otherwise."""
|
||||
if HAS_GPU and isinstance(arr, cp.ndarray):
|
||||
return cp_ndimage.minimum_filter(arr, footprint=footprint, size=size)
|
||||
return ndimage.minimum_filter(arr, footprint=footprint, size=size)
|
||||
Reference in New Issue
Block a user