Suppression éclairage solaire, GPU accéléré, --file multi, tests unitaires
- Suppression de generate_solar (éclairage solaire) des visualisations - Accélération GPU de hillshade, slope, aspect, curvature, depressions, anomalies, roughness, texture GLCM, flow (sink filling) - Nettoyage mémoire GPU entre visualisations (gpu_cleanup) - Correction OOM texture GLCM: calcul entropie bin par bin au lieu d'un tableau 3D massif sur GPU - Correction bug: xp_minimum_filter manquant dans imports visualizations - Option --file accepte plusieurs noms complets sans extension - run.sh affiche l'aide si appelé sans arguments - Option --test pour exécuter les tests unitaires dans Docker - Filtre ReturnNumber>=1 intégré dans le pipeline PDAL (plus d'erreur SMRF) - 60 tests unitaires: GPU, visualisations, rendering, DTM, pipeline, CLI - Ajout pytest au Dockerfile Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@ -23,6 +23,9 @@ logger = logging.getLogger("lidar")
|
||||
def create_smrf_pipeline(input_laz, output_las):
|
||||
"""Create a PDAL pipeline JSON for SMRF ground classification.
|
||||
|
||||
Includes a filter for ReturnNumber/NumberOfReturns >= 1 to handle
|
||||
LiDAR HD files that may contain points with invalid return numbers.
|
||||
|
||||
Args:
|
||||
input_laz: Path to input LAZ/LAS file.
|
||||
output_las: Path to output classified LAS file.
|
||||
@ -33,6 +36,10 @@ def create_smrf_pipeline(input_laz, output_las):
|
||||
pipeline = {
|
||||
"pipeline": [
|
||||
str(input_laz),
|
||||
{
|
||||
"type": "filters.range",
|
||||
"limits": "ReturnNumber[1:],NumberOfReturns[1:]"
|
||||
},
|
||||
{
|
||||
"type": "filters.smrf",
|
||||
"ignore": "Classification[7:7]",
|
||||
@ -87,36 +94,7 @@ def classify_ground(laz_file, temp_dir):
|
||||
logger.info(" ✓ Classification sol terminée")
|
||||
return output_las
|
||||
except subprocess.CalledProcessError as e:
|
||||
error_msg = e.stderr.decode()
|
||||
logger.error(f" ✗ Erreur PDAL: {error_msg}")
|
||||
|
||||
# If error is about ReturnNumber=0, try filtering those points
|
||||
if "ReturnNumber" in error_msg and "NumberOfReturns" in error_msg:
|
||||
logger.info(" → Tentative de filtrage des points ReturnNumber=0...")
|
||||
|
||||
filtered_pipeline = [
|
||||
{"type": "readers.las", "filename": str(laz_file)},
|
||||
{"type": "filters.range", "limits": "ReturnNumber[1:],NumberOfReturns[1:]"},
|
||||
{"type": "filters.smrf", "scalar": 1.25},
|
||||
{"type": "filters.range", "limits": "Classification[2:2]"},
|
||||
{"type": "writers.las", "filename": str(output_las), "extra_dims": "all"}
|
||||
]
|
||||
|
||||
filtered_json = json.dumps(filtered_pipeline)
|
||||
with open(pipeline_file, 'w') as f:
|
||||
f.write(filtered_json)
|
||||
|
||||
try:
|
||||
subprocess.run(
|
||||
["pdal", "pipeline", str(pipeline_file)],
|
||||
capture_output=True, check=True
|
||||
)
|
||||
logger.info(" ✓ Classification sol terminée (points filtrés)")
|
||||
return output_las
|
||||
except subprocess.CalledProcessError as e2:
|
||||
logger.error(f" ✗ Erreur même avec filtrage: {e2.stderr.decode()}")
|
||||
return None
|
||||
|
||||
logger.error(f" ✗ Erreur classification PDAL: {e.stderr.decode()}")
|
||||
return None
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user