top of page

Individual Tree Detection with lidR

This project explored methods for detecting individual trees from airborne LiDAR data using both point-cloud and canopy height model (CHM) approaches. Plot-level LiDAR subsets from the Malcolm Knapp Research Forest were analyzed in R using the lidR package to segment tree crowns and identify tree locations. 

Interactive!

Project Workflow

Step 01

Extract and Prepare Plot-Level LiDAR Point Clouds

LiDAR data from the Malcolm Knapp Research Forest were subset into four circular plots (154 m diameter) using plot coordinates provided in a reference dataset. Outlier points below ground level and above 65 m were removed to ensure that the normalized point cloud represented realistic vegetation structure before further analysis.

#read in plot table
plot_table <- read.csv("data/Lab4_Plots.csv")

 

#define plot radius
radius <- 77

#for loop to extract multiple plots
for(i in 1:nrow(plot_table)){ #run the loop until i = the number of rows in 'Lab4_plots'
  plot_cent <- c(plot_table$X[i], plot_table$Y[i]) #extract plot center
  plot_las <- clip_circle(norm_cat_mkrf, plot_cent[1], plot_cent[2], radius) #clip plot from norm_cat_mkrf
  output_file <- paste("data/Plots/MKRF_Plot_", i, ".las", sep = "") #output directory as string
  writeLAS(assign(paste("MKRF_Plot_", i, sep = ""), plot_las), output_file) #write'MKRF_Plot_i' to output dir.
}

Step 02

Detect Individual Trees Using a Point-Cloud Segmentation Algorithm

Individual trees were first detected directly from the LiDAR point cloud using the Li et al. (2012) segmentation algorithm implemented in the lidR package in R. The algorithm identifies tree tops and groups nearby points into individual crowns using adaptive distance thresholds based on tree height.

#combine plots into a list
plots <- list(
  MKRF_Plot_1,
  MKRF_Plot_2,
  MKRF_Plot_3,
  MKRF_Plot_4)

#create empty list with same length #as number of plots

li2012_trees <- vector("list", length(plots))

for (i in seq_along(plots)) {

#segment each plot in the list using the Li 2012 algorithm
  li2012_trees[[i]] <- segment_trees(plots[[i]], li2012())

 

#plot so each colour corresponds to treeID/one tree
  plot(li2012_trees[[i]], color = "treeID")
}

Step 03

Generate a Canopy Height Model and Locate Tree Tops

A canopy height model (CHM) was generated from the LiDAR data using the pit-free algorithm to create a continuous representation of canopy height. Tree tops were then detected from the CHM using a local maximum filter, which identifies peaks in canopy height that likely represent individual trees.

#just working with Plot 1 for this step

#first create a CHM for Plot 1
chm_0.5_plot1 <- rasterize_canopy(MKRF_Plot_1,
  res = 0.5, #spatial resolution
  pitfree(
    thresholds = c(0, 10, 20, 30), #height thresholds
    subcircle = 0.2, #subcircle with 20cm radius
    max_edge = c(0,1) #classical triangulation threshold = 0, maximum edge length 1 
))


#determine tree tops for Plot 1

#using lmf algorithm specifying a circular moving window of 5m and minimum tree height of 2m
treetops_plot1 <- locate_trees(MKRF_Plot_1, lmf(ws = 5, hmin = 2, shape = "circular")) 

Step 04

Segment Tree Crowns Using CHM-Based Analysis

Tree crown segmentation was then performed using the Dalponte and Coomes (2016) algorithm, which expands individual tree crowns outward from detected tree tops based on canopy height thresholds. Segmentation results were compared across multiple CHM spatial resolutions to evaluate how raster resolution affects the accuracy of tree detection and crown delineation.

#use Dalponte algorithm for segmentation with a CHM of 4m resolution

dalponte_trees_4 <- segment_trees(MKRF_Plot_2, 
                                  dalponte2016(chm = chm_4_plot2, 
                                               treetops = treetops_plot2))

 

Project Visuals

Screenshot 2026-03-08 223026.png
Screenshot 2026-03-08 223401.png
Screenshot 2026-03-08 223600.png
CHM_with_treetops.png

CHM with treetops

One LiDAR tile for Malcolm Knapp Research Forest

LiDAR point-cloud for one plot

3-D plot of segmented trees

bottom of page