r-lidar / lidR

Airborne LiDAR data manipulation and visualisation for forestry application
https://CRAN.R-project.org/package=lidR
GNU General Public License v3.0
590 stars 132 forks source link

TreeIDs of identified trees and crowns #554

Closed nbrodic88 closed 2 years ago

nbrodic88 commented 2 years ago

HI! Would like to know if function segment_trees with silva gives other treeIDs than the ones I got with function find_trees? I am using those tree tops for segmentation but looks like that attribute treeID changes for segmented trees... Regards, Nenad

Jean-Romain commented 2 years ago

Did you try ?

LASfile <- system.file("extdata", "MixedConifer.laz", package="lidR")
las <- readLAS(LASfile, select = "xyz")
col <- pastel.colors(200)

# Using raster because focal does not exist in stars
chm <- rasterize_canopy(las, res = 0.5, p2r(0.3), pkg = "raster")
ker <- matrix(1,3,3)
chm <- raster::focal(chm, w = ker, fun = mean, na.rm = TRUE)

ttops <- locate_trees(chm, lmf(4, 2))
crown <- silva2016(chm, ttops)()

plot(crown == 150)
plot(sf::st_geometry(ttops[ttops$treeID == 150,]), add = T, pch = 19)

The seed IDs are preserved. If called in segment_trees the IDs are preserved too.

las = segment_trees(las, silva2016(chm, ttops))

plot(filter_poi(las, treeID == 150))   |>
  add_treetops3d(ttops[ttops$treeID == 150,])
nbrodic88 commented 2 years ago

You're right, segmented tree from LiDAR point cloud and detected treetop has the same treeID. image

But when I calculate crown metrics it numerates tree crowns with different treeid and also it looks like that the metrics are not related to the generated geometry:

crowns <- crown_metrics(las, func = .stdmetrics, attribute = "treeID", geom = "concave")

image

and is there a difference between .stdmetrics and .stdtreemetrics because with .stdtreemetrics I don't get the all the attributes for each segment

Jean-Romain commented 2 years ago

crow_metrics is supposed to respects the IDs. If you think something is wrong please report a minimal reproducible example. I cannot guess was is supposedly wrong with your image that looks legit.

nbrodic88 commented 2 years ago

(https://drive.google.com/file/d/1LIM3oc7ltVEbu5CodBSa231uQldArCOT/view?usp=sharing) I think it respects the treeID when calculating the metrics, but when I export crowns they have different treeIDs and the crown polygons don't have adequate metrics attributes code:

las <- readLAS("forest_plot.las")
col <- pastel.colors(200)

# Using raster because focal does not exist in stars
chm <- rasterize_canopy(las, res = 0.5, p2r(0.3), pkg = "raster")
ker <- matrix(1,3,3)
chm <- raster::focal(chm, w = ker, fun = mean, na.rm = TRUE)
plot(chm)

ttops <- find_trees(chm, lmf(4, 2))
writeSpatialShape(ttops, "ttops.shp")

las = segment_trees(las, silva2016(chm, ttops))
crowns <- crown_metrics(las, func = .stdmetrics, attribute = "treeID", geom = "concave")
st_write(crowns, "crowns.shp")

plot(filter_poi(las, treeID == 80))   |>
  add_treetops3d(ttops[ttops$treeID == 80,])
Jean-Romain commented 2 years ago

I can't see any obvious problem here. I may have missed it but if you think something is wrong please open a new issue with a minimal reproducible example and explain clearly what does not correspond to your expectation using code or image. Thanks

hansoleorka commented 2 years ago

Hi

I noticed a similar issue using the watershed algorithm. I modified the above example. It seems like there is an issue with the treeID when using crown_metrics. See the resulting plot of the code below.

Regards Hans Ole

LASfile <- system.file("extdata", "MixedConifer.laz", package="lidR")
las <- readLAS(LASfile, select = "xyz")
col <- pastel.colors(200)

chm <- rasterize_canopy(las, res = 0.5, p2r(0.3), pkg = "raster")
ker <- matrix(1,3,3)
chm <- raster::focal(chm, w = ker, fun = mean, na.rm = TRUE)

ttops <- find_trees(chm, lmf(4, 2))
las = segment_trees(las, silva2016(chm, ttops))
crowns <- crown_metrics(las, func = .stdmetrics_z, attribute = "treeID", geom = "concave")

tree <- filter_poi(las, treeID == 80)
top <- ttops[ttops$treeID == 80,]
crown <- crowns[crowns$treeID == 80,]

plot(chm)
plot(sf::st_geometry(crown),add=T)
plot(top,pch=3,add=T)
points(tree$X,tree$Y,pch=".")

plot

Jean-Romain commented 2 years ago

Thank you for the reproducible example I confirm there is something weird. I'll investigate tomorrow.

Jean-Romain commented 2 years ago

It is fixed now

nbrodic88 commented 2 years ago

Hi, How can I use now the fixed version of lidr? Could I just install package again from cran or should I use github repo?

Jean-Romain commented 2 years ago

from github

nbrodic88 commented 2 years ago

Now it works great, even when you import treetops from external file

spono commented 10 months ago

Ciao JR, it seems that, in v 4.0.4, using the standalone algorithm (e.g. dalponte2016(chm, ttops)() ) the treeID of crowns is renamed differently (in my case Z), while using segment_trees and then crown_metrics leads to a correct output.

Updating a bit the code from Hans Ole, you get:

LASfile <- system.file("extdata", "MixedConifer.laz", package="lidR")
las <- readLAS(LASfile, select = "xyz")
col <- pastel.colors(200)

chm <- rasterize_canopy(las, res = 0.5, p2r(0.3), pkg = "raster")
ker <- matrix(1,3,3)
chm <- raster::focal(chm, w = ker, fun = mean, na.rm = TRUE)

ttops <- locate_trees(chm, lmf(4, 2))

crowns <- dalponte2016(chm, ttops)()
names(crowns)
> "layer"

Nevertheless, on a whole segmented LAScatalog, tree IDs and crown IDs seem not to correspond to each other...but I'm digging in more and, in case, I'll open a separate issue.