Commit 2c27c586 authored by Monnet Jean-Matthieu's avatar Monnet Jean-Matthieu
Browse files

Modified data folder and updated tree.detection

parent 30b58523
% This file was created with JabRef 2.10b2.
% Encoding: UTF-8
Title = {Using airborne laser scanning for mountain forests mapping: support vector regression for stand parameters estimation and unsupervised training for treetop detection.},
Author = {Monnet, Jean-Matthieu},
School = {Université de Grenoble},
Year = {2011},
Abstract = {Numerous studies have shown the potential of airborne laser scanning for the mapping of forest resources. However, the application of this remote sensing technique to complex forests encountered in mountainous areas requires further investigation. In this thesis, the two main methods used to derive forest information are tested with airborne laser scanning data acquired in the French Alps, and adapted to the constraints of mountainous environments. In particular, a framework for unsupervised training of treetop detection is proposed, and the performance of support vector regression combined with dimension reduction for forest stand parameters estimation is evaluated.},
Keywords = {Remote sensing, airborne laser scanning, LiDAR, forest mapping, support vector regression, unsupervised training, treetop detection},
Owner = {jimbo},
Timestamp = {2014.05.15},
Url = {}
Title = {Cross-Correlation of Diameter Measures for the Co-Registration of Forest Inventory Plots with Airborne Laser Scanning Data},
Author = {Monnet, Jean-Matthieu and Mermin, Éric},
Journal = {Forests},
Year = {2014},
Number = {9},
Pages = {2307--2326},
Volume = {5},
Doi = {10.3390/f5092307},
ISSN = {1999-4907},
Owner = {jean-matthieu},
Timestamp = {2018.05.04},
Url = {}
TITLE = {{Tree top detection using local maxima filtering: a parameter sensitivity analysis}},
AUTHOR = {Monnet, Jean-Matthieu and Mermin, Eric and Chanussot, Jocelyn and Berger, Fr{\'e}d{\'e}ric},
URL = {},
BOOKTITLE = {{10th International Conference on LiDAR Applications for Assessing Forest Ecosystems (Silvilaser 2010)}},
ADDRESS = {Freiburg, Germany},
HAL_LOCAL_REFERENCE = {D{\'e}partement Images et Signal},
PAGES = {9 p.},
YEAR = {2010},
MONTH = Sep,
PDF = {},
HAL_ID = {hal-00523245},
title={A Benchmark of Lidar-Based Single Tree Detection Methods Using Heterogeneous Forest Data from the Alpine Space},
publisher={MDPI AG},
author={Eysn, Lothar and Hollaus, Markus and Lindberg, Eva and Berger, Frédéric and Monnet, Jean-Matthieu and Dalponte, Michele and Kobal, Milan and Pellegrini, Marco and Lingua, Emanuele and Mongus, Domen and et al.},
This diff is collapsed.
title: "Workflow for tree detection from ALS data"
title: "R workflow for tree segmentation from ALS data"
author: "Jean-Matthieu Monnet"
date: "`r Sys.Date()`"
pdf_document: default
html_document: default
bibliography: workflow.treedetection.bib
bibliography: "./bib/bibliography.bib"
```{r setup, include=FALSE}
......@@ -19,24 +19,17 @@ knitr::opts_chunk$set(fig.align = "center")
The code below presents a tree detection workfow from Airborne Laser Scanning (ALS) data. Workflow is based on functions from R packages `lidaRtRee` and `lidR`.
The code below presents a tree segmentation workflow from Airborne Laser Scanning (lidar remote sensing) data. The workflow is based on functions from R packages `lidaRtRee` and `lidR`, and it includes the following steps:
* treetop detection and crown segmentation
+ accuracy assessment with field inventory
* treetop detection,
+ crown segmentation,
+ accuracy assessment with field inventory,
+ species classification
Licence: CC-BY
Source page:
Steps 1 and 3 are documented in [@Monnet10; @Monnet11c]. The detection performance of this algorithm was evaluated in a benchmark [@Eysn15].
* Jan 26, 2021: checked compatibility with package `lidR` 3.1.0 and `lidaRtRee` 3.0.0
+ Oct 12, 2020: checked compatibility with package `lidR` 2.2
+ Jan 17, 2020: checked compatibility with package `lidR` 2.2
+ Dec 6, 2019: `cloudMetrics` function used for point cloud stats in segments
+ Feb 4, 2019: updated for compatibilty with packages `lidR` 2.0.0 and `lidaRtRee` 2.0.0
+ May 18, 2018: first release
Licence: CC-BY / [source page](
## Material
### Field inventory
......@@ -50,7 +43,7 @@ data(treeinventorychablais3, package = "lidaRtRee")
Otherwise you can load your own data provided positions and heights are measured.
```{r prepareTreeInventory, eval=FALSE}
# import field inventory
fichier <- "lidaRtRee/inst/extdata/chablais3_listeR.csv"
fichier <- "chablais3_listeR.csv"
tree.inventory <- read.csv(file = fichier, sep = ";", header = F)
names(tree.inventory) <- c("x", "y", "d", "h", "n", "s", "e", "t")
# save as rda for later access
......@@ -141,13 +134,13 @@ chm <- dsm - dtm
```{r plotDEMs, echo=FALSE, fig.width = 12, fig.height = 4.5, out.width='100%'}
par(mfrow = c(1, 3))
# display DTM
raster::plot(dtm,asp=1, main="DTM")
raster::plot(dtm, main = "DTM")
# display DSM
raster::plot(dsm,asp=1, main="DSM")
raster::plot(dsm, main = "DSM")
# display CHM
raster::plot(chm,asp=1, main="CHM")
raster::plot(chm, main = "CHM")
### Visual comparison of field inventory and ALS data
......@@ -172,7 +165,7 @@ Displaying inventoried trees on the CHM shows a pretty good correspondance of cr
```{r plotPlot, include = TRUE, out.width = '60%', fig.dim=c(6.5, 4.5), warnings=FALSE}
# display CHM
raster::plot(chm,asp=1, col=gray(seq(0,1,1/255)),
raster::plot(chm, col=gray(seq(0,1,1/255)),
main ="Canopy Height Model and tree positions")
# add inventoried trees
......@@ -197,13 +190,13 @@ segms <- lidaRtRee::treeSegmentation(chm)
# display pre-processed chm
raster::plot(segms$smoothed.dem,asp=1, main="Pre-processed CHM")
raster::plot(segms$smoothed.dem, main="Pre-processed CHM")
# display selected local maxima
raster::plot(segms$local.maxima,asp=1, main="Selected local maxima")
raster::plot(segms$local.maxima, main="Selected local maxima")
# display segments, except ground segment
dummy <- segms$
dummy[dummy==0] <- NA
raster::plot(dummy %% 8,asp=1, main="Segments (random colors)", col=rainbow(8), legend=FALSE)
raster::plot(dummy %% 8, main="Segments (random colors)", col=rainbow(8), legend=FALSE)
### Tree extraction
......@@ -230,9 +223,8 @@ head(trees, n=3L)
v.segments <- raster::rasterToPolygons(segms[[2]], dissolve=T)
# display initial image
raster::plot(chm,asp=1, col=gray(seq(0,1,1/255)),
main ="Canopy Height Model
and detected positions")
raster::plot(chm, col=gray(seq(0,1,1/255)),
main ="CHM and detected positions")
# display segments border
# display plot mask
......@@ -244,9 +236,9 @@ graphics::points(trees$x, trees$y, col="blue", cex=trees$h/20)
## Detection evaluation
### Tree matching
To assess detection accuracy, reference (field) trees should be linked to detected trees. Despite the possibility of error, automated matching has the advantage of making the comparison of results from different algorithms and settings reproducible and objective. The algorithm presented below is based on the 3D distance between detected treetops and inventory positions and heights [@Monnet2014].
To assess detection accuracy, reference (field) trees should be linked to detected trees. Despite the possibility of error, automated matching has the advantage of making the comparison of results from different algorithms and settings reproducible and objective. The algorithm presented below is based on the 3D distance between detected treetops and inventory positions and heights [@Monnet10].
```{r plotMached, include=TRUE, out.width = '60%', fig.dim=c(6.5, 4.5)}
```{r plotMached, include=TRUE, out.width = '70%', fig.dim=c(6.5, 4.5)}
# match detected treetops with field trees based on relative distance of apices
matched <- lidaRtRee::treeMatching(treeinventorychablais3[selec,c("x","y","h")],
cbind(trees@coords, trees$h))
......@@ -334,7 +326,7 @@ trees <- base::merge(trees, metrics, by.x="id", by.y="", all.x=T)
Plotting the reference trees with the mean intensity of lidar points in the segments shows that when they are dominant, broadleaf trees tend to have higher mean intensity than coniferous trees.
```{r Intensity, include=TRUE, out.width = '60%', fig.dim=c(6.5, 4.5)}
```{r Intensity, include=TRUE, out.width = '70%', fig.dim=c(6.5, 4.5)}
# create raster of segment' mean intensity
r.mean.intensity.segm <- segms[[""]]
# match segment id with id in metrics data.frame
......@@ -524,7 +516,7 @@ Be aware that in case tree segments are vectorized, some obtained polygons might
# folder containing the files
lazdir <- "./data.ABA.model/tiles.norm.laz/"
lazdir <- "./data/forest.structure.metrics"
# build catalog
cata <- lidR::catalog(lazdir)
# set coordinate system
......@@ -535,7 +527,7 @@ lidR::sensor(cata) <- "ALS"
# tile size to split area into chunks to process
# trade-off between RAM capacity VS total number of tiles to process
tile.size <- 200 # here 30 for example purpose with a small chm
tile.size <- 70 # here 70 for example purpose with small area
# buffer size: around each tile to avoid border effects on segmentation results
# trade-off between making sure a whole tree crown is processed in case its top is on the border VS duplicate processing
buffer.size <- 10 # 5 m is minimum, 10 is probably better depending on tree size
......@@ -678,14 +670,17 @@ if (vectorize.trees)
The following image displays the results for the whole area.
```{r batch.plot, include=TRUE, eval = FALSE, out.width = '100%', fig.dim=c(8, 8)}
```{r batch.plot, include=TRUE, out.width = '90%', fig.dim=c(8.5, 5.5)}
# threshold outsiders in chm
chm.all[chm.all > 40] <- 40
chm.all[chm.all < 0] <- 0
# plot chm
# display chm
main ="Canopy Height Model and segmented trees")
# display segments border
sp::plot(v.trees, border = "white", add = T)
# add trees
plot(trees, cex = trees$h/80, add = TRUE)
plot(trees, cex = trees$h/40, add = TRUE)
The following lines save outputs to files.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment