Estimate CBH using tree crown polygons and normalized point cloud data
Source:R/trees_cbh.R
trees_cbh.Rdtrees_cbh() uses the input tree crown polygons (e.g. as exported by raster2trees()) with the columns
treeID and tree_height_m to estimate tree CBH using height normalized point cloud data (e.g. as exported by cloud2raster()).
CBH is extracted directly from the height normalized point cloud using the process outlined in Viedma et al. (2024) and implemented via ladderfuelsr_cbh().
There are likely to be trees for which there is insufficient data in the point cloud to successfully estimate CBH. The user can elect to estimate missing CBH values which is accomplished via:
Attempt to extract CBH from the sample of trees elected by the user (
tree_sample_n,tree_sample_propparameter) usingladderfuelsr_cbh()Successfully extracted CBH trees become training data used to estimate the height-CBH allometry relationship that is spatially informed using the relative tree location compared to the training data
The height and location predicting CBH model built from the point cloud training data is used to predict CBH for the non-training (i.e. missing CBH) data
Usage
trees_cbh(
trees_poly,
norm_las = NULL,
tree_sample_n = NA,
tree_sample_prop = NA,
which_cbh = "lowest",
estimate_missing_cbh = TRUE,
min_vhp_n = 3,
voxel_grain_size_m = 1,
dist_btwn_bins_m = 1,
min_fuel_layer_ht_m = 1,
lad_pct_gap = 25,
lad_pct_base = 25,
num_jump_steps = 1,
min_lad_pct = 10,
frst_layer_min_ht_m = 1,
force_same_crs = F,
outfolder = tempdir()
)Arguments
- trees_poly
must be one of the following that has required attributes
treeIDandtree_height_m:sfclass object with POLYGON geometry (seesf::st_geometry_type()). Recommended for smaller tree lists (e.g. <100k) that can fit in memory.character vector with the path to a single or multiple spatial files that can be read by
sf::st_read()and have POLYGON geometry. Recommended for large tree lists (e.g. 100k+) that might cause memory issues.character with the path to a directory that has "final_detected_crowns*" files from
cloud2trees()orraster2trees(). Recommended for large tree lists (e.g. 100k+) that might cause memory issues.
- norm_las
character. a directory with nomalized las files, the path of a single .laz|.las file", -or- an object of class
LAS. It is your responsibility to ensure that the point cloud is projected the same as thetrees_polydata- tree_sample_n, tree_sample_prop
numeric. Provide either
tree_sample_n, the number of trees, ortree_sample_prop, the proportion of the trees to attempt to extract a CBH from the point cloud for. If neither are supplied,tree_sample_n = 333will be used. If both are supplied,tree_sample_nwill be used. Increasingtree_sample_proptoward one (1) will increase the processing time, perhaps significantly depending on the number of trees in thetrees_polydata.- which_cbh
character. One of: "lowest"; "highest"; or "max_lad". See Viedma et al. (2024) reference.
"lowest" - Height of the CBH of the segmented tree based on the last distance found in its profile
"highest" - Height of the CBH of the segmented tree based on the maximum distance found in its profile
"max_lad" - Height of the CBH of the segmented tree based on the maximum LAD percentage
- estimate_missing_cbh
logical. even if the
tree_sample_propparameter is set to "1", it is not likely that CBH will be extracted successfully from every tree. Should the missing CBH values be estimated using the tree height and location information based on trees for which CBH is successfully extracted?- min_vhp_n
numeric. the minimum number of vertical height profiles (VHPs) needed to estimate a CBH.
- voxel_grain_size_m
numeric. horizontal resolution (suggested 1 meter for lad profiles and 10 meters for LAI maps). See
grain.sizeinleafR::lad.voxels()- dist_btwn_bins_m
numeric. value for the actual height bin step (in meters). See
stepinLadderFuelsR::get_gaps_fbhs()- min_fuel_layer_ht_m
numeric. value for the actual minimum base height (in meters). See
min_heightinLadderFuelsR::get_gaps_fbhs()- lad_pct_gap
numeric. value of the percentile threshold used to identify gaps (default percentile 25th). See
perc_gapinLadderFuelsR::get_gaps_fbhs()- lad_pct_base
numeric. value of the percentile threshold used to identify fuels layers base height (default percentile 25th). See
perc_baseinLadderFuelsR::get_gaps_fbhs()- num_jump_steps
numeric. value for the number of height bin steps that can be jumped to reshape fuels layers. See
number_stepsinLadderFuelsR::get_real_fbh()- min_lad_pct
numeric. value for the minimum required LAD percentage in a fuel layer. See
thresholdinLadderFuelsR::get_layers_lad()- frst_layer_min_ht_m
numeric. value for the depth height of the first fuel layer. If the first fuel layer has the maximum LAD and its depth is greater than the indicated value, then this fuel layer is considered as the CBH of the tree. On the contrary, if its depth is <= the value, the CBH with maximum LAD will be the second fuel layer, although it has not the maximum LAD. See
hdepth1_heightinLadderFuelsR::get_cbh_metrics()- force_same_crs
logical. force the same crs between the point cloud and polygon if confident that data are in same projection. data created by a
cloud2treespipeline (e.g.cloud2raster()) will always have the same projection even if not recognized bylidRfunctions- outfolder
string. The path of a folder to write the model data to. Note, in the actual missing value estimation many RF models are estimated and model averaging is used. However, only the first estimated model is saved in this export which does not fully represent the process used to fill in missing values.
References
https://doi.org/10.1111/2041-210X.14427 Viedma, O., Silva, C. A., Moreno, J. M., & Hudak, A. T. (2024). LadderFuelsR: A new automated tool for vertical fuel continuity analysis and crown base height detection using light detection and ranging. Methods in Ecology and Evolution. https://github.com/olgaviedma/LadderFuelsR
https://doi.org/10.3390/rs11010092 Almeida, D. R. A. D., Stark, S. C., Shao, G., Schietti, J., Nelson, B. W., Silva, C. A., ... & Brancalion, P. H. S. (2019). Optimizing the remote detection of tropical rainforest structure with airborne lidar: Leaf area profile sensitivity to pulse density and spatial sampling. Remote Sensing, 11(1), 92. https://github.com/DRAAlmeida/leafR
Examples
if (FALSE) { # \dontrun{
library(tidyverse)
library(sf)
# example tree crown polygons
f <- system.file(package = "cloud2trees","extdata","crowns_poly.gpkg")
crowns <- sf::st_read(f, quiet = T)
# example normalized las files are in this directory
norm_d <- system.file(package = "cloud2trees","extdata","norm_las")
# now run the trees_cbh()
trees_cbh_ans <- trees_cbh(
trees_poly = crowns
, norm_las = norm_d
, tree_sample_n = 44
, estimate_missing_cbh = T
, force_same_crs = T
)
# what?
trees_cbh_ans %>% class()
trees_cbh_ans %>% dplyr::select(treeID,tidyselect::contains("cbh")) %>% dplyr::glimpse()
# spatial polygons
trees_cbh_ans %>% ggplot2::ggplot() +
ggplot2::geom_sf(ggplot2::aes(fill=tree_cbh_m,color=is_training_cbh))
# relationship between height and cbh
trees_cbh_ans %>%
ggplot2::ggplot(
ggplot2::aes(x = tree_height_m, y = tree_cbh_m, color=is_training_cbh)
) +
ggplot2::geom_point()
# tabulate training data
trees_cbh_ans %>%
sf::st_drop_geometry() %>%
dplyr::count(is_training_cbh)
#### try a file list
#### Recommended for large tree lists (e.g. 100k+) that might cause memory issues.
# we'll split the crowns
# as is done automatically for tree lists >250k by raster2trees() and cloud2trees()
crowns <- crowns %>%
dplyr::mutate(
# makes 2 groups of data
grp = ceiling(dplyr::row_number()/(dplyr::n()/2))
)
# make file names
my_dir <- tempdir()
fnm_1 <- file.path(my_dir, "crowns1.gpkg")
fnm_2 <- file.path(my_dir, "crowns2.gpkg")
fnm_1
# write the data
sf::st_write(crowns %>% dplyr::filter(grp==1), dsn = fnm_1, append = F) # grp 1
sf::st_write(crowns %>% dplyr::filter(grp==2), dsn = fnm_2, append = F) # grp 2
# try trees_cbh with our file list
flist <- c(fnm_1,fnm_2)
# now run the trees_cbh()
trees_cbh_ans2 <- trees_cbh(
trees_poly = flist
, norm_las = norm_d
, tree_sample_n = 44
, estimate_missing_cbh = T
, force_same_crs = T
)
# tabulate training data
trees_cbh_ans2 %>%
sf::st_drop_geometry() %>%
dplyr::count(is_training_cbh)
} # }