edit: This question does share an answer with an existing question, and the problem is the same: lastrees() does not work on LAScatalogs. However, I'm going to leave this question up, because I think the code and error message makes it easier to find.
I'm using lidR 2.0.3 (from the rocker/geospatial image). I would like to perform tree segmentation on an entire LAScatalog using the Li 2012 algorithm:
#### setup #####################################################################
# load packages
library(here)
library(lidR)
# load normalized point cloud catalog (just a pointer to the tiled point
# clouds)
normalized_als =
readRDS(here::here('02-data',
'lidar',
'aerial',
'normalized_als_catalog.rds'))
#### configure catalog #########################################################
# set catalog output path
lidR::opt_output_files(normalized_als) =
here::here('02-data',
'lidar',
'aerial',
'02-segmented',
'{ID}_segmented')
# don't use any points with Z below 0 when making the CHM
lidR::opt_filter(normalized_als) =
paste0(lidR::opt_filter(normalized_als), ', drop_z_below 0')
# use n-2 cores to process
lidR::opt_cores(normalized_als) = as.integer(parallel::detectCores()-2L)
# use a 20m buffer
lidR::opt_chunk_buffer(normalized_als) = 20
# process by files - this may preserve the lasheader?
lidR::opt_chunk_size(normalized_als) = 0
# run the algorithm, writing the segmented point cloud to disc
segmented_als =
lidR::lastrees(normalized_als,
algorithm = li2012())
The last call to lastrees returns:
Error in algorithm(las):
no slot of name "header" for this object of class "LAScatalog"
I've confirmed that the individual las files DO have valid headers, but it seems that lidR::li2012() is assuming that "las" is a LAS object, not a LAScatalog. The call fails at line 219 of lidR/R/algorithm-its.R:
if (las@header@PHB$`Max Z` < hmin)
My question is: Is my code incorrect, or is this a bug in lidR::li2012()? I'm trying to follow the examples on the wiki, but I don't 100% understand how lidR maps LAS-based functions over LAScatalogs, and it's very possible that I am misusing the lastrees function. (Is there some catalog_apply() approach that I should be using?) The li2012() function seems to expect a LAS object specifically, not a LAScatalog (which doesn't have a comparable header slot). How can I pass an actual LAS object to li2012()? I would just iterate over the separate tiles, but would like to use the buffering functionality offered by LAScatalogs. Alternatively, was the data validation checking for li2012() written with a LAS object in mind, and causing it to break when given a LAScatalog or a LAScluster?
I would be happy to email a reproducible dataset, but I believe the issue should be reproducible with an arbitrary catalog: Either my code is written incorrectly, or li2012() can't currently be used on LAScatalogs.