2

I have a large catalog and I'd like to create crown maps for the entire catalog or a portion of the catalog. I've been successful at creating crown maps from single LAZ files by editing/running the script below:

#Script to generate crown map from single file
library(lidR)
set_lidr_threads(6L)
las <- readLAS("c:/myfile.laz", select = "xyzcr", filter = "-drop_z_below 0")
las <- segment_trees(las, li2012(R = 3, speed_up = 5))
crowns <- delineate_crowns(las)
par(mar=rep(0,4))
plot(crowns)
crowns <- delineate_crowns(las, func = .stdtreemetrics)
spplot(crowns, "convhull_area")

How do I modify this code to generate crown maps from a catalog?

1 Answer 1

1

The simplest way is to perform the two tasks consecutively on a LAScatalog. Read also chapter 14.11 and 14.12 of the book.

ctg <- readLAScatalog("folder/", filter = "-drop_z_below 0")

opt_output_files(ctg) <- "folder/segmented/{ORIGINALFILENAME}"
ctg_trees <- segment_trees(ctg, li2012(R = 3, speed_up = 5), uniqueness = "gpstime")

opt_output_files(ctg_trees) <- ""
crowns <- delineate_crowns(ctg_trees)

But this has a drawback because it implies to create a copy of the point-cloud to store the segmented point-cloud temporarily. Depending on the size of the collection you may want to skip this step. In this case you must create your own process that applies both segment_trees() and delineate_crowns() and use catalog_apply() to apply your custom function. Something like that:

myprocess = function(x)
{
  las <- readLAS(x)
  if (is.empty(las)) return(NULL)
  las <- segment_trees(las, li2012(R = 3, speed_up = 5), uniqueness = "gpstime")
  crowns <- delineate_crowns(las)
  return(crowns)
}

ctg <- readLAScatalog("folder/", select = "xyzcrt", filter = "-drop_z_below 0", chunk_size = 100)
options <- list(need_buffer = TRUE, automerge = TRUE)
output  <- catalog_apply(ctg, myprocess, .options = options)

Yet this is not correct as is because it is the responsibility of the user to manage how the buffer is treated and removed. Here we did not manage the buffer at all so many trees are found twice or more or are found partially in the buffer.

plot(crowns, col = rgb(0,0,1,0.3)) 

enter image description here

For each chunk we must remove the crowns of the trees that are in the buffer. In this case it's tricky because we are dealing with polygons that may overlap two or more files. The simplest way is to copy paste the code of delineate_crown()

myprocess = function(x)
{
  las <- readLAS(x)
  if (is.empty(las)) return(NULL)
  las <- segment_trees(las, li2012(R = 3, speed_up = 5), uniqueness = "gpstime")
  crowns <- delineate_crowns(las)
  
  bbox  <- raster::extent(x)
  coords <- crowns@data[,c("XTOP", "YTOP")]
  coords$ID <- 1:length(crowns)
  sp::coordinates(coords) <- ~XTOP+YTOP
  coords <- raster::crop(coords, bbox)
  return(crowns[coords$ID,])
}

enter image description here

1
  • Thank you very much. I have a large amount of hard disk storage available so I chose your first code snippet and it worked very well. I also added a line to write the crown map out as a shape file. Here's the line I added: writeOGR(obj=crowns, dsn="c:/path/to/shpfile/ folder", layer="crowns", driver="ESRI Shapefile")
    – Steve
    Mar 30, 2021 at 3:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.