process_tree_data: Obtain tree information by processing point cloud data

View source: R/PostProcess_TreeLocations.R

process_tree_dataR Documentation

Obtain tree information by processing point cloud data

Description

process_tree_data processes the output of get_raster_eigen_treelocs and segment_graph to add information about the height, crown area, and diameter for each unique TreeID. It also has an optional parameter to return an sf object representing the convex hulls for each tree.

Usage

process_tree_data(treeData, segmentedLAS, return_sf = FALSE)

Arguments

treeData

An sf object containing the following tree information: TreeID, X, Y, Z, Radius, and Error, output from the get_raster_eigen_treelocs function.

segmentedLAS

A LAS object that is the output from segment_graph.

return_sf

logical: If TRUE, returns an sf object representing the convex hulls for each tree.

Details

For terrestrial and mobile lidar datasets, tree locations and estimates of DBH are provided by rasterizing individual point cloud values of relative neighborhood density (at 0.3 and 1 m radius) and verticality within a slice of the normalized point cloud around breast height (1.34 m). The algorithm then uses defined threshold values to classify the resulting rasters and create unique polygons from the resulting classified raster. These point-density and verticality polygons were selected by their intersection with one another, resulting in a final set of polygons which were used to clip out regions of the point cloud that were most likely to represent tree boles. A RANSAC cylinder fitting algorithm was then used to estimate the fit of a cylinder to individual bole points. Cylinder centers and radius were used as inputs to an individual tree segmentation.

Value

sf object An updated sf object with the original columns plus:

height

numeric: Height of the highest point for each TreeID.

crown_area

numeric: Area of the convex hull for each TreeID.

diameter

numeric: Diameter of the tree, calculated as twice the Radius.

If return_sf is TRUE, also returns an sf object representing the convex hulls for each tree.

Examples


## Not run: 
# Set the number of threads to use in lidR
set_lidr_threads(8)

# Download and read an example laz
getExampleData("DensePatchA")
LASfile = system.file("extdata", "DensePatchA.laz", package="spanner")
las = readTLSLAS(LASfile, select = "xyzcr", "-filter_with_voxel 0.01")
# Don't forget to make sure the las object has a projection
projection(las) = sp::CRS("+init=epsg:26912")

# Pre-process the example lidar dataset by classifying the ground points
# using lidR::csf(), normalizing it, and removing outlier points
# using lidR::ivf()
las = classify_ground(las, csf(sloop_smooth = FALSE,
                                class_threshold = 0.5,
                                cloth_resolution = 0.5, rigidness = 1L,
                                iterations = 500L, time_step = 0.65))
las = normalize_height(las, tin())
las = classify_noise(las, ivf(0.25, 3))
las = filter_poi(las, Classification != LASNOISE)

# Plot the non-ground points, colored by height
plot(filter_poi(las, Classification != 2), color = "Z")

# Perform a deep inspection of the las object. If you see any
# red text, you may have issues!
las_check(las)

# Find individual tree locations and attribute data
myTreeLocs = get_raster_eigen_treelocs(las = las, res = 0.05,
                                       pt_spacing = 0.0254,
                                       dens_threshold = 0.2,
                                       neigh_sizes = c(0.333, 0.166, 0.5),
                                       eigen_threshold = 0.5,
                                       grid_slice_min = 0.6666,
                                       grid_slice_max = 2.0,
                                       minimum_polygon_area = 0.025,
                                       cylinder_fit_type = "ransac",
                                       max_dia = 0.5,
                                       SDvert = 0.25,
                                       n_pts = 20,
                                       n_best = 25)

# Plot the tree information over a CHM
plot(lidR::grid_canopy(las, res = 0.2, p2r()))
points(myTreeLocs$X, myTreeLocs$Y, col = "black", pch = 16,
       cex = myTreeLocs$Radius^2 * 10, asp = 1)

# Segment the point cloud
myTreeGraph = segment_graph(las = las, tree.locations = myTreeLocs, k = 50,
                             distance.threshold = 0.5,
                             use.metabolic.scale = FALSE,
                             ptcloud_slice_min = 0.6666,
                             ptcloud_slice_max = 2.0,
                             subsample.graph = 0.1,
                             return.dense = FALSE)

# Plot it in 3D colored by treeID
plot(myTreeGraph, color = "treeID", pal=spanner_pal())

# Process the data
processed_data <- process_tree_data(myTreeLocs, myTreeGraph, return_sf = TRUE)

# Print the processed data
print(processed_data$data)
# Print the sf object if return_sf is TRUE
if (!is.null(processed_data$sf)) {
  print(processed_data$sf)
}

## End(Not run)


bi0m3trics/spanner documentation built on June 9, 2025, 3:57 p.m.