This package provides a workflow for training and applying a Superpoint Transformer (SPT) to classify point clouds by semantic class. The four modules clfSPTSetup, clfSPTPreprocess, clfSPTTrain, and clfSPTInfer cover the full workflow from training on labelled tiles to creating a trained model and applying it to new, unlabelled data.

General description

The integration of SPT in OPALS follows two separate workflows that share a common preprocessing step.

Fig. 1 Overall workflow of the Superpoint Transformer integration in OPALS

Workflow A (Training)

In this workflow, the model is trained on labelled point cloud data using the following scripts:

  • clfSPTSetup creates a project directory which serves as the working environment for all subsequent steps. Furthermore, it analyses the input tiles, distributes them into train/validation/test splits, and generates the project configuration files.
  • clfSPTPreprocess produces the hierarchical partition structure (Nested Acyclic Graph - NAG) on which the model is trained. Raw point clouds are partitioned into increasingly coarser superpoint hierarchies that respect semantic class boundaries based on geometric features. clfSPTTrain can do this on-the-fly without using clfSPTPreprocess, which is useful for automated parameter studies.
  • clfSPTTrain trains the model and writes a self-contained run directory. This includes the trained model (checkpoint), the configuration files used for inference (ensuring identical preprocessing parameters), and the evaluation metrics. This run directory can be directly used to classify other point cloud datasets.

Attribute computation

Unlike the tree-based classification (Tree Based Classification), SPT does not rely on a fixed, externally precomputed feature set. Most geometric features it uses (linearity, planarity, scattering, verticality, and elevation) are computed internally as part of the model's own partitioning pipeline (see clfSPTPreprocess) and require no separate OPALS preprocessing step.

A small number of attributes can optionally be derived beforehand with dedicated OPALS modules: NormalX/Y/Z (Module Normals) and EchoRatio (Module EchoRatio) can be computed explicitly to make them available as model features. Elevation can likewise be sourced from a precomputed NormalizedZ attribute (AddInfo) instead of SPT's internal ground estimation. See Feature detection in clfSPTSetup for the full list and how detected/available attributes are matched to model features. Non geometric features like : intensity/RGB/reflectance are picked up automatically if present.

How to create training data?

Due to the lack of an interactive 3D point cloud editor, it is currently not possible to visually create training data within OPALS. However, several commercial and open source software packages (e.g. \href{http://www.meshlab.net/}{MeshLab}, \href{http://www.danielgm.net/cc/}{CloudCompare}, etc.) exist for this task. The labelled point cloud can then be merged back into the corresponding ODM files (or exported as LAS/LAZ with a populated classification attribute) and directly processed with clfSPTSetup.

Workflow B (Inference)

In this workflow, a produced run directory or a pre-trained model is applied to unlabelled data:

  • clfSPTPreprocess produces the NAG structure beforehand. Different to workflow A, in this orkflow this step is mandatory. The pre-transform parameters must always come from the model bundle as they form an integral part of the model.
  • clfSPTInfer runs the actual classification on the superpoint level (partition level 1), projects the result back onto every original point and writes the predicted class back into the input file. If ground truth labels are present, accuracy metrics and a confusion matrix are generated automatically.

Influence of outliers

Raw point clouds from ALS or dense image matching usually contain outliers. Their characteristics and amount differ based on the measurement principle and sensor. In ALS such outliers are often called long or short ranges, since they are obviously not reflected from either the bare Earth or from any other natural (vegetation) or artificial (buildings, power lines) target.

Any gross error distorts the geometric features computed within its vicinity. For SPT this affects the k-nearest-neighbor graph, the local geometric features (linearity, planarity, scattering, verticality) and, downstream, the Cut-Pursuit partitioning itself (see clfSPTPreprocess). Since these features drive both the superpoint partitioning and the semantic classification, outlier contamination here can degrade results more broadly than in a per-point classifier: a single gross error can corrupt the neighborhood features of many surrounding points, and if it distorts a superpoint's shape enough, it can pull that entire superpoint (and everything merged into it) toward an incorrect classification.

Practical tests have shown that classification accuracies are usually better for point clouds where outliers have been removed in advance. A detailed discussion on efficient outlier detection is omitted here, detecting isolated points (e.g. via AddInfo) and applying a coarse DTM/DSM to filter implausible heights is generally sufficient to solve this task before running clfSPTInfer.

Examples

Data preparation

As a prerequisite, the demo tile is imported and cut into sub-tiles of 265x200 m so that a small training set with multiple tiles can be created from a single scene.

opalsImport -inf niederrhein.laz
preTiling -vector niederrhein.odm -tilesize 265 200 -skip False
preCutting -vector niederrhein.odm -shapefile Tiles.shp -skip False -export niederrhein_subtiles/niederrhein

Project setup

clfSPTSetup distributes the sub-tiles into train/val/test splits and generates the project configuration. The class mapping must be defined beforehand by renaming the generic Classification attribute values to semantic labels (see Setup configuration and Setup examples for details on the interactive remapping dialog).

clfSPTSetup.py -inFile niederrhein_subtiles/*.odm -projectDir niederrhein_project -trainRatio 0.7 -valRatio 0.2 -SkipInteractiveMapping True
Available attributes: ['Amplitude', 'Classification', 'ClassificationFlags', 'EchoNumber', 'EdgeOfFlightLine', 'FileId', 'GPSTime', 'Id', 'LayerId', 'NrOfEchos', 'PointSourceId', 'ScanAngle', 'ScanDirection', 'StructNr', 'UserData', 'WinputCode', '_EchoWidth', '_Reflectance']
Class distribution per split (total; 1,963,378 points):
- train (855,199 pts, 43.6% of total): 2:408462(47.8%), 5:233288(27.3%), 6:18365(2.1%), 8:7140(0.8%), 9:140086(16.4%), 11:25693(3.0%), 14:7198(0.8%), 16:2467(0.3%), 18:6178(0.7%), 30:1744(0.2%), 31:4578(0.5%)
- val (575,738 pts, 29.3% of total): 2:301376(52.3%), 5:226099(39.3%), 6:28638(5.0%), 8:2964(0.5%), 9:186(0.0%), 11:9093(1.6%), 14:4160(0.7%), 16:744(0.1%), 18:876(0.2%), 30:1600(0.3%), 31:2(0.0%)
- test (532,441 pts, 27.1% of total): 2:289071(54.3%), 5:222549(41.8%), 6:2332(0.4%), 8:4123(0.8%), 9:3644(0.7%), 11:7711(1.4%), 14:123(0.0%), 16:2(0.0%), 18:1417(0.3%), 30:27(0.0%), 31:1442(0.3%)
Classes: 10
train: 9 tiles
val : 2 tiles
test : 1 tiles

The per-split class distribution above illustrates why reviewing this output is worthwhile before training. Most classes (2, 5, 6, 8, 11, 14, 18, 30) keep a broadly similar share of points across train, val, and test, which is what a representative split looks like. Classes 9, 16, and 31, however, are unevenly distributed: class 9 drops from 11.3% of the train split to 3.3% in val and just 0.8% in test; class 31 similarly falls from 0.5% in train to 0.1% in val and is essentially absent from test (2 out of 348,531 points); class 16 is reduced to a single point in val and is completely absent from test.Metrics reported for class 16 on the test split are therefore not meaningful, there is nothing there to measure against. Note also that the resulting split ratio (56.4/25.8/17.7%) does not match the requested -trainRatio/-valRatio exactly, since clfSPTSetup distributes whole tiles rather than individual points, and tiles vary considerably in point count. When a class is this sparse, either merging it with a related class during the interactive class mapping, or adjusting the split ratios or tile selection to secure a few more tiles containing it, is recommended before proceeding to clfSPTPreprocess and clfSPTTrain.

Partition preview

Before processing the full dataset, clfSPTPreprocess can be run on a single tile with -view True to visually inspect partition quality and feature computation. See Preprocess training mode for a detailed discussion of partition parameters and oracle metric interpretation.

clfSPTPreprocess -projectDir niederrhein_project -mode train -tile niederrhein_project/data/raw/val/niederrhein_351390_566500.odm

Fig. 2 Semantic classes

Level 1 partition

Level 2 partition

Level 3 partition
num_points (mean per level): [277288, 14436, 3297, 727]
|P_0| / |P_1|: 19.2
|P_1| / |P_2|: 4.4
|P_2| / |P_3|: 4.5
Partition oracle (upper bound with this partition):
mIoU: 74.5 OA: 96.2 mAcc: 77.4

Full preprocessing

Once the partition quality is satisfactory, all tiles are preprocessed at once. The cached NAGs are reused across multiple training runs with different hyperparameters.

clfSPTPreprocess -projectDir niederrhein_project -mode train

Training

clfSPTTrain reads the .cfg, trains the model for the configured number of epochs, and evaluates the best checkpoint on the test split. See Train hyperparameters for details on training parameters.

clfSPTTrain -projectDir niederrhein_project -sweep "trainer.max_epochs=50"
Test metrics:
- test/iou_Building: 82.21
- test/iou_Class_30: 0.00
- test/iou_Class_31: 0.00
- test/iou_Ground: 91.09
- test/iou_High Vegetation: 93.39
- test/iou_Reserved: 42.99
- test/iou_Road Surface: 12.78
- test/iou_Water: 72.64
- test/iou_Wire - Conductor: 75.46
- test/iou_Wire-Structure Connector: 0.00
- test/loss: 0.82
- test/macc: 54.91
- test/miou: 47.06
- test/oa: 94.32

After 400 epochs, the model reaches a test mIoU of ~51.6% (OA 92.3%). Classes with abundant training points (Ground, High Vegetation, Wire - Conductor) are learned reliably, with per-class IoU above 75%. Classes with very few training samples (Groyne, Road Surface, Wall) remain close to 0% IoU — this is expected for a demo dataset of this size, where rare classes are represented by too few points/tiles to be learned robustly. The confusion matrix exported alongside the metrics identifies exactly which classes these predictions are confused with, which is the recommended next step when investigating low per-class scores (see Confusion matrix in the Train module documentation).

Note
This automated test run is limited to 50 epochs (via -sweep) to keep it fast. The results reported above (test metrics, confusion matrix) come from a full 400-epoch run using the project's default .cfg settings (clfSPTTrain -projectDir niederrhein_project, without the -sweep override) and are not representative of what a 50-epoch test run would produce.

Inference

To classify new data, the tile is first preprocessed with mode=infer using the frozen transforms from the training run, then classified with clfSPTInfer. -tileSize 0 disables sub-tiling. See Infer examples for details on model loading and output handling.

clfSPTPreprocess -mode infer -runDir niederrhein_project\*latest -tile niederrhein.odm -tileSize 200
clfSPTInfer -runDir niederrhein_project\*latest -tile niederrhein.odm

Running inference on the full niederrhein.odm tile (1.9M points) as a single, unsplit NAG (-tileSize 0) versus splitting it into 200 m sub-tiles (-tileSize 200) with a 10 m buffer produces markedly different results, both in processing time and prediction quality: | | No sub-tiling (-tileSize 0) | Sub-tiling (-tileSize 200) |

no sub-tiling | sub-tiling
| Preprocessing time | ~15 min | ~4 min |
| Test OA | 85.6% | 91.9% |
| Test mIoU | 39.6% | 58.9% |
| Test mAcc | 47.1% | 71.2% |

Sub-tiling is not only substantially faster than building one very large graph over the entire point cloud at once but also produces clearly better predictions across nearly every class:

No sub-tiling IoU (%) | sub-tiling IoU (%)
| Ground | 81.0 | 87.5 |
| High Vegetation | 80.1 | 90.6 |
| Building | 13.4 | 74.9 |
| Reserved | 8.3 | 28.5 |
| Water | 78.1 | 96.3 |
| Road Surface | 1.2 | 22.6 |
| Wire-Conductor | 93.0 | 96.8 |
| Wire-Structure Connector | 41.0 | 55.1 |

References

@ tiling
flat tiling structure
@ tile
flat tiling structure
opalsImport is the executable file of Module Import
Definition: ModuleExecutables.hpp:128
@ test
test exceptions are thrown if the common parameter testErrorProbability is activated
Definition: c++_api/inc/opals/Exception.hpp:59
@ vector
General vector data file (las, shp, ..)