Correction orientation nord + filtrage ReturnNumber=0 pour fichiers corrompus

- Inversion axe Y du DTM pour orientation nord correcte
- Fallback filters.range pour fichiers LAZ avec ReturnNumber=0
- Flèche nord vectorielle noire au-dessus de la légende
- 9/9 fichiers traités avec succès

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jacquin Antoine
2026-05-09 01:21:28 +02:00
parent 57b3b78593
commit 96cd62bc79
2 changed files with 168 additions and 47 deletions

99
analyze_and_fix.py Executable file
View File

@ -0,0 +1,99 @@
#!/usr/bin/env python3
"""
Script pour analyser et corriger les fichiers LAZ avec ReturnNumber=0
"""
import sys
import json
import subprocess
from pathlib import Path
def analyze_return_numbers(laz_file):
"""Analyse les valeurs ReturnNumber dans un fichier LAZ"""
print(f"Analyse de {laz_file}...")
# Pipeline PDAL pour extraire les statistiques ReturnNumber
stats_pipeline = [
{
"type": "readers.las",
"filename": str(laz_file)
},
{
"type": "filters.stats",
"dimensions": "ReturnNumber,NumberOfReturns"
}
]
stats_json = json.dumps(stats_pipeline)
stats_file = Path("/tmp/analyze_stats.json")
with open(stats_file, 'w') as f:
f.write(stats_json)
result = subprocess.run(['pdal', 'pipeline', str(stats_file)],
capture_output=True, text=True)
if result.returncode == 0:
data = json.loads(result.stdout)
stats = data.get('stats', {}).get('statistic', [])
print(f" Statistiques ReturnNumber:")
for stat in stats:
if stat.get('name') == 'ReturnNumber':
counts = stat.get('counts', {})
for val, count in counts.items():
if count > 0:
pct = count / stat.get('total', 1) * 100
print(f" ReturnNumber={val}: {count} points ({pct:.1f}%)")
else:
print(f" Erreur: {result.stderr}")
def fix_return_numbers(laz_file, output_file):
"""Corrige les valeurs ReturnNumber=0 en utilisant une approche différente"""
print(f"Tentative de correction de {laz_file}...")
# Approche: utiliser filters.python pour modifier les valeurs
fix_pipeline = [
{
"type": "readers.las",
"filename": str(laz_file)
},
{
"type": "filters.python",
"script": """
def filter(ins, args):
for point in ins:
if point.ReturnNumber == 0:
point.ReturnNumber = 1
if point.NumberOfReturns == 0:
point.NumberOfReturns = 1
return True
"""
},
{
"type": "writers.las",
"filename": str(output_file),
"extra_dims": "all"
}
]
fix_json = json.dumps(fix_pipeline, indent=2)
fix_file = Path("/tmp/fix_pipeline.json")
with open(fix_file, 'w') as f:
f.write(fix_json)
result = subprocess.run(['pdal', 'pipeline', str(fix_file)],
capture_output=True, text=True)
if result.returncode == 0:
print(f" ✓ Correction réussie: {output_file}")
return True
else:
print(f" ✗ Erreur correction: {result.stderr}")
return False
if __name__ == "__main__":
laz_file = sys.argv[1] if len(sys.argv) > 1 else "/data/input/LHD_FXX_1000_6882_PTS_LAMB93_IGN69.copc.laz"
analyze_return_numbers(laz_file)
output_file = laz_file.replace(".laz", "_fixed.laz").replace("/input/", "/temp/")
fix_return_numbers(laz_file, output_file)