Example notebooks¶
One notebook per stage of a TLS workflow, three more on change between epochs, airborne lidar and full waveforms, one on the synthetic data the others check themselves against, and one on buttressed trees. Most of them run on a real scan: a 20 × 20 m tile of the TERN Litchfield Savanna SuperSite plot in the Northern Territory, scanned in 2021 with a RIEGL VZ-2000i from many positions and registered into one cloud.
| File | What | Size |
|---|---|---|
data/litch_tile.laz |
1.55 M echoes inside the tile, thinned to 5 cm, with classification (2 ground, 4 vegetation) and intensity |
6 MB |
data/litch_tile_shots.parquet |
626 k pulses, every 40th ray clipped to the tile, misses included | 6 MB |
make_litch_subset.py cuts both from the plot's ray cloud. Rays are clipped at
the tile boundary, so a ray that ends inside keeps its echo and a ray that
passes through becomes a pulse with no return. That preserves free space inside
the tile. One scan position falls in the tile's corner and keeps its true
origin, but the rest of the pulses start where they crossed the boundary, so
the tile carries everything point-based while sylva.synthetic is kept for the
cases where the answer has to be known: registration with a known transform,
a QSM and leaf area against a tree's own cylinders and leaves, and leaf area
density, leaf angles and gap fraction against a known stand. These scenes
come from synthetic.tree_model and synthetic.plot, scanned by
synthetic.scan with a beam footprint, range noise and mixed pixels
(notebook 17).
The buttress notebook (18) uses two other real clouds instead: single trees from
the destructive-harvest data of Burt et al. (2021), cut by
make_buttress_subset.py (see the data README).
| File | What | Size |
|---|---|---|
data/buttress_tree.laz |
the whole of a 46 m tree with a flanged base: 1.04 M points, 1 cm up to 6 m and 5 cm above | 3 MB |
data/round_tree.laz |
the lowest 8 m of a tree with a round stem, 41 k points at 1 cm | 0.1 MB |
What real data shows that a synthetic scene cannot is worth reading. Two examples the notebooks work through: the cloth simulation filter puts the terrain metres too high in 8 % of the tile's cells, all of them within about 2 m of the cut edge, because a cloth needs points on both sides to be pulled down -- so classify ground on the whole plot and crop afterwards; and the statistical outlier filter removes 4 % of the cloud, two thirds of it below 1 m, because a sparse grass layer looks like noise by that test.
| Notebook | Data | Covers | |
|---|---|---|---|
| 1 | Point clouds and I/O | tile | PointCloud, attributes, indexing, LAZ / PLY / text |
| 2 | Filtering | tile | subsampling, crops, outlier removal, planarity / linearity, clustering |
| 3 | Registration | synthetic | two scans of a synthetic plot: Kabsch from targets, point-to-point and point-to-plane ICP, trimming on partial overlap, merging |
| 4 | Ground and height | tile | CSF and PMF ground filters, DTM, height normalisation, CHM |
| 5 | Trees | tile | stem detection and DBH, segmentation, heights, crowns, taper |
| 6 | QSMs | both | leaf / wood separation, cylinder models, volumes, mesh export |
| 7 | Canopy structure | both | voxel occupancy, contact-frequency PAD, gap fraction and effective PAI |
| 8 | Pulses and shots files | tile | Shots, misses, conversions, the Parquet shots format |
| 9 | Ray-traced voxels | both | attenuation, PAD / LAD / WAD, leaf angles, wood volume, .vox, streaming |
| 10 | A RIEGL project, end to end | full plot | every stage on one hectare straight from the .rxp files: read, ground, trees, scan quality, QSMs and leaves, gap profile, voxels, sampling |
| 11 | Coordinates | tile | CRS in LAS headers, reprojection and its warnings, translate / rotate / recentre, apply_transforms on scans |
| 12 | Interpolation | tile | labels from a thinned copy, TIN / natural-neighbour / IDW DTMs, rasters sampled onto points |
| 13 | Masking | tile | polygons from GeoJSON, raster masks, attribute expressions, change between two clouds |
| 14 | Change detection | synthetic | two epochs with known changes: alignment on stems and ground, tree matching, DBH increments and their detection limits, plot summary, C2C and M3C2, CHM differences, voxel occupancy, QSM change |
| 15 | Airborne lidar | synthetic | a simulated flight written as tiles: catalogue, ground, DTM, CHM, area-based metrics, individual trees against the known stand, pulses from the trajectory, gap profiles and ray-traced PAI against a known layer |
| 16 | Full waveforms | synthetic | waveforms of known targets, LAS wave packets written and read, Gaussian decomposition against the truth, echoes as pulses for ray-traced voxels |
| 17 | Synthetic data | synthetic | tree archetypes and their truth (cylinders, leaves, leaf angles), a mixed stand with understorey and dead wood, a finite-beam scan and where its mixed pixels fall |
| 18 | Buttresses | two real trees | 3D views of the points, detecting a flanged base, rebuilding it as a closed mesh, the cylinder model it replaces, one fused mesh of the whole tree |
The numbers the notebooks print describe this one tile and are not validation. Accuracy against reference plots, felled trees and independent instruments is on the benchmark pages.
To run them yourself:
pip install -e '.[examples]' # matplotlib and jupyter
jupyter lab docs/examples
They are generated from docs/examples/build_notebooks.py; edit that file and
run it to regenerate and re-execute them (python docs/examples/build_notebooks.py
05_trees for one).
The figures share one style, sylva.mplstyle in the same folder, which the
first cell of each notebook loads: fixed figure widths and font sizes, the
colour-blind-safe Okabe-Ito palette for categories, viridis for magnitudes,
and a diverging map centred on zero for signed differences. Ground, wood,
leaves and grass keep the same colours in every notebook. Copy the file
alongside a notebook to run it elsewhere.
The tile is derived from TERN data, distributed here for documentation and
teaching. Cite TERN if you use it for anything else, and see
data/README.md.
Notebook 10 is different: it reads a whole RiSCAN PRO project, the TERN
Litchfield core hectare (64 VZ-2000i positions, 35 GB), so it needs RiVLib,
the project on disk and about 40 GB of memory, and is run by hand with
build_riscan_notebook.py rather than by build_notebooks.py. Point
PROJECT at your own project and PLOT at its extent to run it elsewhere.