Learn R Programming

spanner (version 1.0.2)

get_raster_eigen_treelocs: Obtain tree information by rasterizing point cloud values of relative neighborhood density and verticality within a slice of a normalized point cloud

Description

get_raster_eigen_treelocs returns a data.frame containing TreeID, X, Y, Z, Radius and Error in the same units as the .las

Usage

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.6666,
  grid_slice_min = 0.6666,
  grid_slice_max = 2,
  minimum_polygon_area = 0.025,
  cylinder_fit_type = "ransac",
  max_dia = 0.5,
  SDvert = 0.25,
  n_best = 25,
  n_pts = 20,
  inliers = 0.9,
  conf = 0.99,
  max_angle = 20
)

Value

sf A sf object containing the following tree seed information: TreeID, Radius, and Error in the same units as the .las, as well as the point geometry

Arguments

las

LAS Normalized las object.

res

numeric Pixel width of rasterized point cloud metrics.

pt_spacing

numeric Subsample spacing for graph connections.

dens_threshold

numeric Minimum point density in raster cell to be considered as potential tree bole.

neigh_sizes

numeric Vector for verticality and relative density (small and large neighborhoods) calculations

eigen_threshold

numeric Minimum average verticality in raster cell to be considered as potential tree bole.

grid_slice_min

numeric Lower bound of point cloud slice in normalized point cloud.

grid_slice_max

numeric Upper bound of point cloud slice in normalized point cloud.

minimum_polygon_area

numeric Smallest allowable polygon area of potential tree boles.

cylinder_fit_type

character Choose "ransac" or "irls" cylinder fitting.

max_dia

numeric The max diameter (in m) of a resulting tree (use to eliminate commission errors).

SDvert

numeric The standard deviation threshold below which polygons will be considered as tree boles.

n_best

integer number of "best" ransac fits to keep when evaluating the best fit.

n_pts

integer number of point to be selected per ransac iteraiton for fitting.

inliers

integer expected proportion of inliers among cylinder points

conf

numeric confidence level

max_angle

numeric maximum tolerated deviation, in degrees, from vertical.

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 algorithim 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

Examples

Run this code

# \donttest{
# Set the number of threads to use in lidR
set_lidr_threads(8)

LASfile = system.file("extdata", "TLS_Clip.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
sf::st_crs(las) <- 26912

# Pre-process the example lidar dataset by classifying the ground  and noise 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")

# find tree locations and attribute data
myTreeLocs = get_raster_eigen_treelocs(las = las, res = 0.025, pt_spacing = 0.0254,
                                       dens_threshold = 0.25,
                                       neigh_sizes = c(0.25, 0.15, 0.66),
                                       eigen_threshold = 0.75,
                                       grid_slice_min = 1,
                                       grid_slice_max = 2,
                                       minimum_polygon_area = 0.005,
                                       cylinder_fit_type = "ransac",
                                       max_dia = 1,
                                       SDvert = 0.33,
                                       n_pts = 20,
                                       n_best = 25,
                                       inliers = 0.9,
                                       conf = 0.99,
                                       max_angle = 20)

# Plot results if trees were found
if (!is.null(myTreeLocs) && nrow(myTreeLocs) > 0) {
  plot(lidR::rasterize_canopy(las, res = 0.2, p2r()))
  symbols(sf::st_coordinates(myTreeLocs)[,1], sf::st_coordinates(myTreeLocs)[,2],
          circles = myTreeLocs$Radius^2*3.14, inches = FALSE, add = TRUE, bg = 'black')
} else {
  message("No tree locations were found. Try adjusting the parameters.")
}
# }

Run the code above in your browser using DataLab