Uno strumento Python modulare ed avanzato, dotato di interfaccia grafica desktop Qt e CLI, per l'analisi approfondita e la caratterizzazione di nuvole di punti in formato LAS, LAZ, E57 e PLY. Estrae automaticamente la "carta d'identità" del rilievo: software di generazione, sensore hardware (TLS, ALS, Mobile, Fotogrammetria UAV), coordinate, CRS/EPSG, statistiche dei punti e tracce di post-processing.
- Interfaccia Grafica Desktop Qt: GUI moderna con Drag & Drop di file e intere cartelle, tabella di avanzamento in tempo reale, ispettore parametri chiave e visualizzatore JSON interattivo.
- Supporto Multi-Formato:
- LAS / LAZ: Analisi completa di header, formati punto, classi, scale, VLR e tempo GPS con decompressione parallela (
lazrs). - E57 (ASTM E57): Supporto per scansioni multiple e singole, estrazione pose matriciali, bounds cartesiani e sferici, metadati dei sensori TLS (Faro, Leica, Trimble, Riegl).
- PLY (Polygon File Format): Analisi header ASCII/binario, proprietà, campi scalari, conteggio vertici/facce, estrazione commenti software e inferenza fotogrammetria.
- LAS / LAZ: Analisi completa di header, formati punto, classi, scale, VLR e tempo GPS con decompressione parallela (
- Analisi della Natura della Nuvola: Returns, classi di classificazione ASPRS, spettro di riflettanza/intensità, colori RGB e normali.
- Sistema di Coordinate & Georeferenziazione: Offset, scale, bounding box 3D, CRS/EPSG e WKT proiettato.
- Rilevamento Software & Provenienza: Identifica il software generatore o di post-processing (CloudCompare, FARO Scene, Leica Cyclone, Metashape, RealityCapture, LAStools, PDAL, ecc.).
- Inferenza Hardware del Sensore: Classifica il tipo di sensore (TLS, ALS, Mobile LiDAR, Fotogrammetria UAV) con indice di confidenza.
- Report HTML Interattivi: Generazione automatica di report visivi per singoli file e raggruppamenti automatici di scansioni correlate.
PointCloud-Identity-Inspector/
├── gui.py # Launcher interfaccia grafica desktop Qt
├── main.py # Entry point CLI e GUI
├── config/ # Database configurazioni e firme
│ ├── sensor_db.json # Database sensori LiDAR / Fotogrammetria
│ ├── sw_sign.json # Firme software e sensori
│ ├── class_map.json # Mappa classificazioni ASPRS
│ └── post_proc_sign.json # Firme di post-processing
├── src/ # Moduli principali
│ ├── extractor.py # PointCloudMetadataExtractor principale
│ ├── extractors/ # Estrattori specifici per formato
│ │ ├── e57_extr.py # Estrattore ASTM E57
│ │ ├── ply_extr.py # Estrattore PLY
│ │ ├── metadata_extr.py # Header & metadati base
│ │ ├── crs_extr.py # Sistemi di coordinate & CRS
│ │ ├── intensity_extr.py # Analisi intensità
│ │ ├── class_extr.py # Classificazioni
│ │ └── timestamp_extr.py # Tempo GPS e date
│ ├── detectors/ # Motori di inferenza
│ │ ├── sw_detect.py # Rilevamento software
│ │ ├── sensor_detect.py # Classificazione sensore hardware
│ │ └── process_detect.py # Rilevamento post-processing
│ ├── gui/ # Interfaccia Grafica Qt
│ │ ├── main_window.py # Finestra principale, drag&drop, tabelle
│ │ └── worker.py # Worker asincrono multi-thread (QThread)
│ └── utils/
│ ├── directory_handler.py # Scansione batch directory
│ ├── file_grouper.py # Raggruppamento nuvole correlate
│ ├── html_generator.py # Generatore report HTML interattivi
│ ├── config_load.py # Loader configurazioni JSON
│ └── file_handler.py # Gestione I/O
├── requirements.txt
├── LICENSE
└── README.mdClona il repository e installa le dipendenze richieste:
git clone https://github.com/ndree97/PC_identity.git
cd PC_identity
pip install -r requirements.txtPuoi avviare l'interfaccia grafica semplicemente eseguendo:
python gui.py
# oppure
python main.py- Trascina direttamente file
.las,.laz,.e57o.ply(o intere cartelle) nell'area di rilascio. - Seleziona le opzioni desiderate e premi Avvia Analisi.
- Clicca su ogni riga per visualizzare la carta d'identità, il JSON formattato e aprire il report HTML nel browser.
python main.py -i input.las
# Supporta anche altri formati:
python main.py -i input.laz
python main.py -i scan.e57
python main.py -i mesh.plySalva automaticamente i risultati in output/<filename>/<filename>_metadata.json e genera il report output/<filename>/<filename>_report.html.
python main.py -d /percorso/directoryScansiona ricorsivamente tutti i file supportati (.las, .laz, .e57, .ply), raggruppando i file correlati e generando statistiche aggregate e report HTML.
python main.py -i input.e57 -ppython main.py -i input.las -c config -ppython main.py -hLo script produce un file JSON strutturato con le seguenti sezioni:
Informazioni generali sul file fisico.
{
"filename": "sample_pointcloud.las",
"filepath": "/path/to/data/sample_pointcloud.las",
"file_size_mb": 125.50
}Versione LAS e formato dei punti.
{
"las_version": "1.2",
"point_format": 3,
"point_count": 8536817
}Cosa significano:
las_version: Versione dello standard LAS (1.0, 1.2, 1.4). Letto daheader.versionpoint_format: ID del formato punto (0-10). Formato 3 = GPS time + RGB colorpoint_count: Numero totale di punti nella nuvola
Caratteristiche intrinseche della nuvola di punti.
{
"num_points": 8536817,
"return_types": {
"return_1": 8499494,
"return_2": 37323
},
"classification": {
"Unclassified": 8536817
},
"intensity_range": {
"min": 0,
"max": 65280,
"mean": 24156.78,
"std": 18932.45
},
"scan_angle_info": null
}Cosa significano:
return_types: Quanti punti sono first return, second return, ecc. (punti che rimbalzano una o più volte)classification: Distribuzione punti per classe (Ground=terreno, Building=edificio, Vegetation=vegetazione). Se tutti "Unclassified" = no processingintensity_range: Valore di riflessività laser (0-65535). Range ampio = buona qualità sensore.meanestdsono media e deviazione standard
Sistema di coordinate e georeferenziazione.
{
"scale": [0.001, 0.001, 0.001],
"offset": [500000.0, 4600000.0, 100.0],
"bounds": {
"x": {"min": 500000.0, "max": 500150.0},
"y": {"min": 4600000.0, "max": 4600120.0},
"z": {"min": 100.0, "max": 135.0}
},
"spatial_extent": {
"x_range": 150.0,
"y_range": 120.0,
"z_range": 35.0
}
}Cosa significano:
scale: Moltiplicatore per convertire coordinate intere in float. Valori piccoli (0.0001) = maggiore precisione. Formula reale:valore_float = valore_grezzo * scale + offsetoffset: Base per le coordinate. Esempi: 431364.69 è probabilmente in UTM (geografico)bounds: Limiti geografici della nuvola (bounding box). I valori X, Y sono coordinate geografiche (UTM), Z è altezzaspatial_extent: Dimensioni nuvola in metri sui tre assi (72m × 73m × 10.8m)
Informazioni temporali.
{
"gps_time_range": {
"min": 1234567890.123,
"max": 1234567920.456
},
"file_creation_date": "2025-021"
}Cosa significano:
gps_time_range: Istante GPS (in secondi della settimana GPS). Se presente = acquisizione GNSS sincronizzatafile_creation_date: Data creazione file. FormatoYYYY-DDD(anno e giorno dell'anno)
Tracce di software generatore.
{
"system_identifier": "LASzip",
"generating_software": "LASzip DLL 3.4 r3 (191111)",
"detected_software": null
}Cosa significano:
system_identifier: Identifica il sistema/hardware che ha creato il file. Letto daheader.system_identifiergenerating_software: Software che ha generato/modificato il file. "LASzip DLL" significa che il file è stato compresso con l'algoritmo LASzip (perdita o no di dati)- Se fosse "CloudCompare v2.11" → file elaborato con CloudCompare
- Se fosse "DJI" → drone DJI
- Se fosse "FARO" → scanner terrestre FARO
detected_software: Nome decodificato del software (es. "CloudCompare", "FARO", "DJI")
Informazioni sul sistema di coordinate e georeferenziazione.
{
"georeferenced": true,
"has_gps_time": true,
"gps_time_type": "GPS Week Time",
"has_geo_keys": true,
"epsg_code": "EPSG:32633",
"crs_wkt": "PROJCS[\"WGS 84 / UTM zone 33N\",GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223...]"
}Cosa significano:
georeferenced:truese il file contiene informazioni di georeferenziazione (non solo coordinate relative)has_gps_time:truese i punti hanno timestamp GPS (sincronizzazione temporale)gps_time_type: "GPS Week Time" (secondi dalla settimana GPS) o "GPS Standard Time (UTC)"has_geo_keys:truese contiene GeoKey records (metadati geografici)epsg_code: Codice EPSG del sistema di coordinate. Es:EPSG:32633= WGS 84 / UTM zone 33N (vedi sopra)EPSG:7030= Definisce i parametri dell'Ellissoide utilizzato (non delle coordinate, ne delle proiezioni).
EPSG:4326= WGS 84 lat/lonEPSG:3857= Web Mercator
crs_wkt: Well-Known Text (WKT) - Descrizione completa del sistema di coordinate in formato testuale standardizzatoPROJCS= Projected Coordinate SystemGEOGCS= Geographic Coordinate SystemDATUM= Datum (es. WGS_1984)SPHEROID= Ellissoide (es. WGS 84 con semiasse 6378137m e eccentricità 298.257223)UTM zone 33N= Proiezione UTM fascia 33 emisfero Nord
{
"is_post_processed": true,
"detected_software_chain": [
{
"software": "CloudCompare",
"field": "generating_software",
"typical_operations": ["merge", "subsample", "classification", "registration"]
}
],
"processing_indicators": [
"Non-standard scale factors",
"Multiple classification classes (5) - likely classified",
"Custom VLR found (ID: 2048)"
],
"anomalies": [
"High precision offset in X: 431364.6939545541",
"File Source ID is 0 (often reset during processing)"
],
"primary_processor": "CloudCompare"
}Cosa significano:
-
is_post_processed:truese il file è stato elaborato dopo la scansione iniziale. Indica modifiche, merge, classificazione automatica, ecc. -
detected_software_chain: Lista di software che hanno toccato il file in sequenza- Campo
field: Dove è stata trovata l'informazione (header.system_identifier o header.generating_software) typical_operations: Cosa tipicamente fa quel software (merge = fusione nuvole, subsample = decimazione, classification = classificazione automatica)
- Campo
-
processing_indicators: Indizi di elaborazione rilevati- "Non-standard scale factors" = Scale/offset irregolari (tipico CloudCompare)
- "Multiple classification classes (5) - likely classified" = Punti sono stati classificati (Ground, Building, Vegetation, ecc.)
- "Custom VLR found (ID: 2048)" = Record personalizzato aggiunto (Variable Length Record)
-
anomalies: Anomalie nel file che suggeriscono modifiche- "High precision offset in X: 431364.69..." = Offset con molti decimali (CloudCompare spesso fa questo)
- "File Source ID is 0" = ID sorgente azzerato (common when re-exporting)
-
primary_processor: Il software che probabilmente ha POST-PROCESSATO il file (es. CloudCompare, LAStools, PDAL)
Tipo di sensore inferito.
{
"characteristics": [
"high_intensity_resolution",
"rgb_data_present"
],
"detected_sensor": null,
"inferred_sensor_types": [
{
"sensor_type": "Terrestrial Laser Scanner (TLS)",
"confidence": 82.5,
"examples": ["Leica BLK360", "FARO Focus", "Riegl VZ-400"]
},
{
"sensor_type": "Mobile LiDAR (MLS)",
"confidence": 65.3,
"examples": ["Velodyne HDL-64E", "Ouster OS1-128"]
}
]
}Cosa significano:
-
characteristics: Proprietà rilevate nei datihigh_intensity_resolution= Range intensità > 1000 (buon sensore)rgb_data_present= Punti contengono colore RGBmulti-return_capable= Sensore può rilevare multipli rimbalzinir_data_present= Canale Near Infrared presente
-
detected_sensor: Se esplicitamente scritto nel metadata (es. "DJI", "Leica").nullse non trovato -
inferred_sensor_types: Lista ordinata per confidenza del tipo di sensore probabile, basata su:- Densità punti (punti/m³)
- Accuratezza stimata (dalla scala)
- Range massimo (dalle dimensioni bounding box)
- Presenza RGB/NIR
- Numero di returns
Ogni voce contiene:
sensor_type: Categoria di sensoreconfidence: Percentuale di compatibilità (0-100%)examples: Modelli reali di quel sensore
"vlr_records": [
{
"record_id": 34735,
"user_id": "TIFF",
"description": "GeoKeyDirectoryTag"
},
{
"record_id": 2112,
"user_id": "LASF_Projection",
"description": "OGC Well Known Text (WKT)"
},
{
"record_id": 2048,
"user_id": "CloudCompare",
"description": "Custom metadata"
}
]Cosa sono: Record metadati extra aggiuntivi nel file LAS. Si trovano dopo l'header standard.
| ID | Significato |
|---|---|
| 34735 | GeoKeyDirectoryTag - Contiene chiavi di georeferenziazione |
| 34736 | GeoDoubleParamsTag - Parametri georeferenziazione double-precision |
| 2112 | OGC Well-Known Text - Descrizione CRS in formato WKT |
| 2048+ | Custom/Privati - Aggiunti da software (es. CloudCompare) |
Importanza: VLR personalizzati (ID > 100) indicano che il file è stato POST-PROCESSATO
"anomalies": [
"Unusual scale values (> 1.0)",
"Non-uniform scales: [0.1, 0.1, 0.001]",
"High precision offset in X: 431364.6939545541",
"File Source ID is 0 (often reset during processing)"
]Significato: Indicatori che il file è stato modificato dopo la scansione originale.
- Scale anomale = CloudCompare spesso crea scale strane
- Offset alta precisione = Non standard, suggerisce post-processing
- File Source ID = 0 = Resettato durante re-export
"processing_indicators": [
"Custom VLR found (ID: 2048)",
"All points classified as Ground",
"Multiple classification classes (5) - likely classified",
"GPS time removed or zeroed"
]Significato: Azioni di processing rilevate sulla nuvola.
- Custom VLR = Software ha aggiunto dati personalizzati
- Uniform classification = Filtro applicato (es. solo terreno estratto)
- Molte classi = File è stato classificato (automated o manuale)
- GPS time zeroed = Timestamp rimosso
PROJCS["WGS 84 / UTM zone 33N",
GEOGCS["WGS 84",
DATUM["WGS_1984",
SPHEROID["WGS 84",6378137,298.257223563]
],
PRIMEM["Greenwich",0],
UNIT["degree",0.0174532925199433]
],
PROJECTION["Transverse_Mercator"],
PARAMETER["latitude_of_origin",0],
PARAMETER["central_meridian",15],
PARAMETER["false_easting",500000],
PARAMETER["false_northing",0],
UNIT["metre",1]
]Cosa è: Standard testuale per descrivere qualsiasi sistema di coordinate geografico.
Componenti:
- PROJCS = Projected Coordinate System (coordinate piane, non geografiche)
- GEOGCS = Geographic Coordinate System base (lat/lon)
- DATUM = Modello della terra (WGS_1984 è lo standard GPS)
- SPHEROID = Ellissoide (forma della terra)
6378137= semiasse maggiore (6378.137 km, raggio all'equatore)298.257223563= inverse flattening (eccentricità)
- PROJECTION = Tipo proiezione (Transverse_Mercator per UTM)
- PARAMETERS = Parametri proiezione
central_meridian=15= meridiano centrale fascia 33
- UTM zone 33N = Fascia 33, emisfero Nord
In pratica: "Le coordinate sono in UTM (proiezione piana), fascia 33N, basate su WGS84"
"generating_software": "LASzip DLL 3.4 r3 (191111)"Cosa significa:
- LASzip = Software/libreria di compressione LAS
- DLL = Dynamic Link Library (è una libreria, non l'applicazione principale)
- 3.4 = Versione
- r3 = Revision 3
- (191111) = Data di build (2019-11-11)
Interpretazione:
- ❌ NON significa "generato da LASzip"
- ✅ Significa "il file è stato compresso/decompresso con LASzip"
- Il vero generatore potrebbe essere CloudCompare, PDAL, o altro software che usa LASzip internamente
- Assieme a
system_identifieraiuta a ricostruire la catena di processing
Altri esempi comuni:
"CloudCompare v2.11.3"= Elaborato con CloudCompare"FARO LS 2023"= Scanner terrestre FARO"DJI Zenmuse L1"= Drone DJI con sensore Zenmuse L1"LAStools by rapidlasso"= Elaborato con LAStools"PDAL 2.4"= Elaborato con PDAL
{
"file_info": {
"filename": "sample_pointcloud.las",
"filepath": "/path/to/data/sample_pointcloud.las",
"file_size_mb": 125.50
},
"header_info": {
"las_version": "1.2",
"point_format": 3,
"point_count": 8536817
},
"punto_cloud_nature": {
"num_points": 8536817,
"return_types": {
"return_1": 8499494,
"return_2": 37323
},
"classification": {
"Unclassified": 8536817
},
"intensity_range": {
"min": 0,
"max": 65280,
"mean": 24156.78,
"std": 18932.45
},
"scan_angle_info": null
},
"coordinate_system": {
"scale": [0.001, 0.001, 0.001],
"offset": [500000.0, 4600000.0, 100.0],
"bounds": {
"x": {"min": 500000.0, "max": 500150.0},
"y": {"min": 4600000.0, "max": 4600120.0},
"z": {"min": 100.0, "max": 135.0}
},
"spatial_extent": {
"x_range": 150.0,
"y_range": 120.0,
"z_range": 35.0
}
},
"temporal_info": {
"gps_time_range": {
"min": 1234567890.123,
"max": 1234567920.456
},
"file_creation_date": "2025-021"
},
"software_metadata": {
"system_identifier": "LASzip",
"generating_software": "LASzip DLL 3.4 r3 (191111)",
"detected_software": null
},
"georeferencing": {
"georeferenced": true,
"coordinate_reference_system": null,
"epsg_code": "EPSG:32633",
"has_gps_time": true,
"gps_time_type": "GPS Week Time",
"has_geo_keys": true,
"crs_wkt": "PROJCS[\"WGS 84 / UTM zone 33N\",GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223...]"
},
"processing_history": {
"is_post_processed": false,
"detected_software_chain": [],
"processing_indicators": [],
"anomalies": [
"File Source ID is 0 (often reset during processing)"
]
},
"sensor_type": {
"detected_sensor": null,
"characteristics": ["multi-return_capable", "high_intensity_resolution", "rgb_data_present"],
"inferred_sensor_types": [
{
"sensor_type": "Terrestrial Laser Scanner (TLS)",
"confidence": 78.5,
"examples": ["Leica BLK360", "FARO Focus", "Riegl VZ-400"]
},
{
"sensor_type": "Mobile LiDAR (MLS)",
"confidence": 65.3,
"examples": ["Velodyne HDL-64E", "Ouster OS1-128"]
}
]
}
}Modifica questo file per aggiungere o modificare i profili di sensori LiDAR.
Aggiungi nuove firme software per rilevare ulteriori strumenti di processing.
Personalizza la mappa delle classificazioni LAS.
- Acquisizione: Sensore LiDAR acquisisce nuvola di punti
- Export iniziale: Software sensore esporta in LAS
- Header contiene
generating_software= "DJI" o "Leica" o "Riegl"
- Header contiene
- Post-processing (opzionale): Utente elabora con CloudCompare
- Header
generating_softwareora = "CloudCompare v2.11" - Vengono aggiunti VLR personalizzati
- Punti potrebbero essere classificati, filtrati, merged
- Header
- Export finale: File salvato
- Se compresso,
generating_software= "LASzip DLL" processing_historymostra la catena di elaborazioni
- Se compresso,
Questo script ricostruisce questa storia leggendo il file!