8 Quantitative Structure Forest
A Quantitative Structure Model (QSM) is a three-dimensional representation of a single individual tree that explicitly describes its geometry and topology (stems, branches, radii, volumes). QSMs provide a physically meaningful model, rather than a purely statistical description.
In this book, we extend this concept from individual trees to entire forests by introducing the Quantitative Structure Forest (QSF). A QSF is a coherent collection of QSMs that together reconstruct the three-dimensional structure of all trees within a forested area.
This conceptual extension is made possible by our advances in QSM algorithms that are fast and robust enough to reconstruct tens of thousands of trees, enabling full 3D modelling of forests spanning several hectares. The QSF concept bridges the gap between tree-level and forest-level analysis, providing a unified framework to study tree architecture, stand structure, competition, biomass distribution, and canopy organisation within a single 3D representation.
8.1 Building a QSF
Building a QSF is relatively straightforward. Users could simply loop over all trees and compute a QSM for each one. Arbor includes a function, qsf(), that performs this task in parallel and in an optimized manner.
As described in previous chapters, the variable las contains the segmented scene.
qsf = qsf(las)The qsf function is blazingly fast and can produce several hundred QSMs per minute! qsf() computes one QSM per tree but excludes trees that are in the buffer zone (see flag_buffer() in Section 6.6) or that are flagged as low understory (see flag_small_trees() in Section 6.5). This makes sense since flag_* functions are designed to exclude trees for which we cannot obtain good results.
A qsf object is simply a list with an additional class to enable convenient printing and plotting methods. Thus, qsf[[1]] contains a qsm object.
qsf() does not throw any warnings because, on a typical 1/4-hectare plot with 400 saplings and 200 young trees, this would generate at least 600 warnings. This is unmanageable. Indeed, qsm() warns about non-measurable young trees. Instead, all QSMs record a message. Users can call qsf_log() to obtain a summary of troubleshooting.
Be careful: by default, qsf() produces a QSM for every instance taller than 2 m. This can create a large number of QSMs with negligible volume, which is not always desirable. The function provides a parameter to control this threshold e.g. qsf(las, min_height = 4).
8.2 What to Do with a QSF?
8.2.1 3D Rendering
The first thing we can do with a QSF is render it in 3D within R.
plot(qsf, pal = "chocolate4") |> lidR::add_dtm3d(dtm)8.2.2 Tree Map & Volume Inventory
A QSF can also be used to perform complete forest inventories, producing a tree map with detailed information for each tree, such as basal area, volume, height, and other structural attributes.
tm <- qsf_treemap(qsf)8.2.3 Export to 3D Software
The qsf() function includes an option to export all trees into separate folders. Users can also use qsf_write() to export individual trees to formats such as .qsm, .obj, .stl, .ply, .csv or other formats supported by 3D software. For example, Blender can be used as an open-source solution for realistic rendering while CloudCompare can be use for casual rendering.
8.2.4 Reclassifying Wood and Foliage
This feature is experimental; it may or may not be removed in future versions.
Our semantic segmentation is not perfect. It intentionally over-segments in order to ensure that the entire tree branching structure is captured. As a result, this approach produces numerous false positives in foliage (by design) and some false negatives (not by design). The semantic segmentation is therefore not intended for direct scientific use; it is primarily designed to support QSM reconstruction.
With a QSF, it becomes possible to reclassify points based on each individual QSM. This reclassification can be useful for downstream analyses such as estimating Plant Area Index (PAI) or Leaf Area Index (LAI), where a more accurate separation between wood and foliage is required.
las = qsf_segment_semantic(las, qsf)8.2.5 Merchandable Volume
See Chapter 9 for more information about forestry operations.
8.3 Code
8.3.1 Function list
qsf()to build a QSFqsf_write()for saving the QSMs in.obj,.ply.csvor.qsmfor analyzing or for rendering in 3D software.qsf_treemap()for saving forest in GIS vector filesqsf_segment_semantic()for more accurate semantic segmentationqsf_merchantable()(see Chapter 9)plot()for 3D rendering
8.3.2 Full Code
library(lidR)
library(arbor)
params <- arbor_parameters_default
params$global$cut_above_ground = 0.25
filter <- "-keep_random_fraction 0.25"
buffer <- 5
las <- readTLS(file, select = "xyz", filter = filter)
las <- hybrid_homogeneization(las)
las <- segment_ground(las)
las <- wood_likelihood(las, params)
las <- segment_semantic(las, params)
see <- find_seeds(las, params)
las <- segment_instance(las, see, params)
las <- flag_small_trees(las, max_height = 2)
las <- flag_buffer(las, see, -buffer)
qsf <- qsf(las, params = params)
plot(qsf)






