The following demonstrates how to write your own functions that are fully applicable on a wide catalog of point clouds and based on the available lidR
tools. We will create a simple lasfilternoise
function. This example should not be considered as the reference method for filtering noise, but rather as a demonstration to help understand the logic behind the design of lidR, and as a full example of how to create a user-defined function that is fully operational. The code design is the one used internally in lidR and relies on S3 method dispatch. For more details, we recommend reading the chapter about S3 method dispatch from the Advanced R book.
lasfilternoise
functionFirst we create a generic function lasfilternoise
that will be usable on different classes.
lasfilternoise = function(las, ...)
{
UseMethod("lasfilternoise", las)
}
lasfilternoise
for LAS
objectsA simple (perhaps too simplistic) way to detect outliers is to measure the 95th percentile of height in 10 x 10-m pixels (area-based approach) and then remove the points that are above the 95th percentile in each pixel plus, for example, 20%. This can easily be built in lidR using grid_metrics
, lasmergespatial
and lasfilter
, and should work either on a normalized or a raw point cloud. Let’s create a function method lasfilternoise
for LAS objects:
lasfilternoise.LAS = function(las, sensitivity)
{
p95 <- grid_metrics(las, ~quantile(Z, probs = 0.95), 10)
las <- lasmergespatial(las, p95, "p95")
las <- lasfilter(las, Z < p95*sensitivity)
las$p95 <- NULL
return(las)
}
This function is fully functional on a point cloud loaded in memory
las <- readLAS("file.las")
las <- lasfilternoise(las, sensitivity = 1.2)
writeLAS(las, "denoised-file.las")
lasfilternoise
function to a LAScatalog
Users can access the catalog processing engine with the function catalog_apply
i.e. the engine used internally. It can be applied to any function over an entire catalog. Here we will apply our custom lasfilternoise
function. To use our function lasfilternoise
on a LAScatalog we must create a compatible function (see documentation of catalog_apply
). In the lidR package we usually create an intermediate method. Here lasfilternoise
for LAScluster
objects (see also the documentation for catalog_apply
):
lasfilternoise.LAScluster = function(las, sensitivity)
{
# The function is automatically fed with LAScluster objects
# Here the input 'las' will a LAScluster
las <- readLAS(las) # Read the LAScluster
if (is.empty(las)) return(NULL) # Exit early (see documentation)
las <- lasfilternoise(las, tolerance) # Filter the noise
las <- lasfilter(las, buffer == 0) # Don't forget to remove the buffer
return(las) # Return the filtered point cloud
}
This function can be used in catalog_apply
. We can then create a method lasfilternoise
for a LAScatalog
:
lasfilternoise.LAScatalog = function(las, sensitivity)
{
catalog_apply(las, lasfilternoise, sensitivity = sensitivity)
}
And it just works. This function lasfilternoise
is now fully compatible with the catalog processing engine and supports all the options of the engine.
myproject <- catalog("folder/to/lidar/data/")
opt_filter(myproject) <- "-drop_z_below 0"
opt_chunk_buffer(myproject) <- 10
opt_chunk_size(myproject) <- 0
opt_cores(myproject) <- 2
opt_output_files(myproject) <- "folder/to/lidar/data/denoised/{ORIGINALFILENAME}_denoised"
output <- lasfilternoise(myproject, tolerance = 1.2)
As is, the function lasfilternoise.LAScatalog
is not actually complete. Indeed:
In lidR the functions usually look like this:
lasfilternoise.LAScatalog = function(las, sensitivity, res)
{
# Force some options
opt_select(las) <- "*" # Do not respect the select argument
opt_chunck_buffer(las) <- res # Force the buffer to be greater than 0.
# Add this option to throw an error if no output template is provided
options <- list(need_output_file = TRUE)
output <- catalog_apply(las, lasfilternoise, sensitivity = sensitivity, .options = options)
output <- unlist(output)
# Build a LAScatalog from the written las files
output <- catalog(output)
return(output)
}
Now you know how to build your custom functions that work either on a LAS or a LAScatalog object.