cspstandsegmentation

R package for single tree delination from TLS/MLS/ULS point clouds

https://github.com/julfrey/cspstandsegmentation

Science Score: 59.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
    Found 2 DOI reference(s) in README
  • Academic publication links
    Links to: zenodo.org
  • Committers with academic emails
    1 of 4 committers (25.0%) from academic institutions
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (13.3%) to scientific vocabulary
Last synced: 7 months ago · JSON representation

Repository

R package for single tree delination from TLS/MLS/ULS point clouds

Basic Info
  • Host: GitHub
  • Owner: JulFrey
  • License: gpl-3.0
  • Language: R
  • Default Branch: main
  • Size: 4.08 MB
Statistics
  • Stars: 21
  • Watchers: 3
  • Forks: 0
  • Open Issues: 0
  • Releases: 1
Created over 3 years ago · Last pushed 9 months ago
Metadata Files
Readme License

README.md

CspStandSegmentation is an R-package for the segmentation of single trees from forest point clouds scanned with terrestrial, mobile or unmanned LiDAR systems

Authors: Julian Frey and Zoe Schindler, University of Freiburg, Chair of Forest Growth and Dendroecology

DOI

Installation

If you are working on Windows operating systems, you will need to install Rtools prior to installation: https://cran.r-project.org/bin/windows/Rtools/>. On Mac, Xcode is required.

```R install.packages(c('devtools', 'Rcpp', 'lidR', 'dbscan', 'igraph', 'foreach', 'doParallel','magrittr', 'data.table'))

devtools::install_github('https://github.com/JulFrey/CspStandSegmentation')

Check if it is working

library(CspStandSegmentation) example("cspcostsegmentation")

```

Usage

The package is firmly based on the lidR package and uses the las file structure. Smaller point clouds can be directly segmented using the csp_cost_segmentation function. This requires a set of tree positions (map) as starting points, which can be derived using the find_base_coordinates_raster function, which might require parameter optimization. Theoretically, tree positions might also come from field measurements or manual assignments.:

```R

read example data

file = system.file("extdata", "beech.las", package="CspStandSegmentation") tls = lidR::readTLSLAS(file)

find tree positions as starting points for segmentation

map <- CspStandSegmentation::findbasecoordinates_raster(tls)

segment trees

segmented <- tls |> CspStandSegmentation::addgeometry(ncores = parallel::detectCores()/2) |> CspStandSegmentation::cspcostsegmentation(map, 1, N_cores = parallel::detectCores()/2)

show results

lidR::plot(segmented, color = "TreeID")

create inventory

inventory <- CspStandSegmentation::forestinventory(segmented) head(inventory) lidR::plot(segmented, color = "TreeID") |> CspStandSegmentation::plotinventory(inventory) ```

For large areas, the package can be used within the lidR LAScatalogue engine to cope with memory limitations. The following example shows how this can be done. The single tiles of segmented trees are saved in a folder in this example and merged afterwards.

```R

packages

library(lidR) library(CspStandSegmentation)

parameters

lasfile <- "yourfile.laz" basedir <- "~/yourprojectfolder/" # with trailing / cores <- parallel::detectCores()/2 # number od cpu cores res <- 0.3 # voxel resolution for segmentation chunksize <- 50 # size of one tile in m excl. buffer chunk_buffer <- 10 # buffer around tile in m

main

create dir for segmentation tiles

if(!dir.exists(paste0(basedir,"segmentationtiles/"))) { dir.create(paste0(basedir,"segmentationtiles/")) }

uls = lidR::readTLSLAScatalog(paste0(basedir,lasfile), select = "XYZ0", chunksize = chunksize, chunkbuffer = chunkbuffer) plot(uls, chunk_pattern = T)

plot(dtm,add = T)

sf::asSpatial(sf::stas_sf(map, coords = c("X", "Y"))) |> plot(add = T)

optoutputfiles(uls) <- paste0(basedir,"segmentationtiles/{ID}") segmented <- catalog_apply(uls, function(cluster) {

las <- suppressWarnings(readLAS(cluster)) # read files if (is.empty(las) ) return(NULL) # stop if empty print(str(cluster)) # find tree positions as starting points for segmentation map <- CspStandSegmentation::findbasecoordinates_raster(las)

# add the tile ID*100,000 to the TreeID to ensure unique IDs across all tiles map$TreeID <- map$TreeID + as.numeric(basename(cluster@save)) * 100000

# only use seed positions within the tile+buffer and save the tile bbox to only return tree pos within the tile (excl. buffer) inv <- map invb <- map # the bbox includes the buffer, the bbbox excludes the buffer bbox <- cluster@bbox bbbox <- cluster@bbbox inv <- inv[inv$X < bbox[1,2] & inv$X > bbox[1,1] & inv$Y < bbox[2,2] & inv$Y > bbox[2,1],] invb <- invb[invb$X < bbbox[1,2] & invb$X > bbbox[1,1] & invb$Y < bbbox[2,2] & invb$Y > bbbox[2,1],] if (nrow(inv) == 0) return(NULL) # stop if no tree pos in tile found if (is.empty(las) ) return(NULL) # stop if empty

# Assign all points to trees las <- las |> addgeometry(ncores = cores) |> cspcostsegmentation(invb,res, Ncores = cores, Vw = 0.5) # las <- las |> cspcostsegmentation(map,res, Ncores = cores, Vw = 0.5) # this is a faster version which does not make use of the geometric feature weights if (is.empty(las)) return(NULL)

las <- las |> filter_poi(TreeID %in% c(0,inv$TreeID)) # only return trees within the tile if (is.empty(las)) return(NULL) # stop if empty

# remove unneccesary attributes for further processing las <- las |> removelasattribute('xvox') |> removelasattribute('yvox') |> removelasattribute('zvox') |> removelasattribute('buffer') |> removelasattribute('Linearity') |> removelasattribute('Sphericity') |> removelasattribute('Verticality')

# validate las las <- las |> lasquantize() |> lasupdate() if (is.empty(las)) return(NULL) return(las) }, .options = list(automerge = TRUE))

merge segmented trees

segmented <- readTLSLAScatalog(paste0(basedir,"segmentationtiles/"), select = "xyz0", chunkbuffer = 0) optmerge(segmented) <- TRUE optoutputfiles(segmented) <- paste0("") segmented <- catalog_apply(segmented, function(cluster) { las <- suppressWarnings(readLAS(cluster)) # read files if (is.empty(las) ) return(NULL) # stop if empty return(las) }, .options = list(automerge = TRUE))

write results in a single file

writeLAS(segmented, paste0(base_dir,"segmented.las")) ```

Owner

  • Login: JulFrey
  • Kind: user

GitHub Events

Total
  • Release event: 1
  • Watch event: 8
  • Push event: 15
  • Create event: 2
Last Year
  • Release event: 1
  • Watch event: 8
  • Push event: 15
  • Create event: 2

Committers

Last synced: 8 months ago

All Time
  • Total Commits: 59
  • Total Committers: 4
  • Avg Commits per committer: 14.75
  • Development Distribution Score (DDS): 0.356
Past Year
  • Commits: 24
  • Committers: 2
  • Avg Commits per committer: 12.0
  • Development Distribution Score (DDS): 0.5
Top Committers
Name Email Commits
JulFrey j****y@i****e 38
Julian Frey 4****y 16
Zoe 5****r 3
unknown J****n@I****t 2
Committer Domains (Top 20 + Academic)

Issues and Pull Requests

Last synced: 7 months ago

All Time
  • Total issues: 1
  • Total pull requests: 2
  • Average time to close issues: 25 days
  • Average time to close pull requests: about 8 hours
  • Total issue authors: 1
  • Total pull request authors: 1
  • Average comments per issue: 4.0
  • Average comments per pull request: 0.0
  • Merged pull requests: 2
  • Bot issues: 0
  • Bot pull requests: 0
Past Year
  • Issues: 0
  • Pull requests: 0
  • Average time to close issues: N/A
  • Average time to close pull requests: N/A
  • Issue authors: 0
  • Pull request authors: 0
  • Average comments per issue: 0
  • Average comments per pull request: 0
  • Merged pull requests: 0
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • LY0025 (1)
Pull Request Authors
  • zoeschindler (2)
Top Labels
Issue Labels
Pull Request Labels

Dependencies

DESCRIPTION cran
  • Rcpp >= 1.0.5 imports
  • TreeLS * imports
  • data.table * imports
  • dbscan * imports
  • doParallel * imports
  • foreach * imports
  • igraph * imports
  • lidR * imports
  • magrittr * imports
  • parallel * imports
  • sf * imports
  • terra * imports