├── .DS_Store ├── .Rbuildignore ├── .gitignore ├── CHANGELOG.md ├── DESCRIPTION ├── LICENSE.txt ├── NAMESPACE ├── R ├── RcppExports.R ├── map_methods.R ├── methods.R ├── plot_extras.R ├── point_metrics_methods.R ├── sample_methods.R ├── stem_points_methods.R ├── stem_segmentation_methods.R └── tree_points_methods.R ├── README.md ├── TreeLS.Rproj ├── inst ├── extdata │ ├── pine.laz │ ├── pine_plot.laz │ └── spruce.laz └── include │ ├── algorithms.hpp │ ├── classes.hpp │ ├── constrained │ └── sumt.hpp │ ├── line_search │ └── more_thuente.hpp │ ├── methods.hpp │ ├── misc │ ├── determine_bounds_type.hpp │ ├── error_reporting.hpp │ ├── error_reporting.ipp │ ├── jacobian_adjust.hpp │ ├── misc.hpp │ ├── numerical_gradient.hpp │ ├── numerical_hessian.hpp │ ├── optim_options.hpp │ ├── optim_structs.hpp │ ├── transform_vals.hpp │ ├── unit_vec.hpp │ └── unit_vec.ipp │ ├── optim.hpp │ ├── unconstrained │ ├── bfgs.hpp │ ├── cg.hpp │ ├── de.hpp │ ├── de_prmm.hpp │ ├── gd.hpp │ ├── lbfgs.hpp │ ├── newton.hpp │ ├── nm.hpp │ ├── pso.hpp │ └── pso_dv.hpp │ ├── utils.hpp │ └── zeros │ └── broyden.hpp ├── man-roxygen ├── example-segmentation.R ├── example-tree-map.R ├── param-colnames.R ├── param-conf.R ├── param-h_step.R ├── param-hbase.R ├── param-inliers.R ├── param-las.R ├── param-max-curvature.R ├── param-max-d.R ├── param-max-radius.R ├── param-max-verticality.R ├── param-min-density.R ├── param-min-h.R ├── param-min-n.R ├── param-min-votes.R ├── param-min_h-max_h.R ├── param-n-best.R ├── param-n-ransac.R ├── param-pixel-size.R ├── param-tol.R ├── param-v3d.R ├── param-votes-weight.R ├── param-voxel-spacing.R ├── param-z-dev.R ├── reference-liang.R ├── reference-olofsson-2016.R ├── reference-olofsson.R ├── reference-thesis.R ├── reference-wang.R ├── reference-zhou.R ├── return-las.R ├── section-brute-force.R ├── section-circlefit.R ├── section-cylinderfit.R ├── section-eigen-decomposition.R ├── section-hough-transform.R ├── section-irls.R ├── section-knn.R ├── section-normals-voting.R ├── section-point-metrics.R ├── section-ransac.R └── section-voxel.R ├── man ├── circleFit.Rd ├── cylinderFit.Rd ├── fastPointMetrics.Rd ├── fastPointMetrics.available.Rd ├── gpsTimeFilter.Rd ├── map.eigen.knn.Rd ├── map.eigen.voxel.Rd ├── map.hough.Rd ├── map.pick.Rd ├── nnFilter.Rd ├── ptm.knn.Rd ├── ptm.voxel.Rd ├── readTLS.Rd ├── setTLS.Rd ├── sgt.bf.cylinder.Rd ├── sgt.irls.circle.Rd ├── sgt.irls.cylinder.Rd ├── sgt.ransac.circle.Rd ├── sgt.ransac.cylinder.Rd ├── shapeFit.Rd ├── shapeFit.forks.Rd ├── smp.randomize.Rd ├── smp.voxelize.Rd ├── stemPoints.Rd ├── stemSegmentation.Rd ├── stm.eigen.knn.Rd ├── stm.eigen.voxel.Rd ├── stm.hough.Rd ├── tlsCrop.Rd ├── tlsInventory.Rd ├── tlsNormalize.Rd ├── tlsPlot.Rd ├── tlsRotate.Rd ├── tlsSample.Rd ├── tlsTransform.Rd ├── treeMap.Rd ├── treeMap.merge.Rd ├── treeMap.positions.Rd ├── treePoints.Rd ├── trp.crop.Rd ├── trp.voronoi.Rd └── writeTLS.Rd ├── old.R ├── src ├── Makevars ├── Makevars.win ├── RcppExports.cpp ├── algorithms.cpp ├── algorithms.hpp ├── classes.hpp ├── constrained │ └── sumt.hpp ├── line_search │ └── more_thuente.hpp ├── methods.cpp ├── methods.hpp ├── misc │ ├── determine_bounds_type.hpp │ ├── error_reporting.hpp │ ├── error_reporting.ipp │ ├── jacobian_adjust.hpp │ ├── misc.hpp │ ├── numerical_gradient.hpp │ ├── numerical_hessian.hpp │ ├── optim_options.hpp │ ├── optim_structs.hpp │ ├── transform_vals.hpp │ ├── unit_vec.hpp │ └── unit_vec.ipp ├── optim.hpp ├── r_interface.cpp ├── unconstrained │ ├── bfgs.hpp │ ├── cg.hpp │ ├── de.hpp │ ├── de_prmm.hpp │ ├── gd.hpp │ ├── lbfgs.hpp │ ├── newton.hpp │ ├── nm.hpp │ ├── pso.hpp │ └── pso_dv.hpp ├── utils.cpp ├── utils.hpp └── zeros │ └── broyden.hpp ├── test.cpp └── tests.R /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiagodc/TreeLS/0e0871f11358b2812adc7564ec66c39a5ab70c71/.DS_Store -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^man-roxygen$ 4 | ^LICENSE\.txt$ 5 | ^Rcpp-quickref\.pdf$ 6 | ^\.vscode$ 7 | ^test_data$ 8 | ^src/classes\.hpp$ 9 | ^src/methods\.hpp$ 10 | ^old\.R$ 11 | ^tests\.R$ 12 | ^test\.cpp$ 13 | ^src/algorithms\.hpp$ 14 | ^src/optim\.hpp$ 15 | ^src/utils\.hpp$ 16 | ^src/constrained$ 17 | ^src/line_search$ 18 | ^src/misc$ 19 | ^src/unconstrained$ 20 | ^src/zeros$ 21 | ^CHANGELOG\.md$ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | ./data 5 | test_data 6 | .vscode 7 | *.o 8 | *.pdf 9 | src/*.dll 10 | src/*.so 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | #### v2.0.0 2 | - *ply* files are now supported in `readTLS`. 3 | - naming convention changed for all methods used inside other functions - all start with a 3 letter prefix (`ptm`, `map`, `ptm`, `trp`...). 4 | - some methods were renamed: `tlsTransform`, `treeMap.positions`. 5 | - new methods added por tree mapping, stem points and stem segmentation, contemplating several new possible use cases and forest scenarios (complex forests, high accuracy LiDAR sensors, irregular stem shapes and so on). 6 | - `treeMap.merge` function introduced and applied internally in `treeMap`, allowing detection and merging of duplicates, mapping errors, and forked stems into the same tree. 7 | - extra step added to the inventory workflow and new method added: `treePoints`. This way whole trees are assigned TreeIDs in a plot, not just their stem points. 8 | - new method added for quick forest inventory metrics: `tlsInventory`. 9 | - new functionalities introduced: `fastPointMetrics`, `shapeFit`, `nnFilter`, `writeTLS`, `shapeFit.forks` 10 | - all RANSAC methods have been tuned internally for extra robustness and stability when estimating diameters of noisy point clouds. 11 | - `tlsPlot` completely refactored to dynamically interpret any unnamed inputs and plot them accordingly. 12 | - `add_*` plot functions added, making plotting of 3D products much more flexible and compatible with `lidR` plots. 13 | - actual 3D cylinder plotting added for all stem segmentation methods. 14 | - dependency issues fixed and updated. 15 | - `lidR` internal calls updated with new naming convention introduced in v3.0.0. 16 | - bug fixes and performance enhancements. 17 | 18 | #### v1.0.1 19 | - bug fix #3. -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: TreeLS 2 | Type: Package 3 | Title: Terrestrial Point Cloud Processing of Forest Data 4 | Version: 2.0.5 5 | Date: 2021-15-01 6 | Authors@R: c(person("Tiago", "de Conto", email = "tdc.florestal@gmail.com", role = c("aut", "cre"))) 7 | Description: High performance algorithms for manipulation of terrestrial 'LiDAR' (but not only) point clouds for use in research and forest monitoring applications, being fully compatible with the 'LAS' infrastructure of 'lidR'. For in depth descriptions of stem denoising and segmentation algorithms refer to Conto et al. (2017) . 8 | URL: https://github.com/tiagodc/TreeLS 9 | Depends: R (>= 3.3.0), data.table (>= 1.12.0), magrittr (>= 1.5), lidR (>= 3.0.0) 10 | Imports: rgl, raster, sp, deldir, dismo, nabor, benchmarkme, rlas, RCSF, glue, mathjaxr 11 | License: GPL-3 12 | Encoding: UTF-8 13 | LazyData: true 14 | LinkingTo: RcppArmadillo,Rcpp,BH,RcppEigen 15 | RoxygenNote: 7.2.3 16 | RdMacros: mathjaxr 17 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(add_segmentIDs) 4 | export(add_stemPoints) 5 | export(add_stemSegments) 6 | export(add_tlsInventory) 7 | export(add_treeIDs) 8 | export(add_treeMap) 9 | export(add_treePoints) 10 | export(fastPointMetrics) 11 | export(fastPointMetrics.available) 12 | export(gpsTimeFilter) 13 | export(map.eigen.knn) 14 | export(map.eigen.voxel) 15 | export(map.hough) 16 | export(map.pick) 17 | export(nnFilter) 18 | export(ptm.knn) 19 | export(ptm.voxel) 20 | export(readTLS) 21 | export(setTLS) 22 | export(sgt.bf.cylinder) 23 | export(sgt.irls.circle) 24 | export(sgt.irls.cylinder) 25 | export(sgt.ransac.circle) 26 | export(sgt.ransac.cylinder) 27 | export(shapeFit) 28 | export(shapeFit.forks) 29 | export(smp.randomize) 30 | export(smp.voxelize) 31 | export(stemPoints) 32 | export(stemSegmentation) 33 | export(stm.eigen.knn) 34 | export(stm.eigen.voxel) 35 | export(stm.hough) 36 | export(tlsCrop) 37 | export(tlsInventory) 38 | export(tlsNormalize) 39 | export(tlsPlot) 40 | export(tlsRotate) 41 | export(tlsSample) 42 | export(tlsTransform) 43 | export(treeMap) 44 | export(treeMap.merge) 45 | export(treeMap.positions) 46 | export(treePoints) 47 | export(trp.crop) 48 | export(trp.voronoi) 49 | export(writeTLS) 50 | import(data.table) 51 | import(deldir) 52 | import(dismo) 53 | import(glue) 54 | import(lidR) 55 | import(magrittr) 56 | import(nabor) 57 | import(rgl) 58 | importFrom(benchmarkme,get_ram) 59 | importFrom(data.table,fread) 60 | importFrom(dismo,voronoi) 61 | importFrom(graphics,abline) 62 | importFrom(graphics,legend) 63 | importFrom(graphics,lines) 64 | importFrom(nabor,knn) 65 | importFrom(raster,"res<-") 66 | importFrom(raster,extent) 67 | importFrom(raster,raster) 68 | importFrom(rlas,read.las) 69 | importFrom(sp,SpatialPoints) 70 | importFrom(sp,over) 71 | importFrom(stats,cov) 72 | importFrom(stats,dist) 73 | importFrom(stats,kmeans) 74 | importFrom(stats,median) 75 | importFrom(stats,quantile) 76 | importFrom(stats,rbinom) 77 | importFrom(stats,runif) 78 | importFrom(utils,combn) 79 | importFrom(utils,head) 80 | useDynLib(TreeLS, .registration = TRUE) 81 | -------------------------------------------------------------------------------- /R/RcppExports.R: -------------------------------------------------------------------------------- 1 | # Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | thinCloud <- function(las, voxel = 0.025) { 5 | .Call(`_TreeLS_thinCloud`, las, voxel) 6 | } 7 | 8 | RCropCloud <- function(las, xCenter, yCenter, len, circle, negative) { 9 | .Call(`_TreeLS_RCropCloud`, las, xCenter, yCenter, len, circle, negative) 10 | } 11 | 12 | getHoughCircle <- function(las, pixel = 0.05, rad_max = 0.25, min_den = 0.1, min_votes = 3L) { 13 | .Call(`_TreeLS_getHoughCircle`, las, pixel, rad_max, min_den, min_votes) 14 | } 15 | 16 | singleStack <- function(las, pixel = 0.05, rad_max = 0.25, min_den = 0.1, min_votes = 3L) { 17 | .Call(`_TreeLS_singleStack`, las, pixel, rad_max, min_den, min_votes) 18 | } 19 | 20 | stackMap <- function(las, hmin = 1, hmax = 3, hstep = 0.5, pixel = 0.025, rad_max = 0.25, min_den = 0.1, min_votes = 3L) { 21 | .Call(`_TreeLS_stackMap`, las, hmin, hmax, hstep, pixel, rad_max, min_den, min_votes) 22 | } 23 | 24 | houghStemPoints <- function(las, h1 = 1, h2 = 3, hstep = 0.5, radius = 0.25, pixel = 0.025, density = 0.1, votes = 3L) { 25 | .Call(`_TreeLS_houghStemPoints`, las, h1, h2, hstep, radius, pixel, density, votes) 26 | } 27 | 28 | houghStemPlot <- function(las, ptIds, h1 = 1, h2 = 3, hstep = 0.5, radius = 0.25, pixel = 0.025, density = 0.1, votes = 3L) { 29 | .Call(`_TreeLS_houghStemPlot`, las, ptIds, h1, h2, hstep, radius, pixel, density, votes) 30 | } 31 | 32 | getCircleRansac <- function(las, nSamples = 5L, pConfidence = 0.99, pInliers = 0.8) { 33 | .Call(`_TreeLS_getCircleRansac`, las, nSamples, pConfidence, pInliers) 34 | } 35 | 36 | ransacStemCircle <- function(las, segs, rads, nSamples = 5L, pConfidence = 0.99, pInliers = 0.8, tolerance = 0.05) { 37 | .Call(`_TreeLS_ransacStemCircle`, las, segs, rads, nSamples, pConfidence, pInliers, tolerance) 38 | } 39 | 40 | irlsStemCylinder <- function(las, segs, rads, nPoints = 500L, tolerance = 0.05) { 41 | .Call(`_TreeLS_irlsStemCylinder`, las, segs, rads, nPoints, tolerance) 42 | } 43 | 44 | irlsStemCircle <- function(las, segs, rads, nSamples = 500L, tolerance = 0.05) { 45 | .Call(`_TreeLS_irlsStemCircle`, las, segs, rads, nSamples, tolerance) 46 | } 47 | 48 | ransacStemCylinder <- function(las, segs, rads, nSamples = 10L, pConfidence = 0.95, pInliers = 0.8, tolerance = 0.05) { 49 | .Call(`_TreeLS_ransacStemCylinder`, las, segs, rads, nSamples, pConfidence, pInliers, tolerance) 50 | } 51 | 52 | ransacPlotCircles <- function(las, tId, segs, rads, nSamples = 5L, pConfidence = 0.99, pInliers = 0.8, tolerance = 0.05) { 53 | .Call(`_TreeLS_ransacPlotCircles`, las, tId, segs, rads, nSamples, pConfidence, pInliers, tolerance) 54 | } 55 | 56 | ransacPlotCylinders <- function(las, tId, segs, rads, nSamples, pConfidence, pInliers, tolerance) { 57 | .Call(`_TreeLS_ransacPlotCylinders`, las, tId, segs, rads, nSamples, pConfidence, pInliers, tolerance) 58 | } 59 | 60 | irlsPlotCylinders <- function(las, tId, segs, rads, nPoints, tolerance) { 61 | .Call(`_TreeLS_irlsPlotCylinders`, las, tId, segs, rads, nPoints, tolerance) 62 | } 63 | 64 | irlsPlotCircles <- function(las, tId, segs, rads, nPoints, tolerance) { 65 | .Call(`_TreeLS_irlsPlotCircles`, las, tId, segs, rads, nPoints, tolerance) 66 | } 67 | 68 | pointMetricsCpp <- function(las, kIds, whichMetrics) { 69 | .Call(`_TreeLS_pointMetricsCpp`, las, kIds, whichMetrics) 70 | } 71 | 72 | voxelIndex <- function(las, d) { 73 | .Call(`_TreeLS_voxelIndex`, las, d) 74 | } 75 | 76 | voxelMetrics <- function(las, voxelIds, whichMetrics) { 77 | .Call(`_TreeLS_voxelMetrics`, las, voxelIds, whichMetrics) 78 | } 79 | 80 | treeEigenHough <- function(las, ids, split_by, voxel = 0.05, rad = 0.25, is2d = FALSE, getSpace = FALSE) { 81 | .Call(`_TreeLS_treeEigenHough`, las, ids, split_by, voxel, rad, is2d, getSpace) 82 | } 83 | 84 | plotEigenHough <- function(las, ids, split_by, resplit_by, voxel = 0.05, rad = 0.25, is2d = FALSE, getSpace = FALSE) { 85 | .Call(`_TreeLS_plotEigenHough`, las, ids, split_by, resplit_by, voxel, rad, is2d, getSpace) 86 | } 87 | 88 | cppFastApply <- function(matrix, funcList) { 89 | .Call(`_TreeLS_cppFastApply`, matrix, funcList) 90 | } 91 | 92 | cppCircleFit <- function(las, method = "qr", n = 5L, p = 0.99, inliers = 0.8, nbest = 0L) { 93 | .Call(`_TreeLS_cppCircleFit`, las, method, n, p, inliers, nbest) 94 | } 95 | 96 | cppCylinderFit <- function(las, method = "nm", n = 10L, p = 0.95, inliers = 0.9, max_angle = 30, n_best = 20L) { 97 | .Call(`_TreeLS_cppCylinderFit`, las, method, n, p, inliers, max_angle, n_best) 98 | } 99 | 100 | treeIdsFromMap <- function(las, xycenters, uniqueIds, length, circle) { 101 | .Call(`_TreeLS_treeIdsFromMap`, las, xycenters, uniqueIds, length, circle) 102 | } 103 | 104 | bruteForceRansacCylinder <- function(las, nSamples, pConfidence, pInliers, nBest, maxAngle) { 105 | .Call(`_TreeLS_bruteForceRansacCylinder`, las, nSamples, pConfidence, pInliers, nBest, maxAngle) 106 | } 107 | 108 | bfStemCylinder <- function(las, segs, rads, nSamples = 10L, pConfidence = 0.95, pInliers = 0.8, max_angle = 30, tolerance = 0.05) { 109 | .Call(`_TreeLS_bfStemCylinder`, las, segs, rads, nSamples, pConfidence, pInliers, max_angle, tolerance) 110 | } 111 | 112 | bfPlotCylinders <- function(las, tId, segs, rads, nSamples = 10L, pConfidence = 0.95, pInliers = 0.8, max_angle = 30, tolerance = 0.05) { 113 | .Call(`_TreeLS_bfPlotCylinders`, las, tId, segs, rads, nSamples, pConfidence, pInliers, max_angle, tolerance) 114 | } 115 | 116 | -------------------------------------------------------------------------------- /R/sample_methods.R: -------------------------------------------------------------------------------- 1 | # =============================================================================== 2 | # 3 | # Developers: 4 | # 5 | # Tiago de Conto - tdc.florestal@gmail.com - https://github.com/tiagodc/ 6 | # 7 | # COPYRIGHT: Tiago de Conto, 2020 8 | # 9 | # This piece of software is open and free to use, redistribution and modifications 10 | # should be done in accordance to the GNU General Public License >= 3 11 | # Use this software as you wish, but no warranty is provided whatsoever. For any 12 | # comments or questions on TreeLS, please contact the developer (prefereably through my github account) 13 | # 14 | # If publishing any work/study/research that used the tools in TreeLS, 15 | # please don't forget to cite the proper sources! 16 | # 17 | # Enjoy! 18 | # 19 | # =============================================================================== 20 | 21 | #' Point sampling algorithm: systematic voxel grid 22 | #' @description This function is meant to be used inside \code{\link{tlsSample}}. It selects one random point per voxel at a given spatial resolution. 23 | #' @param spacing \code{numeric} - voxel side length, in point cloud units. 24 | #' @export 25 | smp.voxelize = function(spacing = 0.05){ 26 | 27 | if(spacing <= 0) 28 | stop('spacing must be a positive number') 29 | 30 | func = function(las){ 31 | las %>% las2xyz %>% thinCloud(spacing) %>% return() 32 | } 33 | 34 | func %<>% setAttribute('tls_sample_mtd') 35 | 36 | return(func) 37 | } 38 | 39 | #' Point sampling algorithm: random sample 40 | #' @description This function is meant to be used inside \code{\link{tlsSample}}. It selects points randomly, returning a fraction of the input point cloud. 41 | #' @param p \code{numeric} - sampling probability (from 0 to 1). 42 | #' @importFrom stats rbinom 43 | #' @export 44 | smp.randomize = function(p = 0.5){ 45 | 46 | if(p <= 0) 47 | stop('p must be a positive number') 48 | 49 | if(p >= 1) 50 | stop('p must be a number between 0 and 1 for random sampling') 51 | 52 | func = function(las){ 53 | n = nrow(las@data) 54 | keep = rbinom(n, 1, p) == 1 55 | return(keep) 56 | } 57 | 58 | func %<>% setAttribute('tls_sample_mtd') 59 | 60 | return(func) 61 | } 62 | -------------------------------------------------------------------------------- /R/tree_points_methods.R: -------------------------------------------------------------------------------- 1 | #' Tree points algorithm: voronoi polygons. 2 | #' @description This function is meant to be used inside \code{\link{treePoints}}. Assign **all** points to a \code{TreeID} based on their closest \code{\link{treeMap}} coordinate. 3 | #' @importFrom dismo voronoi 4 | #' @importFrom sp over SpatialPoints 5 | #' @export 6 | trp.voronoi = function(){ 7 | 8 | func = function(las, xymap){ 9 | xt = extent(las) + c(-1,1,-1,1) 10 | v_poly = voronoi(xymap[,2:3], xt) 11 | v_poly$id = xymap$TreeID 12 | names(v_poly) = 'TreeID' 13 | crs(v_poly) = crs(las) 14 | 15 | xysp = las@data[,.(X,Y)] %>% SpatialPoints 16 | crs(xysp) = crs(las) 17 | xysp %<>% over(y = v_poly) 18 | 19 | xysp = xysp[,1] %>% as.double 20 | xysp[is.na(xysp)] = 0 21 | 22 | las@data$TreeID = xysp 23 | las@data$TreeID[las@data$Classification == 2] = 0 24 | 25 | las %<>% setAttribute('tree_points') 26 | 27 | return(las) 28 | } 29 | 30 | func %<>% setAttribute('tpt_mtd') 31 | return(func) 32 | } 33 | 34 | 35 | #' Tree points algorithm: fixed size patches. 36 | #' @description This function is meant to be used inside \code{\link{treePoints}}. Assign points to a \code{TreeID} inside circles/squares of fixed area around \code{\link{treeMap}} coordinates. 37 | #' @param l \code{numeric} - circle radius or square side length. 38 | #' @param circle \code{logical} - assign \code{TreeID}s to circular (\code{TRUE}) or squared (\code{FALSE}) patches. 39 | #' @export 40 | trp.crop = function(l = 1, circle=TRUE){ 41 | func = function(las, xymap){ 42 | las@data$TreeID = treeIdsFromMap(las@data[,.(X,Y)] %>% as.matrix, xymap[,.(X,Y)] %>% as.matrix, xymap$TreeID %>% as.integer, l, circle) 43 | las %<>% setAttribute('tree_points') 44 | return(las) 45 | } 46 | func %<>% setAttribute('tpt_mtd') 47 | return(func) 48 | } 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![GPLv3 License](https://img.shields.io/badge/License-GPL%20v3-yellow.svg)](https://opensource.org/licenses/) 2 | [![](https://www.r-pkg.org/badges/version/TreeLS)](https://cran.r-project.org/package=TreeLS) 3 | ![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/tiagodc/TreeLS) 4 | ![](https://cranlogs.r-pkg.org/badges/grand-total/TreeLS) 5 | 6 | # TreeLS 7 | 8 | High performance R functions for forest data processing based on **T**errestrial **L**aser **S**canning (but not only) point clouds. 9 | 10 | ## Description 11 | 12 | This package is a refactor of the methods described in [this paper](https://doi.org/10.1016/j.compag.2017.10.019), among many other features for 3D point cloud processing of forest environments. 13 | 14 | Most algorithms are written in C++ and wrapped in R functions through `Rcpp`. *TreeLS* is built on top of [lidR](https://github.com/Jean-Romain/lidR/), using its `LAS` infrastructure internally for most methods. 15 | 16 | For any questions, comments or bug reports please submit an [issue](https://github.com/tiagodc/TreeLS/issues) here on GitHub. Suggestions, ideas and references of new algorithms are always welcome - as long as they fit into TreeLS' scope. 17 | 18 | `TreeLS` is currently on v2.0.2. To install it from an official mirror, use: `install.packages("TreeLS")`. To install the most recent version, check out the *Installation from source* section below. 19 | 20 | ## News 21 | 22 | - August/2020: Version 2.0 is finally available! It's a major release, introducing several new functionalities, bug fixes, more robust estimators for noisy clouds and more flexible plotting. All functionalities from older versions are now available and optimized, so there should be no need to use legacy code anymore. The scope of application of TreeLS has become much wider in this version, specially due to the introduction of functions like `fastPointMetrics` and `shapeFit`, making it much easier for researchers to assess point cloud data in many contexts and develop their own methods on top of those functions. For a comprehensive list of the updates check out the [CHANGELOG](https://github.com/tiagodc/TreeLS/blob/master/CHANGELOG.md). 23 | 24 | - March/2019: `TreeLS` is finally available on CRAN and is now an official R package. 25 | 26 | 27 | 28 | ## Main functionalities 29 | 30 | - Tree detection at plot level 31 | - Tree region assignment 32 | - Stem detection and denoising 33 | - Stem segmentation 34 | - Forest inventory 35 | - Fast calculation of point features 36 | - Research basis and other applications 37 | - 3D plotting and manipulation 38 | 39 | ## Installation from source 40 | 41 | ### Requirements 42 | - Rcpp compiler: 43 | - on Windows: install [Rtools](https://cran.r-project.org/bin/windows/Rtools/) for your R version - make sure to add it to your system's *path* 44 | - on Mac: install Xcode 45 | - on Linux: be sure to have `r-base-dev` installed 46 | 47 | ### Install TreeLS latest version 48 | 49 | On the R console, run: 50 | ``` 51 | remotes::install_github('tiagodc/TreeLS') 52 | ``` 53 | 54 | ## Usage 55 | 56 | Example of full processing workflow from reading a point cloud file until stem segmentation of a forest plot: 57 | ``` 58 | library(TreeLS) 59 | 60 | # open sample plot file 61 | file = system.file("extdata", "pine_plot.laz", package="TreeLS") 62 | tls = readTLS(file) 63 | 64 | # normalize the point cloud 65 | tls = tlsNormalize(tls, keep_ground = F) 66 | x = plot(tls) 67 | 68 | # extract the tree map from a thinned point cloud 69 | thin = tlsSample(tls, smp.voxelize(0.02)) 70 | map = treeMap(thin, map.hough(min_density = 0.1), 0) 71 | add_treeMap(x, map, color='yellow', size=2) 72 | 73 | # classify tree regions 74 | tls = treePoints(tls, map, trp.crop()) 75 | add_treePoints(x, tls, size=4) 76 | add_treeIDs(x, tls, cex = 2, col='yellow') 77 | 78 | # classify stem points 79 | tls = stemPoints(tls, stm.hough()) 80 | add_stemPoints(x, tls, color='red', size=8) 81 | 82 | # make the plot's inventory 83 | inv = tlsInventory(tls, d_method=shapeFit(shape='circle', algorithm = 'irls')) 84 | add_tlsInventory(x, inv) 85 | 86 | # extract stem measures 87 | seg = stemSegmentation(tls, sgt.ransac.circle(n = 20)) 88 | add_stemSegments(x, seg, color='white', fast=T) 89 | 90 | # plot everything once 91 | tlsPlot(tls, map, inv, seg, fast=T) 92 | 93 | # check out only one tree 94 | tlsPlot(tls, inv, seg, tree_id = 11) 95 | 96 | #------------------------------------------# 97 | ### overview of some new methods on v2.0 ### 98 | #------------------------------------------# 99 | 100 | file = system.file("extdata", "pine.laz", package="TreeLS") 101 | tls = readTLS(file) %>% tlsNormalize() 102 | 103 | # calculate some point metrics 104 | tls = fastPointMetrics(tls, ptm.knn()) 105 | x = plot(tls, color='Verticality') 106 | 107 | # get its stem points 108 | tls = stemPoints(tls, stm.eigen.knn(voxel_spacing = .02)) 109 | add_stemPoints(x, tls, size=3, color='red') 110 | 111 | # get dbh and height 112 | dbh_algo = shapeFit(shape='cylinder', algorithm = 'bf', n=15, inliers=.95, z_dev=10) 113 | inv = tlsInventory(tls, hp = .95, d_method = dbh_algo) 114 | add_tlsInventory(x, inv) 115 | 116 | # segment the stem usind 3D cylinders and getting their directions 117 | seg = stemSegmentation(tls, sgt.irls.cylinder(n=300)) 118 | add_stemSegments(x, seg, color='blue') 119 | 120 | # check out a specific tree segment 121 | tlsPlot(seg, tls, segment = 3) 122 | 123 | ``` 124 | -------------------------------------------------------------------------------- /TreeLS.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageBuildArgs: --resave-data 22 | PackageCheckArgs: --as-cran 23 | PackageRoxygenize: rd,collate,namespace 24 | -------------------------------------------------------------------------------- /inst/extdata/pine.laz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiagodc/TreeLS/0e0871f11358b2812adc7564ec66c39a5ab70c71/inst/extdata/pine.laz -------------------------------------------------------------------------------- /inst/extdata/pine_plot.laz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiagodc/TreeLS/0e0871f11358b2812adc7564ec66c39a5ab70c71/inst/extdata/pine_plot.laz -------------------------------------------------------------------------------- /inst/extdata/spruce.laz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiagodc/TreeLS/0e0871f11358b2812adc7564ec66c39a5ab70c71/inst/extdata/spruce.laz -------------------------------------------------------------------------------- /inst/include/algorithms.hpp: -------------------------------------------------------------------------------- 1 | // =============================================================================== 2 | // 3 | // Developers: 4 | // 5 | // Tiago de Conto - tdc.florestal@gmail.com - https://github.com/tiagodc/ 6 | // 7 | // COPYRIGHT: Tiago de Conto, 2020 8 | // 9 | // This piece of software is open and free to use, redistribution and modifications 10 | // should be done in accordance to the GNU General Public License >= 3 11 | // 12 | // Use this software as you wish, but no warranty is provided whatsoever. For any 13 | // comments or questions on TreeLS, please contact the developer (prefereably through my github account) 14 | // 15 | // If publishing any work/study/research that used the tools in TreeLS, 16 | // please don't forget to cite the proper sources! 17 | // 18 | // Enjoy! 19 | // 20 | // =============================================================================== 21 | 22 | #include 23 | 24 | #ifndef ALGORITHMS_HPP 25 | #define ALGORITHMS_HPP 26 | 27 | #include "utils.hpp" 28 | 29 | vector circleDists(vector >& xyz, arma::vec& pars); 30 | 31 | vector cylDists(vector >& xyz, arma::vec& pars); 32 | 33 | vector eigenCircle(vector >& cloud); 34 | 35 | vector irlsCircle(vector >& las, vector initPars, double err_tol = 1E-06, unsigned int max_iter = 100); 36 | 37 | vector irlsCircleFit(NumericMatrix& cloud); 38 | 39 | vector irlsCylinder(vector >& las, vector initPars, double err_tol = 1E-06, unsigned int max_iter = 100); 40 | 41 | double nmCircleDist(const arma::vec& vals_inp, arma::vec* grad_out, void* opt_data); 42 | 43 | vector nmCircleFit(vector >& las); 44 | 45 | double nmCylinderDist(const arma::vec& vals_inp, arma::vec* grad_out, void* opt_data); 46 | 47 | vector nmCylinderFit(vector >& las); 48 | 49 | vector nmCylinderInit(vector >& las); 50 | 51 | vector ransacCircle(vector >& cloud, unsigned int nSamples = 5, double pConfidence = 0.99, double pInliers = 0.8, unsigned int nBest = 0); 52 | 53 | vector ransacCylinder(vector >& las, unsigned int nSamples=10, double pConfidence=0.99, double pInliers=0.8); 54 | 55 | Eigen::Matrix stl2eigenmat(vector >& xyz); 56 | 57 | Eigen::Matrix rotationMatrix(double ax, double ay, double az); 58 | 59 | vector > eigenmat2stl(Eigen::Matrix& mat); 60 | 61 | vector > rotateCloud(vector >& xyz, double ax, double ay, double az); 62 | 63 | vector > bruteForceRansacCylinder(vector >& cloud, unsigned int nSamples, double pConfidence, double pInliers, unsigned int nBest, double maxAngle = 45.0, bool bestOnly = false); 64 | 65 | #endif // ALGORITHMS_HPP -------------------------------------------------------------------------------- /inst/include/methods.hpp: -------------------------------------------------------------------------------- 1 | // =============================================================================== 2 | // 3 | // Developers: 4 | // 5 | // Tiago de Conto - tdc.florestal@gmail.com - https://github.com/tiagodc/ 6 | // 7 | // COPYRIGHT: Tiago de Conto, 2020 8 | // 9 | // This piece of software is open and free to use, redistribution and modifications 10 | // should be done in accordance to the GNU General Public License >= 3 11 | // 12 | // Use this software as you wish, but no warranty is provided whatsoever. For any 13 | // comments or questions on TreeLS, please contact the developer (prefereably through my github account) 14 | // 15 | // If publishing any work/study/research that used the tools in TreeLS, 16 | // please don't forget to cite the proper sources! 17 | // 18 | // Enjoy! 19 | // 20 | // =============================================================================== 21 | 22 | #ifndef METHODS_HPP 23 | #define METHODS_HPP 24 | 25 | #include "algorithms.hpp" 26 | 27 | void assignTreeId(vector& disks, double distmax, double countDensity, unsigned int minLayers=1); 28 | 29 | vector getCenters(Raster* raster, double max_radius=0.25, double min_den=0.1, unsigned int min_votes=3); 30 | 31 | Raster getCounts(vector >& slice, double pixel_size); 32 | 33 | HoughCenters getSingleCenter(Raster* raster, double max_radius=0.25, double min_den=0.1, unsigned int min_votes=3); 34 | 35 | vector > > irlsPlotCircles(vector >& cloud, vector& treeId, vector& segments, vector& radii, unsigned int nPoints=100, double tolerance=0.05); 36 | 37 | vector > > irlsPlotCylinders(vector >& cloud, vector& treeId, vector& segments, vector& radii, unsigned int nPoints=100, double tolerance=0.05); 38 | 39 | vector > irlsStemCircle(vector >& cloud, vector& segments, vector& radii, unsigned int nPoints=0, double tolerance=0.05); 40 | 41 | vector > irlsStemCylinder(vector >& cloud, vector& segments, vector& radii, unsigned int nPoints=100, double tolerance=0.05); 42 | 43 | vector > > ransacPlotCircles(vector >& cloud, vector& treeId, vector& segments, vector& radii, unsigned int nSamples = 5, double pConfidence = 0.99, double pInliers = 0.8, double tolerance = 0.05); 44 | 45 | vector > > ransacPlotCylinders(vector >& cloud, vector& treeId, vector& segments, vector& radii, unsigned int nSamples=10, double pConfidence=0.95, double pInliers=0.9, double tolerance=0.05); 46 | 47 | vector< vector > ransacStemCircle(vector >& cloud, std::vector& segments, std::vector& radii, unsigned int nSamples = 5, double pConfidence = 0.99, double pInliers = 0.8, double tolerance = 0.05); 48 | 49 | vector > ransacStemCylinder(vector >& cloud, vector& segments, vector& radii, unsigned int nSamples=10, double pConfidence=0.95, double pInliers=0.9, double tolerance=0.05); 50 | 51 | vector treeHough(vector >& cppCloud, double h1 = 1, double h2 = 3, double hstep=0.5, double radius=0.25, double pixel=0.025, double density=0.1, unsigned int votes=3); 52 | 53 | vector > pointMetrics(vector >& cloud, vector >& idx, vector which_metrics); 54 | 55 | vector > voxelMetrics(vector >& cloud, vector >& idx, vector which_metrics); 56 | 57 | vector voxelIndex(vector >& cloud, double voxel_spacing=0.05); 58 | 59 | vector > > treeEigenHough(vector >& cppEigenCloud, vector& pointId, vector& segId, double voxel_size, double max_rad, bool is2d = true, bool getSpace = false); 60 | 61 | vector > > plotEigenHough(vector >& cppEigenCloud, vector& pointId, vector& treeId, vector& segId, double voxel_size, double max_rad, bool is2d = true, bool getSpace = false); 62 | 63 | vector treeIdsFromMap(vector >& xy, vector >& xymap, vector ids, double length = 2.5, bool circle = true); 64 | 65 | vector > bfStemCylinder(vector >& cloud, vector& segments, vector& radii, unsigned int nSamples = 10, double pConfidence = 0.99, double pInliers = 0.8, double max_angle = 30, double tolerance = 0.05); 66 | 67 | vector > > bfPlotCylinders(vector >& cloud, vector& treeId, vector& segments, vector& radii, unsigned int nSamples=10, double pConfidence = 0.95, double pInliers = 0.8, double max_angle = 30, double tolerance = 0.05); 68 | 69 | #endif // METHODS_HPP 70 | -------------------------------------------------------------------------------- /inst/include/misc/determine_bounds_type.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * Determine the upper-lower bounds combo type 23 | */ 24 | 25 | // note: std::isfinite is not true for: NaN, - Inf, or + Inf 26 | 27 | inline 28 | arma::uvec 29 | determine_bounds_type(const bool vals_bound, const size_t n_vals, const arma::vec& lower_bounds, const arma::vec& upper_bounds) 30 | { 31 | arma::uvec ret_vec(n_vals); 32 | 33 | ret_vec.fill(1); // base case: 1 - no bounds imposed 34 | 35 | if (vals_bound) 36 | { 37 | for (size_t i=0; i < n_vals; i++) 38 | { 39 | if ( std::isfinite(lower_bounds(i)) && std::isfinite(upper_bounds(i)) ) { 40 | // lower and upper bound imposed 41 | ret_vec(i) = 4; 42 | } else if ( std::isfinite(lower_bounds(i)) && !std::isfinite(upper_bounds(i)) ) { 43 | // lower bound only 44 | ret_vec(i) = 2; 45 | } else if ( !std::isfinite(lower_bounds(i)) && std::isfinite(upper_bounds(i)) ) { 46 | // upper bound only 47 | ret_vec(i) = 3; 48 | } 49 | } 50 | } 51 | 52 | // 53 | 54 | return ret_vec; 55 | } 56 | -------------------------------------------------------------------------------- /inst/include/misc/error_reporting.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * Error reporting 23 | */ 24 | 25 | #ifndef _optim_error_reporting_HPP 26 | #define _optim_error_reporting_HPP 27 | 28 | void error_reporting(arma::vec& out_vals, const arma::vec& x_p, std::function opt_objfn, void* opt_data, 29 | bool& success, const double err, const double err_tol, const int iter, const int iter_max, const int conv_failure_switch, algo_settings_t* settings_inp); 30 | 31 | void error_reporting(arma::vec& out_vals, const arma::vec& x_p, std::function opt_objfn, void* opt_data, 32 | bool& success, const int conv_failure_switch, algo_settings_t* settings_inp); 33 | 34 | void error_reporting(arma::vec& out_vals, const arma::vec& x_p, std::function opt_objfn, void* opt_data, 35 | bool& success, const double err, const double err_tol, const int iter, const int iter_max, const int conv_failure_switch, algo_settings_t* settings_inp); 36 | 37 | // 38 | 39 | void error_reporting(arma::vec& out_vals, const arma::vec& x_p, std::function opt_objfn, void* opt_data, 40 | bool& success, const double err, const double err_tol, const int iter, const int iter_max, const int conv_failure_switch, algo_settings_t* settings_inp); 41 | 42 | // 43 | 44 | #include "error_reporting.ipp" 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /inst/include/misc/jacobian_adjust.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * Jacobian adjustment 23 | */ 24 | 25 | inline 26 | arma::mat 27 | jacobian_adjust(const arma::vec& vals_trans_inp, const arma::uvec& bounds_type, const arma::vec& lower_bounds, const arma::vec& upper_bounds) 28 | { 29 | const size_t n_vals = bounds_type.n_elem; 30 | 31 | arma::mat ret_mat = arma::eye(n_vals,n_vals); 32 | 33 | for (size_t i=0; i < n_vals; i++) 34 | { 35 | switch (bounds_type(i)) 36 | { 37 | case 2: // lower bound only 38 | ret_mat(i,i) = std::exp(vals_trans_inp(i)); 39 | break; 40 | case 3: // upper bound only 41 | ret_mat(i,i) = std::exp(-vals_trans_inp(i)); 42 | break; 43 | case 4: // upper and lower bounds 44 | ret_mat(i,i) = std::exp(vals_trans_inp(i))*(upper_bounds(i) - lower_bounds(i)) / std::pow(std::exp(vals_trans_inp(i)) + 1,2); 45 | break; 46 | } 47 | } 48 | // 49 | return ret_mat; 50 | } 51 | -------------------------------------------------------------------------------- /inst/include/misc/misc.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | #include "determine_bounds_type.hpp" 22 | #include "error_reporting.hpp" 23 | #include "jacobian_adjust.hpp" 24 | #include "numerical_gradient.hpp" 25 | #include "numerical_hessian.hpp" 26 | #include "transform_vals.hpp" 27 | #include "unit_vec.hpp" 28 | -------------------------------------------------------------------------------- /inst/include/misc/numerical_gradient.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * Numerical Gradient, using Abramowitz and Stegun (1972, p. 883, 25.3.21) 23 | */ 24 | 25 | inline 26 | arma::vec 27 | numerical_gradient(const arma::vec& vals_inp, const double* step_size_inp, std::function objfn, void* objfn_data) 28 | { 29 | const size_t n_vals = vals_inp.n_elem; 30 | 31 | const double step_size = (step_size_inp) ? *step_size_inp : 1e-04; 32 | const double mach_eps = std::numeric_limits::epsilon(); 33 | 34 | const arma::vec step_vec = arma::max(arma::abs(vals_inp), std::sqrt(step_size)*arma::ones(n_vals,1)) * std::pow(mach_eps,1.0/6.0); 35 | 36 | arma::vec x_orig = vals_inp, x_term_1, x_term_2; 37 | arma::vec grad_vec = arma::zeros(n_vals,1); 38 | 39 | // 40 | 41 | for (size_t i=0; i < n_vals; i++) 42 | { 43 | x_term_1 = x_orig; 44 | x_term_2 = x_orig; 45 | 46 | x_term_1(i) += step_vec(i); 47 | x_term_2(i) -= step_vec(i); 48 | 49 | 50 | // 51 | 52 | double term_1 = objfn(x_term_1, nullptr, objfn_data); 53 | double term_2 = -objfn(x_term_2, nullptr, objfn_data); 54 | 55 | double denom_term = 2.0 * step_vec(i); 56 | 57 | grad_vec(i) = (term_1 + term_2) / denom_term; 58 | } 59 | 60 | // 61 | 62 | return grad_vec; 63 | } 64 | -------------------------------------------------------------------------------- /inst/include/misc/numerical_hessian.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * Numerical Hessian, using Abramowitz and Stegun (1972, p. 884, 25.3.24 and 25.3.26) 23 | */ 24 | 25 | inline 26 | arma::mat 27 | numerical_hessian(const arma::vec& vals_inp, const double* step_size_inp, std::function objfn, void* objfn_data) 28 | { 29 | const size_t n_vals = vals_inp.n_elem; 30 | 31 | const double step_size = (step_size_inp) ? *step_size_inp : 1e-04; 32 | const double mach_eps = std::numeric_limits::epsilon(); 33 | 34 | const arma::vec step_vec = arma::max(arma::abs(vals_inp), std::sqrt(step_size)*arma::ones(n_vals,1)) * std::pow(mach_eps,1.0/6.0); 35 | 36 | arma::vec x_orig = vals_inp, x_term_1, x_term_2, x_term_3, x_term_4; 37 | arma::mat hessian_mat = arma::zeros(n_vals,n_vals); 38 | 39 | const double f_orig = -30.0*objfn(x_orig, nullptr, objfn_data); 40 | 41 | // 42 | 43 | for (size_t i=0; i < n_vals; i++) 44 | { 45 | for (size_t j=i; j < n_vals; j++) 46 | { 47 | x_term_1 = x_orig; 48 | x_term_2 = x_orig; 49 | x_term_3 = x_orig; 50 | x_term_4 = x_orig; 51 | 52 | if (i==j) 53 | { 54 | x_term_1(i) += 2*step_vec(i); 55 | x_term_2(i) += step_vec(i); 56 | x_term_3(i) -= step_vec(i); 57 | x_term_4(i) -= 2*step_vec(i); 58 | 59 | // 60 | 61 | double term_1 = - objfn(x_term_1, nullptr, objfn_data); 62 | double term_2 = 16.0*objfn(x_term_2, nullptr, objfn_data); 63 | double term_3 = 16.0*objfn(x_term_3, nullptr, objfn_data); 64 | double term_4 = - objfn(x_term_4, nullptr, objfn_data); 65 | 66 | double denom_term = 12.0 * step_vec(i) * step_vec(i); 67 | 68 | hessian_mat(i,j) = (term_1 + term_2 + f_orig + term_3 + term_4) / denom_term; 69 | } 70 | else 71 | { 72 | x_term_1(i) += step_vec(i); 73 | x_term_1(j) += step_vec(j); 74 | 75 | x_term_2(i) += step_vec(i); 76 | x_term_2(j) -= step_vec(j); 77 | 78 | x_term_3(i) -= step_vec(i); 79 | x_term_3(j) += step_vec(j); 80 | 81 | x_term_4(i) -= step_vec(i); 82 | x_term_4(j) -= step_vec(j); 83 | 84 | // 85 | 86 | double term_1 = objfn(x_term_1, nullptr, objfn_data); 87 | double term_2 = -objfn(x_term_2, nullptr, objfn_data); 88 | double term_3 = -objfn(x_term_3, nullptr, objfn_data); 89 | double term_4 = objfn(x_term_4, nullptr, objfn_data); 90 | 91 | double denom_term = 4.0 * step_vec(i) * step_vec(j); 92 | 93 | hessian_mat(i,j) = (term_1 + term_2 + term_3 + term_4) / denom_term; 94 | hessian_mat(j,i) = hessian_mat(i,j); 95 | } 96 | } 97 | } 98 | 99 | // 100 | 101 | return hessian_mat; 102 | } 103 | -------------------------------------------------------------------------------- /inst/include/misc/optim_options.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | #pragma once 22 | 23 | // version 24 | 25 | #ifndef OPTIM_VERSION_MAJOR 26 | #define OPTIM_VERSION_MAJOR 1 27 | #endif 28 | 29 | #ifndef OPTIM_VERSION_MINOR 30 | #define OPTIM_VERSION_MINOR 2 31 | #endif 32 | 33 | #ifndef OPTIM_VERSION_PATCH 34 | #define OPTIM_VERSION_PATCH 0 35 | #endif 36 | 37 | // 38 | 39 | #if defined(_OPENMP) && !defined(OPTIM_DONT_USE_OPENMP) 40 | #undef OPTIM_USE_OPENMP 41 | #define OPTIM_USE_OPENMP 42 | #endif 43 | 44 | #if !defined(_OPENMP) && defined(OPTIM_USE_OPENMP) 45 | #undef OPTIM_USE_OPENMP 46 | 47 | #undef OPTIM_DONE_USE_OPENMP 48 | #define OPTIM_DONE_USE_OPENMP 49 | #endif 50 | 51 | #ifdef OPTIM_USE_OPENMP 52 | // #include "omp.h" // OpenMP 53 | #ifndef ARMA_USE_OPENMP 54 | #define ARMA_USE_OPENMP 55 | #endif 56 | #endif 57 | 58 | #ifdef OPTIM_DONT_USE_OPENMP 59 | #ifdef OPTIM_USE_OPENMP 60 | #undef OPTIM_USE_OPENMP 61 | #endif 62 | 63 | #ifndef ARMA_DONT_USE_OPENMP 64 | #define ARMA_DONT_USE_OPENMP 65 | #endif 66 | #endif 67 | 68 | // 69 | 70 | #ifdef USE_RCPP_ARMADILLO 71 | #include 72 | #else 73 | #ifndef ARMA_DONT_USE_WRAPPER 74 | #define ARMA_DONT_USE_WRAPPER 75 | #endif 76 | #include "armadillo" 77 | #endif 78 | 79 | #ifndef optimlib_inline 80 | #define optimlib_inline 81 | #endif 82 | 83 | namespace optim 84 | { 85 | static const double eps_dbl = std::numeric_limits::epsilon(); 86 | static const double inf = std::numeric_limits::infinity(); 87 | using uint_t = unsigned int; 88 | } 89 | -------------------------------------------------------------------------------- /inst/include/misc/optim_structs.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * Optimization control parameters 23 | */ 24 | 25 | #ifndef optim_structs_HPP 26 | #define optim_structs_HPP 27 | 28 | struct gd_settings_t 29 | { 30 | // step size, or 'learning rate' 31 | double step_size = 0.1; 32 | 33 | // decay 34 | bool step_decay = false; 35 | 36 | uint_t step_decay_periods = 10; 37 | double step_decay_val = 0.5; 38 | 39 | // momentum parameter 40 | double momentum_par = 0.9; 41 | 42 | // Ada parameters 43 | double norm_term = 10e-08; 44 | 45 | double ada_rho = 0.9; 46 | 47 | bool ada_max = false; 48 | 49 | // Adam parameters 50 | double adam_beta_1 = 0.9; 51 | double adam_beta_2 = 0.999; 52 | }; 53 | 54 | struct algo_settings_t 55 | { 56 | // general 57 | int verbose_print_level = 0; 58 | int conv_failure_switch = 0; 59 | int iter_max = 2000; 60 | double err_tol = 1E-08; 61 | 62 | bool vals_bound = false; 63 | 64 | arma::vec lower_bounds; 65 | arma::vec upper_bounds; 66 | 67 | // returned by algorithms 68 | double opt_value; // will be returned by the optimization algorithm 69 | arma::vec zero_values; // will be returned by the root-finding method 70 | 71 | int opt_iter; 72 | double opt_err; 73 | 74 | // SUMT parameter 75 | double sumt_par_eta = 10.0; 76 | 77 | // CG 78 | int cg_method = 2; 79 | double cg_restart_threshold = 0.1; 80 | 81 | // DE 82 | int de_n_pop = 200; 83 | int de_n_pop_best = 6; 84 | int de_n_gen = 1000; 85 | 86 | int de_pmax = 4; 87 | int de_max_fn_eval = 100000; 88 | 89 | int de_mutation_method = 1; // 1 = rand; 2 = best 90 | 91 | int de_check_freq = -1; 92 | 93 | double de_par_F = 0.8; 94 | double de_par_CR = 0.9; 95 | 96 | double de_par_F_l = 0.1; 97 | double de_par_F_u = 1.0; 98 | 99 | double de_par_tau_F = 0.1; 100 | double de_par_tau_CR = 0.1; 101 | 102 | arma::vec de_initial_lb; // this will default to -0.5 103 | arma::vec de_initial_ub; // this will default to 0.5 104 | 105 | // GD 106 | int gd_method = 0; 107 | gd_settings_t gd_settings; 108 | 109 | // L-BFGS 110 | int lbfgs_par_M = 10; 111 | 112 | // Nelder-Mead 113 | bool nm_adaptive= true; 114 | 115 | double nm_par_alpha = 1.0; // reflection parameter 116 | double nm_par_beta = 0.5; // contraction parameter 117 | double nm_par_gamma = 2.0; // expansion parameter 118 | double nm_par_delta = 0.5; // shrinkage parameter 119 | 120 | // PSO 121 | bool pso_center_particle = true; 122 | 123 | int pso_n_pop = 100; 124 | int pso_n_gen = 1000; 125 | 126 | int pso_inertia_method = 1; // 1 for linear decreasing between w_min and w_max; 2 for dampening 127 | 128 | int pso_check_freq = -1; 129 | 130 | double pso_par_initial_w = 1.0; 131 | double pso_par_w_damp = 0.99; 132 | 133 | double pso_par_w_min = 0.10; 134 | double pso_par_w_max = 0.99; 135 | 136 | int pso_velocity_method = 1; // 1 for fixed; 2 for linear 137 | 138 | double pso_par_c_cog = 2.0; 139 | double pso_par_c_soc = 2.0; 140 | 141 | double pso_par_initial_c_cog = 2.5; 142 | double pso_par_final_c_cog = 0.5; 143 | double pso_par_initial_c_soc = 0.5; 144 | double pso_par_final_c_soc = 2.5; 145 | 146 | arma::vec pso_initial_lb; // this will default to -0.5 147 | arma::vec pso_initial_ub; // this will default to 0.5 148 | }; 149 | 150 | #endif 151 | -------------------------------------------------------------------------------- /inst/include/misc/transform_vals.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * transform values 23 | */ 24 | 25 | inline 26 | arma::vec 27 | transform(const arma::vec& vals_inp, const arma::uvec& bounds_type, const arma::vec& lower_bounds, const arma::vec& upper_bounds) 28 | { 29 | const size_t n_vals = bounds_type.n_elem; 30 | 31 | arma::vec vals_trans_out(n_vals); 32 | 33 | for (size_t i=0; i < n_vals; i++) 34 | { 35 | switch (bounds_type(i)) 36 | { 37 | case 1: // no bounds 38 | vals_trans_out(i) = vals_inp(i); 39 | break; 40 | case 2: // lower bound only 41 | vals_trans_out(i) = std::log(vals_inp(i) - lower_bounds(i) + eps_dbl); 42 | break; 43 | case 3: // upper bound only 44 | vals_trans_out(i) = - std::log(upper_bounds(i) - vals_inp(i) + eps_dbl); 45 | break; 46 | case 4: // upper and lower bounds 47 | vals_trans_out(i) = std::log(vals_inp(i) - lower_bounds(i) + eps_dbl) - std::log(upper_bounds(i) - vals_inp(i) + eps_dbl); 48 | break; 49 | } 50 | } 51 | 52 | // 53 | 54 | return vals_trans_out; 55 | } 56 | 57 | inline 58 | arma::vec 59 | inv_transform(const arma::vec& vals_trans_inp, const arma::uvec& bounds_type, const arma::vec& lower_bounds, const arma::vec& upper_bounds) 60 | { 61 | const size_t n_vals = bounds_type.n_elem; 62 | 63 | arma::vec vals_out(n_vals); 64 | 65 | for (size_t i=0; i < n_vals; i++) 66 | { 67 | switch (bounds_type(i)) 68 | { 69 | case 1: // no bounds 70 | vals_out(i) = vals_trans_inp(i); 71 | break; 72 | case 2: // lower bound only 73 | if (!std::isfinite(vals_trans_inp(i))) 74 | { 75 | vals_out(i) = lower_bounds(i) + eps_dbl; 76 | } 77 | else 78 | { 79 | vals_out(i) = lower_bounds(i) + eps_dbl + std::exp(vals_trans_inp(i)); 80 | } 81 | break; 82 | case 3: // upper bound only 83 | if (!std::isfinite(vals_trans_inp(i))) 84 | { 85 | vals_out(i) = upper_bounds(i) - eps_dbl; 86 | } 87 | else 88 | { 89 | vals_out(i) = upper_bounds(i) - eps_dbl - std::exp(-vals_trans_inp(i)); 90 | } 91 | break; 92 | case 4: // upper and lower bounds 93 | if (!std::isfinite(vals_trans_inp(i))) 94 | { 95 | if (std::isnan(vals_trans_inp(i))) 96 | { 97 | vals_out(i) = (upper_bounds(i) - lower_bounds(i)) / 2.0; 98 | } 99 | else if (vals_trans_inp(i) < 0.0) 100 | { 101 | vals_out(i) = lower_bounds(i) + eps_dbl; 102 | } 103 | else 104 | { 105 | vals_out(i) = upper_bounds(i) - eps_dbl; 106 | } 107 | } 108 | else 109 | { 110 | vals_out(i) = ( lower_bounds(i) + eps_dbl + (upper_bounds(i) - eps_dbl)*std::exp(vals_trans_inp(i)) ) \ 111 | / ( 1.0 + std::exp(vals_trans_inp(i)) ); 112 | 113 | if (!std::isfinite(vals_out(i))) 114 | { 115 | vals_out(i) = upper_bounds(i) - eps_dbl; 116 | } 117 | } 118 | break; 119 | } 120 | } 121 | 122 | // 123 | 124 | return vals_out; 125 | } 126 | -------------------------------------------------------------------------------- /inst/include/misc/unit_vec.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * unit vector 23 | */ 24 | 25 | #ifndef _optim_unit_vec_HPP 26 | #define _optim_unit_vec_HPP 27 | 28 | inline arma::vec unit_vec(const size_t j, const size_t n); 29 | 30 | #include "unit_vec.ipp" 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /inst/include/misc/unit_vec.ipp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * unit vector 23 | */ 24 | 25 | inline 26 | arma::vec 27 | unit_vec(const size_t j, const size_t n) 28 | { 29 | arma::vec ret = arma::zeros(n,1); 30 | ret(j) = 1; 31 | 32 | return ret; 33 | } 34 | -------------------------------------------------------------------------------- /inst/include/optim.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | #ifndef OPTIMLIB_INCLUDES 22 | #define OPTIMLIB_INCLUDES 23 | 24 | #include "misc/optim_options.hpp" 25 | 26 | namespace optim 27 | { 28 | // structs 29 | #include "misc/optim_structs.hpp" 30 | 31 | // misc files 32 | #include "misc/misc.hpp" 33 | 34 | // line search 35 | #include "line_search/more_thuente.hpp" 36 | 37 | // unconstrained optimization 38 | #include "unconstrained/bfgs.hpp" 39 | #include "unconstrained/lbfgs.hpp" 40 | #include "unconstrained/newton.hpp" 41 | #include "unconstrained/cg.hpp" 42 | #include "unconstrained/gd.hpp" 43 | #include "unconstrained/de.hpp" 44 | #include "unconstrained/de_prmm.hpp" 45 | #include "unconstrained/nm.hpp" 46 | #include "unconstrained/pso.hpp" 47 | #include "unconstrained/pso_dv.hpp" 48 | 49 | // constrained optimization 50 | #include "constrained/sumt.hpp" 51 | 52 | // solving systems of nonlinear equations 53 | #include "zeros/broyden.hpp" 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /inst/include/unconstrained/newton.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * Newton's method for non-linear optimization 23 | */ 24 | 25 | #ifndef _optim_newton_HPP 26 | #define _optim_newton_HPP 27 | 28 | bool newton_int(arma::vec& init_out_vals, std::function opt_objfn, void* opt_data, algo_settings_t* settings_inp); 29 | 30 | bool newton(arma::vec& init_out_vals, std::function opt_objfn, void* opt_data); 31 | bool newton(arma::vec& init_out_vals, std::function opt_objfn, void* opt_data, algo_settings_t& settings); 32 | 33 | // 34 | 35 | inline 36 | bool 37 | newton_int(arma::vec& init_out_vals, std::function opt_objfn, void* opt_data, algo_settings_t* settings_inp) 38 | { 39 | // notation: 'p' stands for '+1'. 40 | 41 | bool success = false; 42 | 43 | const size_t n_vals = init_out_vals.n_elem; 44 | 45 | // 46 | // Newton settings 47 | 48 | algo_settings_t settings; 49 | 50 | if (settings_inp) 51 | { 52 | settings = *settings_inp; 53 | } 54 | 55 | const uint_t conv_failure_switch = settings.conv_failure_switch; 56 | const uint_t iter_max = settings.iter_max; 57 | const double err_tol = settings.err_tol; 58 | 59 | // 60 | // initialization 61 | 62 | arma::vec x = init_out_vals; 63 | 64 | if (!x.is_finite()) 65 | { 66 | Rprintf("newton error: non-finite initial value(s).\n"); 67 | return false; 68 | } 69 | 70 | arma::mat H(n_vals,n_vals); // hessian matrix 71 | arma::vec grad(n_vals); // gradient vector 72 | opt_objfn(x,&grad,&H,opt_data); 73 | 74 | double err = arma::norm(grad, 2); 75 | if (err <= err_tol) { 76 | return true; 77 | } 78 | 79 | // 80 | // if ||gradient(initial values)|| > tolerance, then continue 81 | 82 | arma::vec d = - arma::solve(H,grad); // Newton direction 83 | 84 | arma::vec x_p = x + d; // no line search used here 85 | 86 | opt_objfn(x_p,&grad,&H,opt_data); 87 | 88 | err = arma::norm(grad, 2); 89 | if (err <= err_tol) 90 | { 91 | init_out_vals = x_p; 92 | return true; 93 | } 94 | 95 | // 96 | // begin loop 97 | 98 | uint_t iter = 0; 99 | 100 | while (err > err_tol && iter < iter_max) 101 | { 102 | iter++; 103 | 104 | // 105 | 106 | d = - arma::solve(H,grad); 107 | x_p = x + d; 108 | 109 | opt_objfn(x_p,&grad,&H,opt_data); 110 | 111 | // 112 | 113 | err = arma::norm(grad, 2); 114 | if (err <= err_tol) { 115 | break; 116 | } 117 | 118 | err = arma::norm(x_p - x, 2); 119 | 120 | // 121 | 122 | x = x_p; 123 | } 124 | 125 | // 126 | 127 | error_reporting(init_out_vals,x_p,opt_objfn,opt_data,success,err,err_tol,iter,iter_max,conv_failure_switch,settings_inp); 128 | 129 | return success; 130 | } 131 | 132 | inline 133 | bool 134 | newton(arma::vec& init_out_vals, std::function opt_objfn, void* opt_data) 135 | { 136 | return newton_int(init_out_vals,opt_objfn,opt_data,nullptr); 137 | } 138 | 139 | inline 140 | bool 141 | newton(arma::vec& init_out_vals, std::function opt_objfn, void* opt_data, algo_settings_t& settings) 142 | { 143 | return newton_int(init_out_vals,opt_objfn,opt_data,&settings); 144 | } 145 | 146 | #endif 147 | -------------------------------------------------------------------------------- /inst/include/utils.hpp: -------------------------------------------------------------------------------- 1 | // =============================================================================== 2 | // 3 | // Developers: 4 | // 5 | // Tiago de Conto - tdc.florestal@gmail.com - https://github.com/tiagodc/ 6 | // 7 | // COPYRIGHT: Tiago de Conto, 2020 8 | // 9 | // This piece of software is open and free to use, redistribution and modifications 10 | // should be done in accordance to the GNU General Public License >= 3 11 | // 12 | // Use this software as you wish, but no warranty is provided whatsoever. For any 13 | // comments or questions on TreeLS, please contact the developer (prefereably through my github account) 14 | // 15 | // If publishing any work/study/research that used the tools in TreeLS, 16 | // please don't forget to cite the proper sources! 17 | // 18 | // Enjoy! 19 | // 20 | // =============================================================================== 21 | 22 | #ifndef UTILS_HPP 23 | #define UTILS_HPP 24 | 25 | #include "classes.hpp" 26 | using namespace Rcpp; 27 | 28 | void bringOrigin(vector >& las); 29 | 30 | vector > cropCloud(vector > cloud, double xCenter, double yCenter, double len = 1, bool circle = true, bool negative = false); 31 | 32 | vector cropCloudFilter(vector > cloud, double xCenter, double yCenter, double len = 1, bool circle = true, bool negative = false); 33 | 34 | vector > > getChunks(vector >& cloud, vector& identifier); 35 | 36 | vector > > getFullChunks(vector >& cloud, vector& identifier); 37 | 38 | vector getMinMax(vector >& xyz); 39 | 40 | vector > > getSlices(vector >& cloud, double zmin = 1, double zmax=3, double zstep = 0.5); 41 | 42 | vector > > getSlices(NumericMatrix& cloud, double zmin = 1, double zmax=3, double zstep = 0.5); 43 | 44 | vector idSortUnique(vector& identifier, vector& values); 45 | 46 | vector idSortUnique(vector& identifier, vector& values); 47 | 48 | double mad(vector x, double c = 1.4826); 49 | 50 | double median(vector x); 51 | 52 | double variance(vector& x); 53 | 54 | vector > partitionIndex(vector& identifier, vector& partitioner); 55 | 56 | vector > partitionIndex(vector& identifier, vector& partitioner); 57 | 58 | vector > randomPoints(vector >& cloud, double p = 0.5); 59 | 60 | vector > rmatrix2cpp(NumericMatrix& cloud); 61 | 62 | void tukeyBiSq(vector& werrors, double b = 5); 63 | 64 | vector voxelFilter(vector >& cloud, double voxel_spacing = 0.025); 65 | 66 | vector xprod(vector& a, vector& b); 67 | 68 | void eigenDecomposition(vector >& cloud, vector* eiVals, vector >* eiVecs); 69 | 70 | vector pointDistances(vector >& cloud); 71 | 72 | vector nnMetrics(vector >& xyz, vector which); 73 | 74 | vector > intmatrix2cpp(NumericMatrix& idxMatrix); 75 | 76 | double vecAngle(vector& a, vector& b); 77 | 78 | vector > voxelCounter(vector >& xyzNormals, double voxel, double max_rad, bool is2d = false, bool sendSpace = false); 79 | 80 | vector > splitVector(vector& to_split, vector& split_by); 81 | 82 | vector > fastApply(vector >& matrix, vector& funcList); 83 | 84 | vector sortIndexes(vector& values); 85 | 86 | unsigned int uniqueTotalCounter(vector input); 87 | 88 | void progressPrinter(string units, unsigned int n, unsigned int total); 89 | 90 | #endif // UTILS_HPP 91 | -------------------------------------------------------------------------------- /man-roxygen/example-segmentation.R: -------------------------------------------------------------------------------- 1 | #' @examples 2 | #' ### single tree 3 | #' file = system.file("extdata", "pine.laz", package="TreeLS") 4 | #' tls = readTLS(file) 5 | #' tls = stemPoints(tls) 6 | #' df = stemSegmentation(tls) 7 | #' 8 | #' head(df) 9 | #' tlsPlot(tls, df) 10 | #' 11 | #' ### forest plot 12 | #' file = system.file("extdata", "pine_plot.laz", package="TreeLS") 13 | #' tls = readTLS(file) 14 | #' 15 | #' # normalize the point cloud 16 | #' tls = tlsNormalize(tls) 17 | #' 18 | #' # map the trees on a resampled point cloud so all trees have approximately the same point density 19 | #' thin = tlsSample(tls, voxelize(0.02)) 20 | #' map = treeMap(thin, map.hough(min_density = 0.05)) 21 | #' 22 | #' tls = stemPoints(tls, map) 23 | #' df = stemSegmentation(tls, sgmt.ransac.circle(n=10)) 24 | #' 25 | #' head(df) 26 | #' tlsPlot(tls, df, map) 27 | -------------------------------------------------------------------------------- /man-roxygen/example-tree-map.R: -------------------------------------------------------------------------------- 1 | #' @examples 2 | #' file = system.file("extdata", "pine_plot.laz", package="TreeLS") 3 | #' tls = readTLS(file) %>% 4 | #' tlsNormalize %>% 5 | #' tlsSample 6 | #' 7 | #' x = plot(tls) 8 | #' 9 | #' map = treeMap(tls, map.hough(h_step = 1, max_h = 4)) 10 | #' add_treeMap(x, map, color='red') 11 | #' 12 | #' xymap = treeMap.positions(map) 13 | -------------------------------------------------------------------------------- /man-roxygen/param-colnames.R: -------------------------------------------------------------------------------- 1 | #' @param col_names optional - \code{character} vector. Only used for table-like objects. It states the column names. If not set, only the 3 first columns will be used and assigned to the XYZ fields. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-conf.R: -------------------------------------------------------------------------------- 1 | #' @param conf \code{numeric} - confidence level. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-h_step.R: -------------------------------------------------------------------------------- 1 | #' @param h_step \code{numeric} - height interval to perform point filtering/assignment/classification. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-hbase.R: -------------------------------------------------------------------------------- 1 | #' @param h_base \code{numeric} vector of length 2 - tree base height interval to initiate circle search. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-inliers.R: -------------------------------------------------------------------------------- 1 | #' @param inliers \code{numeric} - expected proportion of inliers among stem segments' point cloud chunks. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-las.R: -------------------------------------------------------------------------------- 1 | #' @param las \code{\link[lidR:LAS]{LAS}} object. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-max-curvature.R: -------------------------------------------------------------------------------- 1 | #' @param max_curvature \code{numeric} - maximum curvature (from 0 to 1) accepted when filtering a point neighborhood. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-max-d.R: -------------------------------------------------------------------------------- 1 | #' @param max_d \code{numeric} - largest tree diameter expected in the point cloud. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-max-radius.R: -------------------------------------------------------------------------------- 1 | #' @param max_radius \code{numeric} - approximately the largest stem cross section radius expected in the point cloud. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-max-verticality.R: -------------------------------------------------------------------------------- 1 | #' @param max_verticality \code{numeric} - maximum deviation of a point neighborhood's orientation from an absolute vertical axis ( Z = c(0,0,1) ), in \emph{degrees} (from 0 to 90). 2 | -------------------------------------------------------------------------------- /man-roxygen/param-min-density.R: -------------------------------------------------------------------------------- 1 | #' @param min_density \code{numeric} - between 0 and 1 - minimum point density within a pixel evaluated on the Hough Transform - i.e. only \emph{dense} point clousters will undergo circle search. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-min-h.R: -------------------------------------------------------------------------------- 1 | #' @param min_h \code{numeric} - minimum height of a point cluster to consider it as a tree. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-min-n.R: -------------------------------------------------------------------------------- 1 | #' @param min_n \code{numeric} - lowest point count accepted in a tree's point cluster. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-min-votes.R: -------------------------------------------------------------------------------- 1 | #' @param min_votes \code{integer} - Hough Transform parameter - minimum number of circle intersections over a pixel to assign it as a circle center candidate. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-min_h-max_h.R: -------------------------------------------------------------------------------- 1 | #' @param min_h,max_h \code{numeric} - height thresholds applied to filter a point cloud before processing. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-n-best.R: -------------------------------------------------------------------------------- 1 | #' @param n_best \code{integer} - estimate optimal RANSAC parameters as the median of the \code{n_best} estimations with lowest error. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-n-ransac.R: -------------------------------------------------------------------------------- 1 | #' @param n \code{numeric} - number of points selected on every RANSAC iteration. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-pixel-size.R: -------------------------------------------------------------------------------- 1 | #' @param pixel_size \code{numeric} - pixel side length to discretize the point cloud layers while performing the Hough Transform circle search. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-tol.R: -------------------------------------------------------------------------------- 1 | #' @param tol \code{numeric} - tolerance offset between absolute radii estimates and hough transform estimates. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-v3d.R: -------------------------------------------------------------------------------- 1 | #' @param v3d \code{logical} - count votes in 3D voxels (TRUE) or 2D pixels (FALSE). 2 | -------------------------------------------------------------------------------- /man-roxygen/param-votes-weight.R: -------------------------------------------------------------------------------- 1 | #' @param votes_weight \code{numeric} - fraction of votes a point neighborhood needs do reach in order to belong to a stem (applied for every \emph{TreeID}), in relation to the voxel with most votes with same \emph{TreeID}. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-voxel-spacing.R: -------------------------------------------------------------------------------- 1 | #' @param voxel_spacing \code{numeric} - voxel side length. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-z-dev.R: -------------------------------------------------------------------------------- 1 | #' @param z_dev \code{numeric} - maximum angle deviation for brute force cylinder estimation (\code{bf}), i.e. angle, in degrees (0-90), that a cylinder can be tilted in relation to a perfect vertival axis (\code{Z = c(0,0,1)}). 2 | -------------------------------------------------------------------------------- /man-roxygen/reference-liang.R: -------------------------------------------------------------------------------- 1 | #' @references 2 | #' Liang, X. et al., 2012. Automatic stem mapping using single-scan terrestrial laser scanning. IEEE Transactions on Geoscience and Remote Sensing, 50(2), pp.661–670. 3 | -------------------------------------------------------------------------------- /man-roxygen/reference-olofsson-2016.R: -------------------------------------------------------------------------------- 1 | #' @references 2 | #' Olofsson, K. & Holmgren, J., 2016. Single Tree Stem Profile Detection Using Terrestrial Laser Scanner Data, Flatness Saliency Features and Curvature Properties. Forests, 7, 207. 3 | -------------------------------------------------------------------------------- /man-roxygen/reference-olofsson.R: -------------------------------------------------------------------------------- 1 | #' @references 2 | #' Olofsson, K., Holmgren, J. & Olsson, H., 2014. Tree stem and height measurements using terrestrial laser scanning and the RANSAC algorithm. Remote Sensing, 6(5), pp.4323–4344. 3 | -------------------------------------------------------------------------------- /man-roxygen/reference-thesis.R: -------------------------------------------------------------------------------- 1 | #' @references 2 | #' Conto, T. et al., 2017. Performance of stem denoising and stem modelling algorithms on single tree point clouds from terrestrial laser scanning. Computers and Electronics in Agriculture, v. 143, p. 165-176. 3 | -------------------------------------------------------------------------------- /man-roxygen/reference-wang.R: -------------------------------------------------------------------------------- 1 | #' @references 2 | #' Wang, D.; Hollaus, M.; Pfeifer, N., 2017. Feasibility of machine learning methods for separating wood and leaf points from terrestrial laser scanning data. ISPRS Annals of the Photogrammetry, Remote Sensing and Spatial Information Sciences, Volume IV-2/W4. 3 | -------------------------------------------------------------------------------- /man-roxygen/reference-zhou.R: -------------------------------------------------------------------------------- 1 | #' @references 2 | #' Zhou, J. et. al., 2019. Separating leaf and wood points in terrestrial scanning data using multiple optimal scales. Sensors, 19(8):1852. 3 | -------------------------------------------------------------------------------- /man-roxygen/return-las.R: -------------------------------------------------------------------------------- 1 | #' @return \code{\link[lidR:LAS]{LAS}} object. 2 | -------------------------------------------------------------------------------- /man-roxygen/section-brute-force.R: -------------------------------------------------------------------------------- 1 | #' @section Brute Force Cylinder Fit: 2 | #' 3 | #' The brute force cylinder fit approach estimates the axis rotation 4 | #' angles by brute force combined with 2D ransac circle fit. The coordinates 5 | #' of a point cloud representing a single cylinder are iteratively rotated up 6 | #' to a pre defined threshold, and for every iteration a circle is estimated after 7 | #' rotation is performed. The rotation that minimizes the circle parameters the most 8 | #' is used to describe the axis direction of the cylinder with the circle's radius. 9 | #' 10 | #' The parameters returned by the brute force cylinder fit method are: 11 | #' \itemize{ 12 | #' \item \code{X,Y}: 2D circle center coordinates after rotation 13 | #' \item \code{Radius}: 3D circle radius, in point cloud units 14 | #' \item \code{Error}: model circle error from the RANSAC least squares fit, after rotation 15 | #' \item \code{DX,DY}: absolute rotation angles (in degrees) applied to the X and Y axes, respectively 16 | #' \item \code{AvgHeight}: average height of the stem segment's points 17 | #' \item \code{N}: number of points belonging to the stem segment 18 | #' } 19 | -------------------------------------------------------------------------------- /man-roxygen/section-circlefit.R: -------------------------------------------------------------------------------- 1 | #' @section Least Squares Circle Fit: 2 | #' 3 | #' The circle fit methods applied in \emph{TreeLS} estimate the circle parameters (its center's XY coordinates and radius) 4 | #' from a pre-selected (denoised) set of points in a least squares fashion 5 | #' by applying either \href{https://en.wikipedia.org/wiki/QR_decomposition}{QR decompostion}, used in combination 6 | #' with the RANSAC algorithm, or \href{https://en.wikipedia.org/wiki/Nelder-Mead_method}{Nelder-Mead simplex} 7 | #' optimization combined the IRLS approach. 8 | #' 9 | #' The parameters returned by the circle fit methods are: 10 | #' \itemize{ 11 | #' \item \code{X,Y}: 2D circle center coordinates 12 | #' \item \code{Radius}: 2D circle radius, in point cloud units 13 | #' \item \code{Error}: model circle error from the least squares fit 14 | #' \item \code{AvgHeight}: average height of the stem segment's points 15 | #' \item \code{N}: number of points belonging to the stem segment 16 | #' } 17 | -------------------------------------------------------------------------------- /man-roxygen/section-cylinderfit.R: -------------------------------------------------------------------------------- 1 | #' @section Least Squares Cylinder Fit: 2 | #' 3 | #' \loadmathjax 4 | #' 5 | #' The cylinder fit methods implemented in \emph{TreeLS} estimate a 3D 6 | #' cylinder`s axis direction and radius. The algorithm used internally 7 | #' to optimize the cylinder parameters is the 8 | #' \href{https://en.wikipedia.org/wiki/Nelder-Mead_method}{Nelder-Mead simplex}, 9 | #' which takes as objective function the model describing the distance from any point 10 | #' to a modelled cylinder`s surface on a regular 3D cylinder point cloud: 11 | #' 12 | #' \mjdeqn{D_{p} = |(p - q) \times a| - r}{Dp = abs((p - q) x a) - r} 13 | #' 14 | #' where: 15 | #' 16 | #' \itemize{ 17 | #' \item \emph{Dp}: distance from a point to the model cylinder`s surface 18 | #' \item \emph{p}: a point on the cylinder`s surface 19 | #' \item \emph{q}: a point on the cylinder`s axis 20 | #' \item \emph{a}: unit vector of cylinder`s direction 21 | #' \item \emph{r}: cylinder`s radius 22 | #' } 23 | #' 24 | #' The Nelder-Mead algorithm minimizes the sum of squared \emph{Dp} from 25 | #' a set of points belonging to a stem segment - in the context of \emph{TreeLS}. 26 | #' 27 | #' The parameters returned by the cylinder fit methods are: 28 | #' \itemize{ 29 | #' \item \code{rho,theta,phi,alpha}: 3D cylinder estimated axis parameters (Liang et al. 2012) 30 | #' \item \code{Radius}: 3D cylinder radius, in point cloud units 31 | #' \item \code{Error}: model cylinder error from the least squares fit 32 | #' \item \code{AvgHeight}: average height of the stem segment's points 33 | #' \item \code{N}: number of points belonging to the stem segment 34 | #' \item \code{PX,PY,PZ}: absolute center positions of the stem segment points, in point cloud units (used for plotting) 35 | #' } 36 | -------------------------------------------------------------------------------- /man-roxygen/section-eigen-decomposition.R: -------------------------------------------------------------------------------- 1 | #' @section Eigen Decomposition of Point Neighborhoods: 2 | #' 3 | #' Point filtering/classification methods that rely on eigen 4 | #' decomposition rely on shape indices calculated for point 5 | #' neighborhoods (knn or voxel). To derive these shape indices, eigen 6 | #' decomposition is performed on the XYZ columns of a point cloud patch. 7 | #' Metrics related to object curvature are calculated upon ratios of the resulting 8 | #' eigen values, and metrics related to object orientation are caltulated from 9 | #' approximate normals obtained from the eigen vectors. 10 | #' 11 | #' For instance, a point neighborhood that belongs to a perfect flat 12 | #' surface will have all of its variance explained by the first two eigen values, 13 | #' and none explained by the third eigen value. The 'normal' of such surface, 14 | #' i.e. the vector oriented in the direction orthogonal to the surface, 15 | #' is therefore represented by the third eigenvector. 16 | #' 17 | #' Methods for both tree mapping and stem segmentation use those metrics, so in order 18 | #' to speed up the workflow one might apply \code{\link{fastPointMetrics}} to the point 19 | #' cloud before other methods. The advantages of this approach are that users 20 | #' can parameterize the point neighborhoods themselves when calculating their metrics. 21 | #' Those calculations won't be performed again internally in the tree mapping or stem 22 | #' denoising methods, reducing the overall processing time. 23 | -------------------------------------------------------------------------------- /man-roxygen/section-hough-transform.R: -------------------------------------------------------------------------------- 1 | #' @section Adapted Hough Transform: 2 | #' 3 | #' The Hough Transform circle search algorithm used in 4 | #' TreeLS applies a constrained circle search on discretized 5 | #' point cloud layers. Tree-wise, the circle search is 6 | #' recursive, in which the search for circle parameters 7 | #' of a stem section is constrained to the 8 | #' \emph{feature space} of the stem section underneath it. 9 | #' Initial estimates of the stem's \emph{feature space} 10 | #' are performed on a \emph{baselise} stem segment - i.e. 11 | #' a low height interval where a tree's bole is expected 12 | #' to be clearly visible in the point cloud. 13 | #' The algorithm is described in detail by Conto et al. (2017). 14 | #' 15 | #' This adapted version of the algorithm is very robust against outliers, 16 | #' but not against forked or leaning stems. 17 | -------------------------------------------------------------------------------- /man-roxygen/section-irls.R: -------------------------------------------------------------------------------- 1 | #' @section Iterative Reweighted Least Squares (IRLS) Algorithm: 2 | #' 3 | #' \emph{irls} \code{circle} or \code{cylinder} estimation methods 4 | #' perform automatic outlier assigning through iterative reweighting 5 | #' with M-estimators, followed by a Nelder-Mead optimization of squared distance sums 6 | #' to determine the best circle/cylinder parameters for a given point 7 | #' cloud. The reweighting strategy used in \emph{TreeLS} is based on 8 | #' Liang et al. (2012). The Nelder-Mead algorithm implemented in Rcpp was provided by 9 | #' \href{https://github.com/kthohr/optim}{kthohr/optim}. 10 | #' @template reference-liang 11 | -------------------------------------------------------------------------------- /man-roxygen/section-knn.R: -------------------------------------------------------------------------------- 1 | #' @section K Neares Neighbors (KNN) Point Cloud Search: 2 | #' 3 | #' Methods that rely on nearest neighborhood search use the 4 | #' \code{\link[nabor:knn]{knn}} from the \code{nabor} package. -------------------------------------------------------------------------------- /man-roxygen/section-normals-voting.R: -------------------------------------------------------------------------------- 1 | #' @section Radius Estimation Through Normal Vectors Intersection: 2 | #' 3 | #' \code{stemPoints} methods that filter points based on eigen decomposition 4 | #' metrics (knn or voxel) provide a rough estimation of stem segments radii 5 | #' by splitting every stem segment into a local voxel space and counting 6 | #' the number of times that point normals intersect on every voxel (votes). 7 | #' Every stem point then has a radius assigned to it, corresponding to the distance 8 | #' between the point and the voxel with most votes its normal intersects. The average of 9 | #' all points' radii in a stem segment is the segment's radius. For approximately straight 10 | #' vertical stem segments, the voting can be done in 2D (pixels). 11 | #' 12 | #' The point normals of this method are extracted from the eigen vectors calculated by 13 | #' \code{\link{fastPointMetrics}}. On top of the point metrics used for stem point filtering, the following 14 | #' fields are also added to the \code{LAS} object: 15 | #' 16 | #' \itemize{ 17 | #' \item \code{Votes}: number of normal vector intersections crossing the point's normal at its estimated center 18 | #' \item \code{VotesWeight}: ratio of (votes count) / (highest votes count) per \emph{TreeID} 19 | #' \item \code{Radius}: estimated stem segment radius 20 | #' } 21 | #' 22 | #' This method was inspired by the denoising algorithm developed by Olofsson & Holmgren (2016), 23 | #' but it is not an exact reproduction of their work. 24 | -------------------------------------------------------------------------------- /man-roxygen/section-point-metrics.R: -------------------------------------------------------------------------------- 1 | #' @section List of available point metrics: 2 | #' 3 | #' \loadmathjax 4 | #' 5 | #' * \emph{EVi} = \emph{i}-th 3D eigen value 6 | #' 7 | #' * \emph{EV2Di} = \emph{i}-th 2D eigen value 8 | #' 9 | #' \itemize{ 10 | #' \item \code{N}: number of nearest neighbors 11 | #' \item \code{MinDist}: minimum distance among neighbors 12 | #' \item \code{MaxDist}: maximum distance among neighbors 13 | #' \item \code{MeanDist}: mean distance 14 | #' \item \code{SdDist}: standard deviation of within neighborhood distances 15 | #' \item \code{Linearity}: linear saliency, \mjeqn{(EV_{1} + EV_{2}) / EV_{1}}{(EV1 + EV2) / EV1} 16 | #' \item \code{Planarity}: planar saliency, \mjeqn{(EV_{2} + EV_{3}) / EV_{1}}{(EV2 + EV3) / EV1} 17 | #' \item \code{Scattering}: \mjeqn{EV_{3} / EV_{1}}{EV3 / EV1} 18 | #' \item \code{Omnivariance}: \mjeqn{(EV_{2} + EV_{3}) / EV_{1}}{(EV2 + EV3) / EV1} 19 | #' \item \code{Anisotropy}: \mjeqn{(EV_{1} - EV_{3}) / EV_{1}}{(EV1 - EV3) / EV1} 20 | #' \item \code{Eigentropy}: \mjeqn{- \sum_{i=1}^{n=3} EV_{i} * ln(EV_{i})}{-sum(EV * ln(EV))} 21 | #' \item \code{EigenSum}: sum of eigenvalues, \mjeqn{\sum_{i=1}^{n=3} EV_{i}}{sum(EV)} 22 | #' \item \code{Curvature}: surface variation, \mjeqn{EV_{3} / EigenSum}{EV3 / EigenSum} 23 | #' \item \code{KnnRadius}: 3D neighborhood radius 24 | #' \item \code{KnnDensity}: 3D point density (N / sphere volume) 25 | #' \item \code{Verticality}: absolute vertical deviation, in degrees 26 | #' \item \code{ZRange}: point neighborhood height difference 27 | #' \item \code{ZSd}: standard deviation of point neighborhood heights 28 | #' \item \code{KnnRadius2d}: 2D neighborhood radius 29 | #' \item \code{KnnDensity2d}: 2D point density (N / circle area) 30 | #' \item \code{EigenSum2d}: sum of 2D eigenvalues, \mjeqn{\sum_{i=1}^{n=2} EV2D_{i}}{sum(EV2D)} 31 | #' \item \code{EigenRatio2d}: \mjeqn{EV2D_{2} / EV2D_{1}}{EV2D2 / EV2D1} 32 | #' \item \code{EigenValuei}: 3D eigenvalues 33 | #' \item \code{EigenVectorij}: 3D eigenvector coefficients, \emph{i}-th load of \emph{j}-th eigenvector 34 | #' } 35 | -------------------------------------------------------------------------------- /man-roxygen/section-ransac.R: -------------------------------------------------------------------------------- 1 | #' @section Random Sample Consensus (RANSAC) Algorithm: 2 | #' 3 | #' \loadmathjax 4 | #' 5 | #' The \strong{RAN}dom \strong{SA}mple \strong{C}onsensus algorithm is a method that relies on resampling 6 | #' a data set as many times as necessary to find a subset comprised of only inliers - e.g. observations 7 | #' belonging to a desired model. The RANSAC algorithm provides a way of estimating the necessary number of 8 | #' iterations necessary to fit a model using inliers only, at least once, as shown in the equation: 9 | #' \mjdeqn{k = log(1 - p) / log(1 - w^{n})}{k = log(1 - p) / log(1 - w^n)} 10 | #' where: 11 | #' \itemize{ 12 | #' \item \emph{k}: number of iterations 13 | #' \item \emph{p}: confidence level, i.e. desired probability of success 14 | #' \item \emph{w}: proportion of inliers expected in the \emph{full} dataset 15 | #' \item \emph{n}: number of observations sampled on every iteration 16 | #' } 17 | #' 18 | #' The models reiterated in \emph{TreeLS} usually relate to circle or cylinder 19 | #' fitting over a set of 3D coordinates, selecting the best possible model through the RANSAC algorithm 20 | #' 21 | #' For more information, checkout \href{https://en.wikipedia.org/wiki/Random_sample_consensus}{this wikipedia page}. 22 | -------------------------------------------------------------------------------- /man-roxygen/section-voxel.R: -------------------------------------------------------------------------------- 1 | #' @section Voxel Point Cloud Search: 2 | #' 3 | #' Methods that rely on voxel metrics define point neighborhoods 4 | #' as all points contained in fixed size voxels. -------------------------------------------------------------------------------- /man/circleFit.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{circleFit} 4 | \alias{circleFit} 5 | \title{Point cloud circle fit} 6 | \usage{ 7 | circleFit(las, method = "irls", n = 5, inliers = 0.8, conf = 0.99, n_best = 0) 8 | } 9 | \arguments{ 10 | \item{las}{\code{\link[lidR:LAS]{LAS}} object.} 11 | 12 | \item{method}{method for estimating the circle parameters. Currently available: \code{"qr"}, \code{"nm"}, \code{"irls"} and \code{"ransac"}.} 13 | 14 | \item{n}{\code{numeric} - number of points selected on every RANSAC iteration.} 15 | 16 | \item{inliers}{\code{numeric} - expected proportion of inliers among stem segments' point cloud chunks.} 17 | 18 | \item{conf}{\code{numeric} - confidence level.} 19 | 20 | \item{n_best}{\code{integer} - estimate optimal RANSAC parameters as the median of the \code{n_best} estimations with lowest error.} 21 | } 22 | \value{ 23 | vector of parameters 24 | } 25 | \description{ 26 | Fits a 2D horizontally-aligned circle on a set of 3D points. 27 | } 28 | -------------------------------------------------------------------------------- /man/cylinderFit.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{cylinderFit} 4 | \alias{cylinderFit} 5 | \title{Point cloud cylinder fit} 6 | \usage{ 7 | cylinderFit( 8 | las, 9 | method = "ransac", 10 | n = 5, 11 | inliers = 0.9, 12 | conf = 0.95, 13 | max_angle = 30, 14 | n_best = 20 15 | ) 16 | } 17 | \arguments{ 18 | \item{las}{\code{\link[lidR:LAS]{LAS}} object.} 19 | 20 | \item{method}{method for estimating the cylinder parameters. Currently available: \code{"nm"}, \code{"irls"}, \code{"ransac"} and \code{"bf"}.} 21 | 22 | \item{n}{\code{numeric} - number of points selected on every RANSAC iteration.} 23 | 24 | \item{inliers}{\code{numeric} - expected proportion of inliers among stem segments' point cloud chunks.} 25 | 26 | \item{conf}{\code{numeric} - confidence level.} 27 | 28 | \item{max_angle}{\code{numeric} - used when \code{method == "bf"}. The maximum tolerated deviation, in degrees, from an absolute vertical line (Z = c(0,0,1)).} 29 | 30 | \item{n_best}{\code{integer} - estimate optimal RANSAC parameters as the median of the \code{n_best} estimations with lowest error.} 31 | } 32 | \value{ 33 | vector of parameters 34 | } 35 | \description{ 36 | Fits a cylinder on a set of 3D points. 37 | } 38 | -------------------------------------------------------------------------------- /man/fastPointMetrics.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/point_metrics_methods.R 3 | \name{fastPointMetrics} 4 | \alias{fastPointMetrics} 5 | \title{Calculate point neighborhood metrics} 6 | \usage{ 7 | fastPointMetrics( 8 | las, 9 | method = ptm.voxel(), 10 | which_metrics = ENABLED_POINT_METRICS$names 11 | ) 12 | } 13 | \arguments{ 14 | \item{las}{\code{\link[lidR:LAS]{LAS}} object.} 15 | 16 | \item{method}{neighborhood search algorithm. Currently available: \code{\link{ptm.voxel}} and \code{\link{ptm.knn}}.} 17 | 18 | \item{which_metrics}{optional \code{character} vector - list of metrics (by name) to be calculated. Check out \code{\link{fastPointMetrics.available}} for a list of all metrics.} 19 | } 20 | \value{ 21 | \code{\link[lidR:LAS]{LAS}} object. 22 | } 23 | \description{ 24 | Get statistics for every point in a \code{LAS} object. Neighborhood search methods are prefixed by \code{ptm}. 25 | } 26 | \details{ 27 | Individual or voxel-wise point metrics build up the basis for many studies involving TLS in forestry. This 28 | function is used internally in other \emph{TreeLS} methods for tree mapping and stem denoising, but also may 29 | be useful to users interested in developing their own custom methods for point cloud classification/filtering of 30 | vegetation features or build up input datasets for machine learning classifiers. 31 | 32 | \code{fastPointMetrics} provides a way to calculate several geometry related metrics (listed below) in an optimized way. 33 | All metrics are calculated internally by C++ functions in a single pass (\emph{O(n)} time), hence \emph{fast}. 34 | This function is provided for convenience, as it allows very fast calculations of several complex variables 35 | on a single line of code, speeding up heavy work loads. For a more flexible approach that allows user defined 36 | metrics check out \code{\link[lidR:point_metrics]{point_metrics}} from the \emph{lidR} package. 37 | 38 | In order to avoid excessive memory use, not all available metrics are calculated by default. 39 | The calculated metrics can be specified every time \code{fastPointMetrics} is run by naming the desired metrics 40 | into the \code{which_metrics} argument, or changed globally for the active R session by setting new default 41 | metrics using \code{\link{fastPointMetrics.available}}. 42 | } 43 | \section{List of available point metrics}{ 44 | 45 | 46 | \loadmathjax 47 | 48 | * \emph{EVi} = \emph{i}-th 3D eigen value 49 | 50 | * \emph{EV2Di} = \emph{i}-th 2D eigen value 51 | 52 | \itemize{ 53 | \item \code{N}: number of nearest neighbors 54 | \item \code{MinDist}: minimum distance among neighbors 55 | \item \code{MaxDist}: maximum distance among neighbors 56 | \item \code{MeanDist}: mean distance 57 | \item \code{SdDist}: standard deviation of within neighborhood distances 58 | \item \code{Linearity}: linear saliency, \mjeqn{(EV_{1} + EV_{2}) / EV_{1}}{(EV1 + EV2) / EV1} 59 | \item \code{Planarity}: planar saliency, \mjeqn{(EV_{2} + EV_{3}) / EV_{1}}{(EV2 + EV3) / EV1} 60 | \item \code{Scattering}: \mjeqn{EV_{3} / EV_{1}}{EV3 / EV1} 61 | \item \code{Omnivariance}: \mjeqn{(EV_{2} + EV_{3}) / EV_{1}}{(EV2 + EV3) / EV1} 62 | \item \code{Anisotropy}: \mjeqn{(EV_{1} - EV_{3}) / EV_{1}}{(EV1 - EV3) / EV1} 63 | \item \code{Eigentropy}: \mjeqn{- \sum_{i=1}^{n=3} EV_{i} * ln(EV_{i})}{-sum(EV * ln(EV))} 64 | \item \code{EigenSum}: sum of eigenvalues, \mjeqn{\sum_{i=1}^{n=3} EV_{i}}{sum(EV)} 65 | \item \code{Curvature}: surface variation, \mjeqn{EV_{3} / EigenSum}{EV3 / EigenSum} 66 | \item \code{KnnRadius}: 3D neighborhood radius 67 | \item \code{KnnDensity}: 3D point density (N / sphere volume) 68 | \item \code{Verticality}: absolute vertical deviation, in degrees 69 | \item \code{ZRange}: point neighborhood height difference 70 | \item \code{ZSd}: standard deviation of point neighborhood heights 71 | \item \code{KnnRadius2d}: 2D neighborhood radius 72 | \item \code{KnnDensity2d}: 2D point density (N / circle area) 73 | \item \code{EigenSum2d}: sum of 2D eigenvalues, \mjeqn{\sum_{i=1}^{n=2} EV2D_{i}}{sum(EV2D)} 74 | \item \code{EigenRatio2d}: \mjeqn{EV2D_{2} / EV2D_{1}}{EV2D2 / EV2D1} 75 | \item \code{EigenValuei}: 3D eigenvalues 76 | \item \code{EigenVectorij}: 3D eigenvector coefficients, \emph{i}-th load of \emph{j}-th eigenvector 77 | } 78 | } 79 | 80 | \examples{ 81 | file = system.file("extdata", "pine.laz", package="TreeLS") 82 | tls = readTLS(file, select='xyz') 83 | 84 | all_metrics = fastPointMetrics.available() 85 | my_metrics = all_metrics[c(1,4,6)] 86 | 87 | tls = fastPointMetrics(tls, ptm.knn(10), my_metrics) 88 | head(tls@data) 89 | plot(tls, color='Linearity') 90 | } 91 | \references{ 92 | Wang, D.; Hollaus, M.; Pfeifer, N., 2017. Feasibility of machine learning methods for separating wood and leaf points from terrestrial laser scanning data. ISPRS Annals of the Photogrammetry, Remote Sensing and Spatial Information Sciences, Volume IV-2/W4. 93 | 94 | Zhou, J. et. al., 2019. Separating leaf and wood points in terrestrial scanning data using multiple optimal scales. Sensors, 19(8):1852. 95 | } 96 | -------------------------------------------------------------------------------- /man/fastPointMetrics.available.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/point_metrics_methods.R 3 | \name{fastPointMetrics.available} 4 | \alias{fastPointMetrics.available} 5 | \title{Print available point metrics} 6 | \usage{ 7 | fastPointMetrics.available(enable = ENABLED_POINT_METRICS$names) 8 | } 9 | \arguments{ 10 | \item{enable}{optional \code{integer} or \code{character} vector containing indices or names of the metrics you want to 11 | enable globally. Enabled metrics are calculated every time you run \code{\link{fastPointMetrics}} by default. 12 | Only metrics used internally in other \emph{TreeLS} methods are enabled out-of-the-box.} 13 | } 14 | \value{ 15 | \code{character} vector of all metrics. 16 | } 17 | \description{ 18 | Print the list of available metrics for \code{\link{fastPointMetrics}}. 19 | } 20 | \section{List of available point metrics}{ 21 | 22 | 23 | \loadmathjax 24 | 25 | * \emph{EVi} = \emph{i}-th 3D eigen value 26 | 27 | * \emph{EV2Di} = \emph{i}-th 2D eigen value 28 | 29 | \itemize{ 30 | \item \code{N}: number of nearest neighbors 31 | \item \code{MinDist}: minimum distance among neighbors 32 | \item \code{MaxDist}: maximum distance among neighbors 33 | \item \code{MeanDist}: mean distance 34 | \item \code{SdDist}: standard deviation of within neighborhood distances 35 | \item \code{Linearity}: linear saliency, \mjeqn{(EV_{1} + EV_{2}) / EV_{1}}{(EV1 + EV2) / EV1} 36 | \item \code{Planarity}: planar saliency, \mjeqn{(EV_{2} + EV_{3}) / EV_{1}}{(EV2 + EV3) / EV1} 37 | \item \code{Scattering}: \mjeqn{EV_{3} / EV_{1}}{EV3 / EV1} 38 | \item \code{Omnivariance}: \mjeqn{(EV_{2} + EV_{3}) / EV_{1}}{(EV2 + EV3) / EV1} 39 | \item \code{Anisotropy}: \mjeqn{(EV_{1} - EV_{3}) / EV_{1}}{(EV1 - EV3) / EV1} 40 | \item \code{Eigentropy}: \mjeqn{- \sum_{i=1}^{n=3} EV_{i} * ln(EV_{i})}{-sum(EV * ln(EV))} 41 | \item \code{EigenSum}: sum of eigenvalues, \mjeqn{\sum_{i=1}^{n=3} EV_{i}}{sum(EV)} 42 | \item \code{Curvature}: surface variation, \mjeqn{EV_{3} / EigenSum}{EV3 / EigenSum} 43 | \item \code{KnnRadius}: 3D neighborhood radius 44 | \item \code{KnnDensity}: 3D point density (N / sphere volume) 45 | \item \code{Verticality}: absolute vertical deviation, in degrees 46 | \item \code{ZRange}: point neighborhood height difference 47 | \item \code{ZSd}: standard deviation of point neighborhood heights 48 | \item \code{KnnRadius2d}: 2D neighborhood radius 49 | \item \code{KnnDensity2d}: 2D point density (N / circle area) 50 | \item \code{EigenSum2d}: sum of 2D eigenvalues, \mjeqn{\sum_{i=1}^{n=2} EV2D_{i}}{sum(EV2D)} 51 | \item \code{EigenRatio2d}: \mjeqn{EV2D_{2} / EV2D_{1}}{EV2D2 / EV2D1} 52 | \item \code{EigenValuei}: 3D eigenvalues 53 | \item \code{EigenVectorij}: 3D eigenvector coefficients, \emph{i}-th load of \emph{j}-th eigenvector 54 | } 55 | } 56 | 57 | \examples{ 58 | m = fastPointMetrics.available() 59 | length(m) 60 | } 61 | -------------------------------------------------------------------------------- /man/gpsTimeFilter.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{gpsTimeFilter} 4 | \alias{gpsTimeFilter} 5 | \title{Filter points based on the \code{gpstime} field} 6 | \usage{ 7 | gpsTimeFilter(las, from = 0, to = 1) 8 | } 9 | \arguments{ 10 | \item{las}{\code{\link[lidR:LAS]{LAS}} object.} 11 | 12 | \item{from, to}{\code{numeric} - gpstime percentile thresholds (from 0 to 1) to keep points in between.} 13 | } 14 | \value{ 15 | \code{\link[lidR:LAS]{LAS}} object. 16 | } 17 | \description{ 18 | This is a simple wrapper to \code{\link[lidR:filter_poi]{filter_poi}} that takes as input relative values instead of absolute time stamps for filtering \code{LAS} object based on the gpstime. This function is particularly useful to check narrow intervals of point cloud frames from mobile scanning data. 19 | } 20 | -------------------------------------------------------------------------------- /man/map.eigen.knn.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/map_methods.R 3 | \name{map.eigen.knn} 4 | \alias{map.eigen.knn} 5 | \title{Tree mapping algorithm: KNN point geometry} 6 | \usage{ 7 | map.eigen.knn( 8 | max_curvature = 0.1, 9 | max_verticality = 10, 10 | max_mean_dist = 0.1, 11 | max_d = 0.5, 12 | min_h = 1.5, 13 | max_h = 3 14 | ) 15 | } 16 | \arguments{ 17 | \item{max_curvature}{\code{numeric} - maximum curvature (from 0 to 1) accepted when filtering a point neighborhood.} 18 | 19 | \item{max_verticality}{\code{numeric} - maximum deviation of a point neighborhood's orientation from an absolute vertical axis ( Z = c(0,0,1) ), in \emph{degrees} (from 0 to 90).} 20 | 21 | \item{max_mean_dist}{\code{numeric} - maximum mean distance tolerated from a point to its nearest neighbors.} 22 | 23 | \item{max_d}{\code{numeric} - largest tree diameter expected in the point cloud.} 24 | 25 | \item{min_h, max_h}{\code{numeric} - height thresholds applied to filter a point cloud before processing.} 26 | } 27 | \description{ 28 | This function is meant to be used inside \code{\link{treeMap}}. It applies a KNN filter to select points with specific neighborhood features. For more details on geometry features, check out \code{\link{fastPointMetrics}}. 29 | } 30 | \details{ 31 | Point metrics are calculated for every point. Points are then removed depending on their point 32 | metrics parameters and clustered to represent individual tree regions. 33 | Clusters are defined as a function of the expected maximum diameter. Any fields added to the 34 | point cloud are described in \code{\link{fastPointMetrics}}. 35 | } 36 | \section{Eigen Decomposition of Point Neighborhoods}{ 37 | 38 | 39 | Point filtering/classification methods that rely on eigen 40 | decomposition rely on shape indices calculated for point 41 | neighborhoods (knn or voxel). To derive these shape indices, eigen 42 | decomposition is performed on the XYZ columns of a point cloud patch. 43 | Metrics related to object curvature are calculated upon ratios of the resulting 44 | eigen values, and metrics related to object orientation are caltulated from 45 | approximate normals obtained from the eigen vectors. 46 | 47 | For instance, a point neighborhood that belongs to a perfect flat 48 | surface will have all of its variance explained by the first two eigen values, 49 | and none explained by the third eigen value. The 'normal' of such surface, 50 | i.e. the vector oriented in the direction orthogonal to the surface, 51 | is therefore represented by the third eigenvector. 52 | 53 | Methods for both tree mapping and stem segmentation use those metrics, so in order 54 | to speed up the workflow one might apply \code{\link{fastPointMetrics}} to the point 55 | cloud before other methods. The advantages of this approach are that users 56 | can parameterize the point neighborhoods themselves when calculating their metrics. 57 | Those calculations won't be performed again internally in the tree mapping or stem 58 | denoising methods, reducing the overall processing time. 59 | } 60 | 61 | -------------------------------------------------------------------------------- /man/map.eigen.voxel.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/map_methods.R 3 | \name{map.eigen.voxel} 4 | \alias{map.eigen.voxel} 5 | \title{Tree mapping algorithm: Voxel geometry} 6 | \usage{ 7 | map.eigen.voxel( 8 | max_curvature = 0.15, 9 | max_verticality = 15, 10 | voxel_spacing = 0.1, 11 | max_d = 0.5, 12 | min_h = 1.5, 13 | max_h = 3 14 | ) 15 | } 16 | \arguments{ 17 | \item{max_curvature}{\code{numeric} - maximum curvature (from 0 to 1) accepted when filtering a point neighborhood.} 18 | 19 | \item{max_verticality}{\code{numeric} - maximum deviation of a point neighborhood's orientation from an absolute vertical axis ( Z = c(0,0,1) ), in \emph{degrees} (from 0 to 90).} 20 | 21 | \item{voxel_spacing}{\code{numeric} - voxel side length, in point cloud units.} 22 | 23 | \item{max_d}{\code{numeric} - largest tree diameter expected in the point cloud.} 24 | 25 | \item{min_h, max_h}{\code{numeric} - height thresholds applied to filter a point cloud before processing.} 26 | } 27 | \description{ 28 | This function is meant to be used inside \code{\link{treeMap}}. It applies a filter to select points belonging to voxels with specific features. For more details on geometry features, check out \code{\link{fastPointMetrics}}. 29 | } 30 | \details{ 31 | Point metrics are calculated for every voxel. Points are then removed depending on their voxel's metrics 32 | metrics parameters and clustered to represent individual tree regions. 33 | Clusters are defined as a function of the expected maximum diameter. Any fields added to the 34 | point cloud are described in \code{\link{fastPointMetrics}}. 35 | } 36 | \section{Eigen Decomposition of Point Neighborhoods}{ 37 | 38 | 39 | Point filtering/classification methods that rely on eigen 40 | decomposition rely on shape indices calculated for point 41 | neighborhoods (knn or voxel). To derive these shape indices, eigen 42 | decomposition is performed on the XYZ columns of a point cloud patch. 43 | Metrics related to object curvature are calculated upon ratios of the resulting 44 | eigen values, and metrics related to object orientation are caltulated from 45 | approximate normals obtained from the eigen vectors. 46 | 47 | For instance, a point neighborhood that belongs to a perfect flat 48 | surface will have all of its variance explained by the first two eigen values, 49 | and none explained by the third eigen value. The 'normal' of such surface, 50 | i.e. the vector oriented in the direction orthogonal to the surface, 51 | is therefore represented by the third eigenvector. 52 | 53 | Methods for both tree mapping and stem segmentation use those metrics, so in order 54 | to speed up the workflow one might apply \code{\link{fastPointMetrics}} to the point 55 | cloud before other methods. The advantages of this approach are that users 56 | can parameterize the point neighborhoods themselves when calculating their metrics. 57 | Those calculations won't be performed again internally in the tree mapping or stem 58 | denoising methods, reducing the overall processing time. 59 | } 60 | 61 | -------------------------------------------------------------------------------- /man/map.hough.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/map_methods.R 3 | \name{map.hough} 4 | \alias{map.hough} 5 | \title{Tree mapping algorithm: Hough Transform} 6 | \usage{ 7 | map.hough( 8 | min_h = 1, 9 | max_h = 3, 10 | h_step = 0.5, 11 | pixel_size = 0.025, 12 | max_d = 0.5, 13 | min_density = 0.1, 14 | min_votes = 3 15 | ) 16 | } 17 | \arguments{ 18 | \item{min_h, max_h}{\code{numeric} - height thresholds applied to filter a point cloud before processing.} 19 | 20 | \item{h_step}{\code{numeric} - height interval to perform point filtering/assignment/classification.} 21 | 22 | \item{pixel_size}{\code{numeric} - pixel side length to discretize the point cloud layers while performing the Hough Transform circle search.} 23 | 24 | \item{max_d}{\code{numeric} - largest tree diameter expected in the point cloud.} 25 | 26 | \item{min_density}{\code{numeric} - between 0 and 1 - minimum point density within a pixel evaluated on the Hough Transform - i.e. only \emph{dense} point clousters will undergo circle search.} 27 | 28 | \item{min_votes}{\code{integer} - Hough Transform parameter - minimum number of circle intersections over a pixel to assign it as a circle center candidate.} 29 | } 30 | \description{ 31 | This function is meant to be used inside \code{\link{treeMap}}. It applies an adapted version of the Hough Transform for circle search. Mode details are given in the sections below. 32 | } 33 | \section{\code{LAS@data} Special Fields}{ 34 | 35 | 36 | Each point in the \code{LAS} object output represents a pixel center that is 37 | \emph{possibly} also a stem cross-section center. 38 | 39 | The variables describing each point in the output are: 40 | 41 | \itemize{ 42 | \item \code{Intensity}: number of votes received by that point 43 | \item \code{PointSourceID}: unique stem segment ID (among all trees) 44 | \item \code{Keypoint_flag}: if \code{TRUE}, the point is the most likely circle center 45 | of its stem segment (\code{PointSourceID}) 46 | \item \code{Radii}: approximate radius estimated by that point - always a multiple of the \code{pixel_size} 47 | \item \code{TreeID}: unique tree ID of the point 48 | \item \code{TreePosition}: if \code{TRUE}, the point represents the tree's position coordinate 49 | } 50 | } 51 | 52 | \section{Adapted Hough Transform}{ 53 | 54 | 55 | The Hough Transform circle search algorithm used in 56 | TreeLS applies a constrained circle search on discretized 57 | point cloud layers. Tree-wise, the circle search is 58 | recursive, in which the search for circle parameters 59 | of a stem section is constrained to the 60 | \emph{feature space} of the stem section underneath it. 61 | Initial estimates of the stem's \emph{feature space} 62 | are performed on a \emph{baselise} stem segment - i.e. 63 | a low height interval where a tree's bole is expected 64 | to be clearly visible in the point cloud. 65 | The algorithm is described in detail by Conto et al. (2017). 66 | 67 | This adapted version of the algorithm is very robust against outliers, 68 | but not against forked or leaning stems. 69 | } 70 | 71 | \section{Tree Selection}{ 72 | 73 | 74 | An initial tree filter is used to select \emph{probable} trees in the input point 75 | cloud. Parallel stacked layers, each one as thick as \code{hstep}, undergo the 76 | circle search within the \code{hmin}/\code{hmax} limits. On every layer, pixels 77 | above the \code{min_votes} criterion are clustered, forming 78 | \emph{probability zones}. \emph{Probability zones} vertically aligned 79 | on at least 3/4 of the stacked layers are assigned as \emph{tree occurrence regions} 80 | and exported in the output map. 81 | } 82 | 83 | \examples{ 84 | file = system.file("extdata", "pine_plot.laz", package="TreeLS") 85 | tls = readTLS(file) \%>\% 86 | tlsNormalize \%>\% 87 | tlsSample 88 | 89 | x = plot(tls) 90 | 91 | map = treeMap(tls, map.hough(h_step = 1, max_h = 4)) 92 | add_treeMap(x, map, color='red') 93 | 94 | xymap = treeMap.positions(map) 95 | } 96 | \references{ 97 | Conto, T. et al., 2017. Performance of stem denoising and stem modelling algorithms on single tree point clouds from terrestrial laser scanning. Computers and Electronics in Agriculture, v. 143, p. 165-176. 98 | } 99 | -------------------------------------------------------------------------------- /man/map.pick.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/map_methods.R 3 | \name{map.pick} 4 | \alias{map.pick} 5 | \title{Tree mapping algorithm: pick trees manually} 6 | \usage{ 7 | map.pick(map = NULL, min_h = 1, max_h = 5, bg = "gray50") 8 | } 9 | \arguments{ 10 | \item{map}{optional tree map to be manually updated.} 11 | 12 | \item{min_h, max_h}{\code{numeric} - height thresholds applied to filter a point cloud before processing.} 13 | 14 | \item{bg}{background color for the rgl plot.} 15 | } 16 | \description{ 17 | This function is meant to be used inside \code{\link{treeMap}}. It opens an interactive \code{rgl} plot where the user can specify tree locations by clicking. 18 | } 19 | -------------------------------------------------------------------------------- /man/nnFilter.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{nnFilter} 4 | \alias{nnFilter} 5 | \title{Nearest neighborhood point filter} 6 | \usage{ 7 | nnFilter(las, d = 0.05, n = 2) 8 | } 9 | \arguments{ 10 | \item{las}{\code{\link[lidR:LAS]{LAS}} object.} 11 | 12 | \item{d}{\code{numeric} - search radius.} 13 | 14 | \item{n}{\code{numeric} - number of neighbors within \code{d} distance a point must have to be kept in the output.} 15 | } 16 | \value{ 17 | \code{\link[lidR:LAS]{LAS}} object. 18 | } 19 | \description{ 20 | Remove isolated points from a \code{LAS} point cloud based on their neighborhood distances. 21 | } 22 | \examples{ 23 | file = system.file("extdata", "spruce.laz", package="TreeLS") 24 | tls = readTLS(file) 25 | nrow(tls@data) 26 | 27 | nn_tls = nnFilter(tls, 0.05, 3) 28 | nrow(nn_tls@data) 29 | } 30 | -------------------------------------------------------------------------------- /man/ptm.knn.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/point_metrics_methods.R 3 | \name{ptm.knn} 4 | \alias{ptm.knn} 5 | \title{Point metrics algorithm: K Nearest Neighbors metrics} 6 | \usage{ 7 | ptm.knn(k = 20, r = 0) 8 | } 9 | \arguments{ 10 | \item{k}{\code{numeric} - number of nearest points to search per neighborhood.} 11 | 12 | \item{r}{\code{numeric} - search radius limit. If \code{r == 0}, no distance limit is applied.} 13 | } 14 | \description{ 15 | This function is meant to be used inside \code{\link{fastPointMetrics}}. It calculates metrics for every point using its nearest neighbors (KNN). 16 | } 17 | -------------------------------------------------------------------------------- /man/ptm.voxel.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/point_metrics_methods.R 3 | \name{ptm.voxel} 4 | \alias{ptm.voxel} 5 | \title{Point metrics algorithm: Voxel metrics} 6 | \usage{ 7 | ptm.voxel(d = 0.1, exact = FALSE) 8 | } 9 | \arguments{ 10 | \item{d}{\code{numeric} - voxel spacing, in point cloud units.} 11 | 12 | \item{exact}{\code{logical} - use exact voxel search? If \code{FALSE}, applies approximate voxel search using integer index hashing, much faster on large point clouds (several million points).} 13 | } 14 | \description{ 15 | This function is meant to be used inside \code{\link{fastPointMetrics}}. It calculates metrics per voxel. 16 | } 17 | -------------------------------------------------------------------------------- /man/readTLS.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{readTLS} 4 | \alias{readTLS} 5 | \title{Import a point cloud file into a LAS object} 6 | \usage{ 7 | readTLS(file, col_names = NULL, ...) 8 | } 9 | \arguments{ 10 | \item{file}{file path.} 11 | 12 | \item{col_names}{optional - \code{character} vector. Only used for table-like objects. It states the column names. If not set, only the 3 first columns will be used and assigned to the XYZ fields.} 13 | 14 | \item{...}{further arguments passed down to \code{readLAS}, \code{read.las} or \code{fread}.} 15 | } 16 | \value{ 17 | \code{\link[lidR:LAS]{LAS}} object. 18 | } 19 | \description{ 20 | Wrapper to read point cloud files straight into LAS objects. Reads \emph{las} or \emph{laz} files with \code{\link[lidR:readLAS]{readLAS}}, \emph{ply} files with \code{\link[rlas:read.las]{read.las}} and other file formats with \code{\link[data.table:fread]{fread}} (txt, xyz, 3d or any other table like format). 21 | } 22 | \examples{ 23 | cloud = matrix(runif(300), ncol=3) 24 | file = tempfile(fileext = '.txt') 25 | fwrite(cloud, file) 26 | tls = readTLS(file) 27 | summary(tls) 28 | } 29 | -------------------------------------------------------------------------------- /man/setTLS.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{setTLS} 4 | \alias{setTLS} 5 | \title{(Re-)Create a \code{LAS} object depending on the input's type} 6 | \usage{ 7 | setTLS(cloud, col_names = NULL) 8 | } 9 | \arguments{ 10 | \item{cloud}{\code{LAS}, \code{data.frame}, \code{matrix} or similar object to be converted.} 11 | 12 | \item{col_names}{optional - \code{character} vector. Only used for table-like objects. It states the column names. If not set, only the 3 first columns will be used and assigned to the XYZ fields.} 13 | } 14 | \value{ 15 | \code{\link[lidR:LAS]{LAS}} object. 16 | } 17 | \description{ 18 | Reset the input's header if it is a \code{LAS} object, or generate a new \code{LAS} from a table-like input. For more information, checkout \code{\link[lidR:LAS]{lidR::LAS}}. 19 | } 20 | \examples{ 21 | cloud = matrix(runif(300, 0, 10), ncol=3) 22 | cloud = setTLS(cloud) 23 | summary(cloud) 24 | } 25 | -------------------------------------------------------------------------------- /man/sgt.bf.cylinder.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stem_segmentation_methods.R 3 | \name{sgt.bf.cylinder} 4 | \alias{sgt.bf.cylinder} 5 | \title{Stem segmentation algorithm: Brute Force cylinder fit} 6 | \usage{ 7 | sgt.bf.cylinder(tol = 0.1, n = 10, conf = 0.95, inliers = 0.9, z_dev = 30) 8 | } 9 | \arguments{ 10 | \item{tol}{\code{numeric} - tolerance offset between absolute radii estimates and hough transform estimates.} 11 | 12 | \item{n}{\code{numeric} - number of points selected on every RANSAC iteration.} 13 | 14 | \item{conf}{\code{numeric} - confidence level.} 15 | 16 | \item{inliers}{\code{numeric} - expected proportion of inliers among stem segments' point cloud chunks.} 17 | 18 | \item{z_dev}{\code{numeric} - maximum angle deviation for brute force cylinder estimation (\code{bf}), i.e. angle, in degrees (0-90), that a cylinder can be tilted in relation to a perfect vertival axis (\code{Z = c(0,0,1)}).} 19 | } 20 | \description{ 21 | This function is meant to be used inside \code{\link{stemSegmentation}}. It applies a least squares cylinder fit algorithm in a RANSAC fashion over stem segments. More details are given in the sections below. 22 | } 23 | \section{Brute Force Cylinder Fit}{ 24 | 25 | 26 | The brute force cylinder fit approach estimates the axis rotation 27 | angles by brute force combined with 2D ransac circle fit. The coordinates 28 | of a point cloud representing a single cylinder are iteratively rotated up 29 | to a pre defined threshold, and for every iteration a circle is estimated after 30 | rotation is performed. The rotation that minimizes the circle parameters the most 31 | is used to describe the axis direction of the cylinder with the circle's radius. 32 | 33 | The parameters returned by the brute force cylinder fit method are: 34 | \itemize{ 35 | \item \code{X,Y}: 2D circle center coordinates after rotation 36 | \item \code{Radius}: 3D circle radius, in point cloud units 37 | \item \code{Error}: model circle error from the RANSAC least squares fit, after rotation 38 | \item \code{DX,DY}: absolute rotation angles (in degrees) applied to the X and Y axes, respectively 39 | \item \code{AvgHeight}: average height of the stem segment's points 40 | \item \code{N}: number of points belonging to the stem segment 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /man/sgt.irls.circle.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stem_segmentation_methods.R 3 | \name{sgt.irls.circle} 4 | \alias{sgt.irls.circle} 5 | \title{Stem segmentation algorithm: Iterated Reweighted Least Squares circle fit} 6 | \usage{ 7 | sgt.irls.circle(tol = 0.1, n = 500) 8 | } 9 | \arguments{ 10 | \item{tol}{\code{numeric} - tolerance offset between absolute radii estimates and hough transform estimates.} 11 | 12 | \item{n}{\code{numeric} - maximum number of points to sample for fitting stem segments.} 13 | } 14 | \description{ 15 | This function is meant to be used inside \code{\link{stemSegmentation}}. It applies a reweighted least squares circle fit algorithm using M-estimators in order to remove outlier effects. 16 | } 17 | \section{Iterative Reweighted Least Squares (IRLS) Algorithm}{ 18 | 19 | 20 | \emph{irls} \code{circle} or \code{cylinder} estimation methods 21 | perform automatic outlier assigning through iterative reweighting 22 | with M-estimators, followed by a Nelder-Mead optimization of squared distance sums 23 | to determine the best circle/cylinder parameters for a given point 24 | cloud. The reweighting strategy used in \emph{TreeLS} is based on 25 | Liang et al. (2012). The Nelder-Mead algorithm implemented in Rcpp was provided by 26 | \href{https://github.com/kthohr/optim}{kthohr/optim}. 27 | } 28 | 29 | \section{Least Squares Circle Fit}{ 30 | 31 | 32 | The circle fit methods applied in \emph{TreeLS} estimate the circle parameters (its center's XY coordinates and radius) 33 | from a pre-selected (denoised) set of points in a least squares fashion 34 | by applying either \href{https://en.wikipedia.org/wiki/QR_decomposition}{QR decompostion}, used in combination 35 | with the RANSAC algorithm, or \href{https://en.wikipedia.org/wiki/Nelder-Mead_method}{Nelder-Mead simplex} 36 | optimization combined the IRLS approach. 37 | 38 | The parameters returned by the circle fit methods are: 39 | \itemize{ 40 | \item \code{X,Y}: 2D circle center coordinates 41 | \item \code{Radius}: 2D circle radius, in point cloud units 42 | \item \code{Error}: model circle error from the least squares fit 43 | \item \code{AvgHeight}: average height of the stem segment's points 44 | \item \code{N}: number of points belonging to the stem segment 45 | } 46 | } 47 | 48 | \references{ 49 | Liang, X. et al., 2012. Automatic stem mapping using single-scan terrestrial laser scanning. IEEE Transactions on Geoscience and Remote Sensing, 50(2), pp.661–670. 50 | 51 | Conto, T. et al., 2017. Performance of stem denoising and stem modelling algorithms on single tree point clouds from terrestrial laser scanning. Computers and Electronics in Agriculture, v. 143, p. 165-176. 52 | } 53 | -------------------------------------------------------------------------------- /man/sgt.irls.cylinder.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stem_segmentation_methods.R 3 | \name{sgt.irls.cylinder} 4 | \alias{sgt.irls.cylinder} 5 | \title{Stem segmentation algorithm: Iterated Reweighted Least Squares cylinder fit} 6 | \usage{ 7 | sgt.irls.cylinder(tol = 0.1, n = 100) 8 | } 9 | \arguments{ 10 | \item{tol}{\code{numeric} - tolerance offset between absolute radii estimates and hough transform estimates.} 11 | 12 | \item{n}{\code{numeric} - maximum number of points to sample for fitting stem segments.} 13 | } 14 | \description{ 15 | This function is meant to be used inside \code{\link{stemSegmentation}}. It applies a reweighted least squares cylinder fit algorithm using M-estimators and Nelder-Mead optimization in order to remove outlier effects. 16 | } 17 | \section{Iterative Reweighted Least Squares (IRLS) Algorithm}{ 18 | 19 | 20 | \emph{irls} \code{circle} or \code{cylinder} estimation methods 21 | perform automatic outlier assigning through iterative reweighting 22 | with M-estimators, followed by a Nelder-Mead optimization of squared distance sums 23 | to determine the best circle/cylinder parameters for a given point 24 | cloud. The reweighting strategy used in \emph{TreeLS} is based on 25 | Liang et al. (2012). The Nelder-Mead algorithm implemented in Rcpp was provided by 26 | \href{https://github.com/kthohr/optim}{kthohr/optim}. 27 | } 28 | 29 | \section{Least Squares Cylinder Fit}{ 30 | 31 | 32 | \loadmathjax 33 | 34 | The cylinder fit methods implemented in \emph{TreeLS} estimate a 3D 35 | cylinder`s axis direction and radius. The algorithm used internally 36 | to optimize the cylinder parameters is the 37 | \href{https://en.wikipedia.org/wiki/Nelder-Mead_method}{Nelder-Mead simplex}, 38 | which takes as objective function the model describing the distance from any point 39 | to a modelled cylinder`s surface on a regular 3D cylinder point cloud: 40 | 41 | \mjdeqn{D_{p} = |(p - q) \times a| - r}{Dp = abs((p - q) x a) - r} 42 | 43 | where: 44 | 45 | \itemize{ 46 | \item \emph{Dp}: distance from a point to the model cylinder`s surface 47 | \item \emph{p}: a point on the cylinder`s surface 48 | \item \emph{q}: a point on the cylinder`s axis 49 | \item \emph{a}: unit vector of cylinder`s direction 50 | \item \emph{r}: cylinder`s radius 51 | } 52 | 53 | The Nelder-Mead algorithm minimizes the sum of squared \emph{Dp} from 54 | a set of points belonging to a stem segment - in the context of \emph{TreeLS}. 55 | 56 | The parameters returned by the cylinder fit methods are: 57 | \itemize{ 58 | \item \code{rho,theta,phi,alpha}: 3D cylinder estimated axis parameters (Liang et al. 2012) 59 | \item \code{Radius}: 3D cylinder radius, in point cloud units 60 | \item \code{Error}: model cylinder error from the least squares fit 61 | \item \code{AvgHeight}: average height of the stem segment's points 62 | \item \code{N}: number of points belonging to the stem segment 63 | \item \code{PX,PY,PZ}: absolute center positions of the stem segment points, in point cloud units (used for plotting) 64 | } 65 | } 66 | 67 | \references{ 68 | Liang, X. et al., 2012. Automatic stem mapping using single-scan terrestrial laser scanning. IEEE Transactions on Geoscience and Remote Sensing, 50(2), pp.661–670. 69 | 70 | Conto, T. et al., 2017. Performance of stem denoising and stem modelling algorithms on single tree point clouds from terrestrial laser scanning. Computers and Electronics in Agriculture, v. 143, p. 165-176. 71 | } 72 | -------------------------------------------------------------------------------- /man/sgt.ransac.circle.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stem_segmentation_methods.R 3 | \name{sgt.ransac.circle} 4 | \alias{sgt.ransac.circle} 5 | \title{Stem segmentation algorithm: RANSAC circle fit} 6 | \usage{ 7 | sgt.ransac.circle(tol = 0.1, n = 10, conf = 0.99, inliers = 0.8) 8 | } 9 | \arguments{ 10 | \item{tol}{\code{numeric} - tolerance offset between absolute radii estimates and hough transform estimates.} 11 | 12 | \item{n}{\code{numeric} - number of points selected on every RANSAC iteration.} 13 | 14 | \item{conf}{\code{numeric} - confidence level.} 15 | 16 | \item{inliers}{\code{numeric} - expected proportion of inliers among stem segments' point cloud chunks.} 17 | } 18 | \description{ 19 | This function is meant to be used inside \code{\link{stemSegmentation}}. It applies a least squares circle fit algorithm in a RANSAC fashion over stem segments. More details are given in the sections below. 20 | } 21 | \section{Random Sample Consensus (RANSAC) Algorithm}{ 22 | 23 | 24 | \loadmathjax 25 | 26 | The \strong{RAN}dom \strong{SA}mple \strong{C}onsensus algorithm is a method that relies on resampling 27 | a data set as many times as necessary to find a subset comprised of only inliers - e.g. observations 28 | belonging to a desired model. The RANSAC algorithm provides a way of estimating the necessary number of 29 | iterations necessary to fit a model using inliers only, at least once, as shown in the equation: 30 | \mjdeqn{k = log(1 - p) / log(1 - w^{n})}{k = log(1 - p) / log(1 - w^n)} 31 | where: 32 | \itemize{ 33 | \item \emph{k}: number of iterations 34 | \item \emph{p}: confidence level, i.e. desired probability of success 35 | \item \emph{w}: proportion of inliers expected in the \emph{full} dataset 36 | \item \emph{n}: number of observations sampled on every iteration 37 | } 38 | 39 | The models reiterated in \emph{TreeLS} usually relate to circle or cylinder 40 | fitting over a set of 3D coordinates, selecting the best possible model through the RANSAC algorithm 41 | 42 | For more information, checkout \href{https://en.wikipedia.org/wiki/Random_sample_consensus}{this wikipedia page}. 43 | } 44 | 45 | \section{Least Squares Circle Fit}{ 46 | 47 | 48 | The circle fit methods applied in \emph{TreeLS} estimate the circle parameters (its center's XY coordinates and radius) 49 | from a pre-selected (denoised) set of points in a least squares fashion 50 | by applying either \href{https://en.wikipedia.org/wiki/QR_decomposition}{QR decompostion}, used in combination 51 | with the RANSAC algorithm, or \href{https://en.wikipedia.org/wiki/Nelder-Mead_method}{Nelder-Mead simplex} 52 | optimization combined the IRLS approach. 53 | 54 | The parameters returned by the circle fit methods are: 55 | \itemize{ 56 | \item \code{X,Y}: 2D circle center coordinates 57 | \item \code{Radius}: 2D circle radius, in point cloud units 58 | \item \code{Error}: model circle error from the least squares fit 59 | \item \code{AvgHeight}: average height of the stem segment's points 60 | \item \code{N}: number of points belonging to the stem segment 61 | } 62 | } 63 | 64 | \references{ 65 | Olofsson, K., Holmgren, J. & Olsson, H., 2014. Tree stem and height measurements using terrestrial laser scanning and the RANSAC algorithm. Remote Sensing, 6(5), pp.4323–4344. 66 | 67 | Conto, T. et al., 2017. Performance of stem denoising and stem modelling algorithms on single tree point clouds from terrestrial laser scanning. Computers and Electronics in Agriculture, v. 143, p. 165-176. 68 | } 69 | -------------------------------------------------------------------------------- /man/sgt.ransac.cylinder.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stem_segmentation_methods.R 3 | \name{sgt.ransac.cylinder} 4 | \alias{sgt.ransac.cylinder} 5 | \title{Stem segmentation algorithm: RANSAC cylinder fit} 6 | \usage{ 7 | sgt.ransac.cylinder(tol = 0.1, n = 10, conf = 0.95, inliers = 0.9) 8 | } 9 | \arguments{ 10 | \item{tol}{\code{numeric} - tolerance offset between absolute radii estimates and hough transform estimates.} 11 | 12 | \item{n}{\code{numeric} - number of points selected on every RANSAC iteration.} 13 | 14 | \item{conf}{\code{numeric} - confidence level.} 15 | 16 | \item{inliers}{\code{numeric} - expected proportion of inliers among stem segments' point cloud chunks.} 17 | } 18 | \description{ 19 | This function is meant to be used inside \code{\link{stemSegmentation}}. It applies a least squares cylinder fit algorithm in a RANSAC fashion over stem segments. More details are given in the sections below. 20 | } 21 | \section{Random Sample Consensus (RANSAC) Algorithm}{ 22 | 23 | 24 | \loadmathjax 25 | 26 | The \strong{RAN}dom \strong{SA}mple \strong{C}onsensus algorithm is a method that relies on resampling 27 | a data set as many times as necessary to find a subset comprised of only inliers - e.g. observations 28 | belonging to a desired model. The RANSAC algorithm provides a way of estimating the necessary number of 29 | iterations necessary to fit a model using inliers only, at least once, as shown in the equation: 30 | \mjdeqn{k = log(1 - p) / log(1 - w^{n})}{k = log(1 - p) / log(1 - w^n)} 31 | where: 32 | \itemize{ 33 | \item \emph{k}: number of iterations 34 | \item \emph{p}: confidence level, i.e. desired probability of success 35 | \item \emph{w}: proportion of inliers expected in the \emph{full} dataset 36 | \item \emph{n}: number of observations sampled on every iteration 37 | } 38 | 39 | The models reiterated in \emph{TreeLS} usually relate to circle or cylinder 40 | fitting over a set of 3D coordinates, selecting the best possible model through the RANSAC algorithm 41 | 42 | For more information, checkout \href{https://en.wikipedia.org/wiki/Random_sample_consensus}{this wikipedia page}. 43 | } 44 | 45 | \section{Least Squares Cylinder Fit}{ 46 | 47 | 48 | \loadmathjax 49 | 50 | The cylinder fit methods implemented in \emph{TreeLS} estimate a 3D 51 | cylinder`s axis direction and radius. The algorithm used internally 52 | to optimize the cylinder parameters is the 53 | \href{https://en.wikipedia.org/wiki/Nelder-Mead_method}{Nelder-Mead simplex}, 54 | which takes as objective function the model describing the distance from any point 55 | to a modelled cylinder`s surface on a regular 3D cylinder point cloud: 56 | 57 | \mjdeqn{D_{p} = |(p - q) \times a| - r}{Dp = abs((p - q) x a) - r} 58 | 59 | where: 60 | 61 | \itemize{ 62 | \item \emph{Dp}: distance from a point to the model cylinder`s surface 63 | \item \emph{p}: a point on the cylinder`s surface 64 | \item \emph{q}: a point on the cylinder`s axis 65 | \item \emph{a}: unit vector of cylinder`s direction 66 | \item \emph{r}: cylinder`s radius 67 | } 68 | 69 | The Nelder-Mead algorithm minimizes the sum of squared \emph{Dp} from 70 | a set of points belonging to a stem segment - in the context of \emph{TreeLS}. 71 | 72 | The parameters returned by the cylinder fit methods are: 73 | \itemize{ 74 | \item \code{rho,theta,phi,alpha}: 3D cylinder estimated axis parameters (Liang et al. 2012) 75 | \item \code{Radius}: 3D cylinder radius, in point cloud units 76 | \item \code{Error}: model cylinder error from the least squares fit 77 | \item \code{AvgHeight}: average height of the stem segment's points 78 | \item \code{N}: number of points belonging to the stem segment 79 | \item \code{PX,PY,PZ}: absolute center positions of the stem segment points, in point cloud units (used for plotting) 80 | } 81 | } 82 | 83 | \references{ 84 | Liang, X. et al., 2012. Automatic stem mapping using single-scan terrestrial laser scanning. IEEE Transactions on Geoscience and Remote Sensing, 50(2), pp.661–670. 85 | 86 | Olofsson, K., Holmgren, J. & Olsson, H., 2014. Tree stem and height measurements using terrestrial laser scanning and the RANSAC algorithm. Remote Sensing, 6(5), pp.4323–4344. 87 | 88 | Conto, T. et al., 2017. Performance of stem denoising and stem modelling algorithms on single tree point clouds from terrestrial laser scanning. Computers and Electronics in Agriculture, v. 143, p. 165-176. 89 | } 90 | -------------------------------------------------------------------------------- /man/shapeFit.forks.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{shapeFit.forks} 4 | \alias{shapeFit.forks} 5 | \title{EXPERIMENTAL: Point cloud multiple circle fit} 6 | \usage{ 7 | shapeFit.forks( 8 | dlas, 9 | pixel_size = 0.02, 10 | max_d = 0.4, 11 | votes_percentile = 0.7, 12 | min_density = 0.25, 13 | plot = FALSE 14 | ) 15 | } 16 | \arguments{ 17 | \item{dlas}{\code{\link[lidR:LAS]{LAS}} object.} 18 | 19 | \item{pixel_size}{\code{numeric} - pixel side length to discretize the point cloud layers while performing the Hough Transform circle search.} 20 | 21 | \item{max_d}{\code{numeric} - largest tree diameter expected in the point cloud.} 22 | 23 | \item{votes_percentile}{\code{numeric} - use only estimates with more votes than \code{votes_percentile}.} 24 | 25 | \item{min_density}{\code{numeric} - between 0 and 1 - minimum point density within a pixel evaluated on the Hough Transform - i.e. only \emph{dense} point clousters will undergo circle search.} 26 | 27 | \item{plot}{\code{logical} - plot the results?} 28 | } 29 | \description{ 30 | Search and fit multiple 2D circles on a point cloud layer from a single tree, i.e. a forked stem segment. 31 | } 32 | -------------------------------------------------------------------------------- /man/smp.randomize.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sample_methods.R 3 | \name{smp.randomize} 4 | \alias{smp.randomize} 5 | \title{Point sampling algorithm: random sample} 6 | \usage{ 7 | smp.randomize(p = 0.5) 8 | } 9 | \arguments{ 10 | \item{p}{\code{numeric} - sampling probability (from 0 to 1).} 11 | } 12 | \description{ 13 | This function is meant to be used inside \code{\link{tlsSample}}. It selects points randomly, returning a fraction of the input point cloud. 14 | } 15 | -------------------------------------------------------------------------------- /man/smp.voxelize.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sample_methods.R 3 | \name{smp.voxelize} 4 | \alias{smp.voxelize} 5 | \title{Point sampling algorithm: systematic voxel grid} 6 | \usage{ 7 | smp.voxelize(spacing = 0.05) 8 | } 9 | \arguments{ 10 | \item{spacing}{\code{numeric} - voxel side length, in point cloud units.} 11 | } 12 | \description{ 13 | This function is meant to be used inside \code{\link{tlsSample}}. It selects one random point per voxel at a given spatial resolution. 14 | } 15 | -------------------------------------------------------------------------------- /man/stemPoints.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{stemPoints} 4 | \alias{stemPoints} 5 | \title{Stem points classification} 6 | \usage{ 7 | stemPoints(las, method = stm.hough()) 8 | } 9 | \arguments{ 10 | \item{las}{\code{\link[lidR:LAS]{LAS}} object.} 11 | 12 | \item{method}{stem denoising algorithm. Currently available: \code{\link{stm.hough}}, \code{\link{stm.eigen.knn}} and \code{\link{stm.eigen.voxel}}.} 13 | } 14 | \value{ 15 | \code{\link[lidR:LAS]{LAS}} object. 16 | } 17 | \description{ 18 | Classify stem points of all trees in a \strong{normalized} point cloud. Stem denoising methods are prefixed by \code{stm}. 19 | } 20 | \examples{ 21 | ### single tree 22 | file = system.file("extdata", "spruce.laz", package="TreeLS") 23 | tls = readTLS(file) \%>\% 24 | tlsNormalize \%>\% 25 | stemPoints(stm.hough(h_base = c(.5,2))) 26 | plot(tls, color='Stem') 27 | 28 | ### entire forest plot 29 | file = system.file("extdata", "pine_plot.laz", package="TreeLS") 30 | tls = readTLS(file) \%>\% 31 | tlsNormalize \%>\% 32 | tlsSample 33 | 34 | map = treeMap(tls, map.hough()) 35 | tls = treePoints(tls, map, trp.crop(circle=FALSE)) 36 | tls = stemPoints(tls, stm.hough(pixel_size = 0.03)) 37 | tlsPlot(tls) 38 | } 39 | -------------------------------------------------------------------------------- /man/stm.eigen.knn.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stem_points_methods.R 3 | \name{stm.eigen.knn} 4 | \alias{stm.eigen.knn} 5 | \title{Stem denoising algorithm: KNN eigen decomposition + point normals intersections voting} 6 | \usage{ 7 | stm.eigen.knn( 8 | h_step = 0.5, 9 | max_curvature = 0.1, 10 | max_verticality = 10, 11 | voxel_spacing = 0.025, 12 | max_d = 0.5, 13 | votes_weight = 0.2, 14 | v3d = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{h_step}{\code{numeric} - height interval to perform point filtering/assignment/classification.} 19 | 20 | \item{max_curvature}{\code{numeric} - maximum curvature (from 0 to 1) accepted when filtering a point neighborhood.} 21 | 22 | \item{max_verticality}{\code{numeric} - maximum deviation of a point neighborhood's orientation from an absolute vertical axis ( Z = c(0,0,1) ), in \emph{degrees} (from 0 to 90).} 23 | 24 | \item{voxel_spacing}{\code{numeric} - voxel (or pixel) spacing for counting point normals intersections.} 25 | 26 | \item{max_d}{\code{numeric} - largest tree diameter expected in the point cloud.} 27 | 28 | \item{votes_weight}{\code{numeric} - fraction of votes a point neighborhood needs do reach in order to belong to a stem (applied for every \emph{TreeID}), in relation to the voxel with most votes with same \emph{TreeID}.} 29 | 30 | \item{v3d}{\code{logical} - count votes in 3D voxels (TRUE) or 2D pixels (FALSE).} 31 | } 32 | \description{ 33 | This function is meant to be used inside \code{\link{stemPoints}}. It filters points based on their nearest neighborhood geometries (check \code{\link{fastPointMetrics}}) and assign them to stem patches if reaching a voxel with enough votes. 34 | } 35 | \section{Eigen Decomposition of Point Neighborhoods}{ 36 | 37 | 38 | Point filtering/classification methods that rely on eigen 39 | decomposition rely on shape indices calculated for point 40 | neighborhoods (knn or voxel). To derive these shape indices, eigen 41 | decomposition is performed on the XYZ columns of a point cloud patch. 42 | Metrics related to object curvature are calculated upon ratios of the resulting 43 | eigen values, and metrics related to object orientation are caltulated from 44 | approximate normals obtained from the eigen vectors. 45 | 46 | For instance, a point neighborhood that belongs to a perfect flat 47 | surface will have all of its variance explained by the first two eigen values, 48 | and none explained by the third eigen value. The 'normal' of such surface, 49 | i.e. the vector oriented in the direction orthogonal to the surface, 50 | is therefore represented by the third eigenvector. 51 | 52 | Methods for both tree mapping and stem segmentation use those metrics, so in order 53 | to speed up the workflow one might apply \code{\link{fastPointMetrics}} to the point 54 | cloud before other methods. The advantages of this approach are that users 55 | can parameterize the point neighborhoods themselves when calculating their metrics. 56 | Those calculations won't be performed again internally in the tree mapping or stem 57 | denoising methods, reducing the overall processing time. 58 | } 59 | 60 | \section{Radius Estimation Through Normal Vectors Intersection}{ 61 | 62 | 63 | \code{stemPoints} methods that filter points based on eigen decomposition 64 | metrics (knn or voxel) provide a rough estimation of stem segments radii 65 | by splitting every stem segment into a local voxel space and counting 66 | the number of times that point normals intersect on every voxel (votes). 67 | Every stem point then has a radius assigned to it, corresponding to the distance 68 | between the point and the voxel with most votes its normal intersects. The average of 69 | all points' radii in a stem segment is the segment's radius. For approximately straight 70 | vertical stem segments, the voting can be done in 2D (pixels). 71 | 72 | The point normals of this method are extracted from the eigen vectors calculated by 73 | \code{\link{fastPointMetrics}}. On top of the point metrics used for stem point filtering, the following 74 | fields are also added to the \code{LAS} object: 75 | 76 | \itemize{ 77 | \item \code{Votes}: number of normal vector intersections crossing the point's normal at its estimated center 78 | \item \code{VotesWeight}: ratio of (votes count) / (highest votes count) per \emph{TreeID} 79 | \item \code{Radius}: estimated stem segment radius 80 | } 81 | 82 | This method was inspired by the denoising algorithm developed by Olofsson & Holmgren (2016), 83 | but it is not an exact reproduction of their work. 84 | } 85 | 86 | \references{ 87 | Liang, X. et al., 2012. Automatic stem mapping using single-scan terrestrial laser scanning. IEEE Transactions on Geoscience and Remote Sensing, 50(2), pp.661–670. 88 | 89 | Olofsson, K. & Holmgren, J., 2016. Single Tree Stem Profile Detection Using Terrestrial Laser Scanner Data, Flatness Saliency Features and Curvature Properties. Forests, 7, 207. 90 | } 91 | -------------------------------------------------------------------------------- /man/stm.eigen.voxel.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stem_points_methods.R 3 | \name{stm.eigen.voxel} 4 | \alias{stm.eigen.voxel} 5 | \title{Stem denoising algorithm: Voxel eigen decomposition + point normals intersections voting} 6 | \usage{ 7 | stm.eigen.voxel( 8 | h_step = 0.5, 9 | max_curvature = 0.1, 10 | max_verticality = 10, 11 | voxel_spacing = 0.025, 12 | max_d = 0.5, 13 | votes_weight = 0.2, 14 | v3d = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{h_step}{\code{numeric} - height interval to perform point filtering/assignment/classification.} 19 | 20 | \item{max_curvature}{\code{numeric} - maximum curvature (from 0 to 1) accepted when filtering a point neighborhood.} 21 | 22 | \item{max_verticality}{\code{numeric} - maximum deviation of a point neighborhood's orientation from an absolute vertical axis ( Z = c(0,0,1) ), in \emph{degrees} (from 0 to 90).} 23 | 24 | \item{voxel_spacing}{\code{numeric} - voxel side length.} 25 | 26 | \item{max_d}{\code{numeric} - largest tree diameter expected in the point cloud.} 27 | 28 | \item{votes_weight}{\code{numeric} - fraction of votes a point neighborhood needs do reach in order to belong to a stem (applied for every \emph{TreeID}), in relation to the voxel with most votes with same \emph{TreeID}.} 29 | 30 | \item{v3d}{\code{logical} - count votes in 3D voxels (TRUE) or 2D pixels (FALSE).} 31 | } 32 | \description{ 33 | This function is meant to be used inside \code{\link{stemPoints}}. It filters points based on their voxel geometries (check \code{\link{fastPointMetrics}}) and assign them to stem patches if reaching a voxel with enough votes. 34 | } 35 | \section{Eigen Decomposition of Point Neighborhoods}{ 36 | 37 | 38 | Point filtering/classification methods that rely on eigen 39 | decomposition rely on shape indices calculated for point 40 | neighborhoods (knn or voxel). To derive these shape indices, eigen 41 | decomposition is performed on the XYZ columns of a point cloud patch. 42 | Metrics related to object curvature are calculated upon ratios of the resulting 43 | eigen values, and metrics related to object orientation are caltulated from 44 | approximate normals obtained from the eigen vectors. 45 | 46 | For instance, a point neighborhood that belongs to a perfect flat 47 | surface will have all of its variance explained by the first two eigen values, 48 | and none explained by the third eigen value. The 'normal' of such surface, 49 | i.e. the vector oriented in the direction orthogonal to the surface, 50 | is therefore represented by the third eigenvector. 51 | 52 | Methods for both tree mapping and stem segmentation use those metrics, so in order 53 | to speed up the workflow one might apply \code{\link{fastPointMetrics}} to the point 54 | cloud before other methods. The advantages of this approach are that users 55 | can parameterize the point neighborhoods themselves when calculating their metrics. 56 | Those calculations won't be performed again internally in the tree mapping or stem 57 | denoising methods, reducing the overall processing time. 58 | } 59 | 60 | \section{Radius Estimation Through Normal Vectors Intersection}{ 61 | 62 | 63 | \code{stemPoints} methods that filter points based on eigen decomposition 64 | metrics (knn or voxel) provide a rough estimation of stem segments radii 65 | by splitting every stem segment into a local voxel space and counting 66 | the number of times that point normals intersect on every voxel (votes). 67 | Every stem point then has a radius assigned to it, corresponding to the distance 68 | between the point and the voxel with most votes its normal intersects. The average of 69 | all points' radii in a stem segment is the segment's radius. For approximately straight 70 | vertical stem segments, the voting can be done in 2D (pixels). 71 | 72 | The point normals of this method are extracted from the eigen vectors calculated by 73 | \code{\link{fastPointMetrics}}. On top of the point metrics used for stem point filtering, the following 74 | fields are also added to the \code{LAS} object: 75 | 76 | \itemize{ 77 | \item \code{Votes}: number of normal vector intersections crossing the point's normal at its estimated center 78 | \item \code{VotesWeight}: ratio of (votes count) / (highest votes count) per \emph{TreeID} 79 | \item \code{Radius}: estimated stem segment radius 80 | } 81 | 82 | This method was inspired by the denoising algorithm developed by Olofsson & Holmgren (2016), 83 | but it is not an exact reproduction of their work. 84 | } 85 | 86 | \references{ 87 | Liang, X. et al., 2012. Automatic stem mapping using single-scan terrestrial laser scanning. IEEE Transactions on Geoscience and Remote Sensing, 50(2), pp.661–670. 88 | 89 | Olofsson, K. & Holmgren, J., 2016. Single Tree Stem Profile Detection Using Terrestrial Laser Scanner Data, Flatness Saliency Features and Curvature Properties. Forests, 7, 207. 90 | } 91 | -------------------------------------------------------------------------------- /man/stm.hough.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stem_points_methods.R 3 | \name{stm.hough} 4 | \alias{stm.hough} 5 | \title{Stem denoising algorithm: Hough Transform} 6 | \usage{ 7 | stm.hough( 8 | h_step = 0.5, 9 | max_d = 0.5, 10 | h_base = c(1, 2.5), 11 | pixel_size = 0.025, 12 | min_density = 0.1, 13 | min_votes = 3 14 | ) 15 | } 16 | \arguments{ 17 | \item{h_step}{\code{numeric} - height interval to perform point filtering/assignment/classification.} 18 | 19 | \item{max_d}{\code{numeric} - largest tree diameter expected in the point cloud.} 20 | 21 | \item{h_base}{\code{numeric} vector of length 2 - tree base height interval to initiate circle search.} 22 | 23 | \item{pixel_size}{\code{numeric} - pixel side length to discretize the point cloud layers while performing the Hough Transform circle search.} 24 | 25 | \item{min_density}{\code{numeric} - between 0 and 1 - minimum point density within a pixel evaluated on the Hough Transform - i.e. only \emph{dense} point clousters will undergo circle search.} 26 | 27 | \item{min_votes}{\code{integer} - Hough Transform parameter - minimum number of circle intersections over a pixel to assign it as a circle center candidate.} 28 | } 29 | \description{ 30 | This function is meant to be used inside \code{\link{stemPoints}}. It applies an adapted version of the Hough Transform for circle search. Mode details are given in the sections below. 31 | } 32 | \section{\code{LAS@data} Special Fields}{ 33 | 34 | 35 | Meaninful new fields in the output: 36 | 37 | \itemize{ 38 | \item \code{Stem}: \code{TRUE} for stem points 39 | \item \code{Segment}: stem segment number (from bottom to top and nested with TreeID) 40 | \item \code{Radius}: approximate radius of the point's stem segment estimated by the Hough Transform - always a multiple of the \code{pixel_size} 41 | \item \code{Votes}: votes received by the stem segment's center through the Hough Transform 42 | } 43 | } 44 | 45 | \section{Adapted Hough Transform}{ 46 | 47 | 48 | The Hough Transform circle search algorithm used in 49 | TreeLS applies a constrained circle search on discretized 50 | point cloud layers. Tree-wise, the circle search is 51 | recursive, in which the search for circle parameters 52 | of a stem section is constrained to the 53 | \emph{feature space} of the stem section underneath it. 54 | Initial estimates of the stem's \emph{feature space} 55 | are performed on a \emph{baselise} stem segment - i.e. 56 | a low height interval where a tree's bole is expected 57 | to be clearly visible in the point cloud. 58 | The algorithm is described in detail by Conto et al. (2017). 59 | 60 | This adapted version of the algorithm is very robust against outliers, 61 | but not against forked or leaning stems. 62 | } 63 | 64 | \references{ 65 | Olofsson, K., Holmgren, J. & Olsson, H., 2014. Tree stem and height measurements using terrestrial laser scanning and the RANSAC algorithm. Remote Sensing, 6(5), pp.4323–4344. 66 | 67 | Conto, T. et al., 2017. Performance of stem denoising and stem modelling algorithms on single tree point clouds from terrestrial laser scanning. Computers and Electronics in Agriculture, v. 143, p. 165-176. 68 | } 69 | -------------------------------------------------------------------------------- /man/tlsCrop.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{tlsCrop} 4 | \alias{tlsCrop} 5 | \title{Point cloud cropping} 6 | \usage{ 7 | tlsCrop(las, x, y, len, circle = TRUE, negative = FALSE) 8 | } 9 | \arguments{ 10 | \item{las}{\code{\link[lidR:LAS]{LAS}} object.} 11 | 12 | \item{x, y}{\code{numeric} - X and Y center coordinates of the crop region.} 13 | 14 | \item{len}{\code{numeric} - if \code{circle = TRUE}, \code{len} is the circle's radius, otherwise it is the side length of a square.} 15 | 16 | \item{circle}{\code{logical} - crops a circle (if \code{TRUE}) or a square.} 17 | 18 | \item{negative}{\code{logical} - if \code{TRUE}, returns all points **outside** the specified circle/square perimeter.} 19 | } 20 | \value{ 21 | \code{\link[lidR:LAS]{LAS}} object. 22 | } 23 | \description{ 24 | Returns a cropped point cloud of all points inside or outside specified boundaries of circle or square shapes. 25 | } 26 | \examples{ 27 | file = system.file("extdata", "pine_plot.laz", package="TreeLS") 28 | tls = readTLS(file) 29 | 30 | tls = tlsCrop(tls, 2, 3, 1.5, TRUE, TRUE) 31 | plot(tls) 32 | 33 | tls = tlsCrop(tls, 5, 5, 5, FALSE, FALSE) 34 | plot(tls) 35 | } 36 | -------------------------------------------------------------------------------- /man/tlsInventory.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{tlsInventory} 4 | \alias{tlsInventory} 5 | \title{Extract forest inventory metrics from a point cloud} 6 | \usage{ 7 | tlsInventory( 8 | las, 9 | dh = 1.3, 10 | dw = 0.5, 11 | hp = 1, 12 | d_method = shapeFit(shape = "circle", algorithm = "ransac", n = 15, n_best = 20) 13 | ) 14 | } 15 | \arguments{ 16 | \item{las}{\code{\link[lidR:LAS]{LAS}} object.} 17 | 18 | \item{dh}{\code{numeric} - height layer (above ground) to estimate stem diameters, in point cloud units.} 19 | 20 | \item{dw}{\code{numeric} - height layer width, in point cloud units.} 21 | 22 | \item{hp}{\code{numeric} - height percentile to extract per tree (0-1). Use 1 for top height, i.e. the highest point.} 23 | 24 | \item{d_method}{parameterized \code{\link{shapeFit}} function, i.e. method to use for diameter estimation.} 25 | } 26 | \description{ 27 | Estimation of diameter and height tree-wise for normalized point clouds with assigned stem points. 28 | } 29 | \examples{ 30 | \donttest{ 31 | file = system.file("extdata", "pine_plot.laz", package="TreeLS") 32 | tls = readTLS(file) \%>\% 33 | tlsNormalize \%>\% 34 | tlsSample 35 | 36 | map = treeMap(tls, map.hough()) 37 | tls = treePoints(tls, map, trp.crop(circle=FALSE)) 38 | tls = stemPoints(tls, stm.hough()) 39 | 40 | dmt = shapeFit(shape = 'circle', algorithm='ransac', n=20) 41 | inv = tlsInventory(tls, d_method = dmt) 42 | tlsPlot(tls, inv) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /man/tlsNormalize.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{tlsNormalize} 4 | \alias{tlsNormalize} 5 | \title{Normalize a TLS point cloud} 6 | \usage{ 7 | tlsNormalize(las, min_res = 0.25, keep_ground = TRUE) 8 | } 9 | \arguments{ 10 | \item{las}{\code{\link[lidR:LAS]{LAS}} object.} 11 | 12 | \item{min_res}{\code{numeric} - minimum resolution of the DTM used for normalization, in point cloud units.} 13 | 14 | \item{keep_ground}{\code{logical} - if \code{FALSE} removes the ground points from the output.} 15 | } 16 | \value{ 17 | \code{\link[lidR:LAS]{LAS}} object. 18 | } 19 | \description{ 20 | Fast normalization of TLS point clouds based on a Digital Terrain Model (DTM) of the ground points. If the input's ground points are not yet classified, the \code{\link[lidR:csf]{csf}} algorithm is applied internally. 21 | } 22 | \examples{ 23 | file = system.file("extdata", "pine_plot.laz", package="TreeLS") 24 | tls = readTLS(file) 25 | plot(tls) 26 | rgl::axes3d(col='white') 27 | 28 | tls = tlsNormalize(tls, 0.5, FALSE) 29 | plot(tls) 30 | rgl::axes3d(col='white') 31 | } 32 | -------------------------------------------------------------------------------- /man/tlsPlot.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R, R/plot_extras.R 3 | \name{tlsPlot} 4 | \alias{tlsPlot} 5 | \alias{add_segmentIDs} 6 | \alias{add_treeIDs} 7 | \alias{add_treeMap} 8 | \alias{add_treePoints} 9 | \alias{add_stemPoints} 10 | \alias{add_stemSegments} 11 | \alias{add_tlsInventory} 12 | \title{Plot \emph{TreeLS} outputs} 13 | \usage{ 14 | tlsPlot(..., fast = FALSE, tree_id = NULL, segment = NULL) 15 | 16 | add_segmentIDs(x, las, ...) 17 | 18 | add_treeIDs(x, las, ...) 19 | 20 | add_treeMap(x, las, ...) 21 | 22 | add_treePoints(x, las, color_func = pastel.colors, ...) 23 | 24 | add_stemPoints(x, las, ...) 25 | 26 | add_stemSegments(x, stems_data_table, color = "white", fast = FALSE) 27 | 28 | add_tlsInventory(x, inventory_data_table, color = "white", fast = FALSE) 29 | } 30 | \arguments{ 31 | \item{...}{in \code{tlsPlot}: any object returned from a \emph{TreeLS} method. In the \code{add_*} methods: parameters passed down to 3D plotting \code{rgl} functions.} 32 | 33 | \item{fast}{\code{logical}, use \code{TRUE} to plot spheres representing tree diameters or \code{FALSE} to plot detailed 3D cylinders.} 34 | 35 | \item{tree_id}{\code{numeric} - plot only the tree matching this tree id.} 36 | 37 | \item{segment}{\code{numeric} - plot only stem segments matching this segment id.} 38 | 39 | \item{x}{output from \code{\link[lidR:plot]{plot}} or \code{tlsPlot}} 40 | 41 | \item{las}{\code{\link[lidR:LAS]{LAS}} object.} 42 | 43 | \item{color_func}{color palette function used in \code{add_treePoints}.} 44 | 45 | \item{stems_data_table, inventory_data_table}{\code{data.table} objects generated by \code{stemSegmentation} and \code{tlsInventory}.} 46 | 47 | \item{color}{color of 3D objects.} 48 | } 49 | \description{ 50 | Plot the outputs of \emph{TreeLS} methods on the same scene using \code{rgl}. 51 | } 52 | \examples{ 53 | file = system.file("extdata", "pine.laz", package="TreeLS") 54 | tls = readTLS(file) \%>\% 55 | tlsNormalize \%>\% 56 | stemPoints(stm.hough()) 57 | 58 | dmt = shapeFit(shape = 'circle', algorithm='ransac', n=20) 59 | inv = tlsInventory(tls, d_method = dmt) 60 | 61 | ### quick plot 62 | tlsPlot(tls, inv) 63 | 64 | ### customizable plots 65 | x = plot(tls) 66 | add_stemPoints(x, tls, color='red', size=3) 67 | add_tlsInventory(x, inv, color='yellow') 68 | add_segmentIDs(x, tls, color='white', cex=2, pos=4) 69 | } 70 | -------------------------------------------------------------------------------- /man/tlsRotate.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{tlsRotate} 4 | \alias{tlsRotate} 5 | \title{Rotate point cloud to fit a horizontal ground plane} 6 | \usage{ 7 | tlsRotate(las) 8 | } 9 | \arguments{ 10 | \item{las}{\code{\link[lidR:LAS]{LAS}} object.} 11 | } 12 | \value{ 13 | \code{\link[lidR:LAS]{LAS}} object. 14 | } 15 | \description{ 16 | Check for ground points and rotates the point cloud aligning its ground surface to a horizontal plane (XY). 17 | This function is especially useful for point clouds not georeferenced or generated through mobile scanning, 18 | which might present a tilted coordinate system. 19 | } 20 | -------------------------------------------------------------------------------- /man/tlsSample.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{tlsSample} 4 | \alias{tlsSample} 5 | \title{Resample a point cloud} 6 | \usage{ 7 | tlsSample(las, method = smp.voxelize()) 8 | } 9 | \arguments{ 10 | \item{las}{\code{\link[lidR:LAS]{LAS}} object.} 11 | 12 | \item{method}{point sampling algorithm. Currently available: \code{\link{smp.voxelize}} and \code{\link{smp.randomize}}} 13 | } 14 | \value{ 15 | \code{\link[lidR:LAS]{LAS}} object. 16 | } 17 | \description{ 18 | Applies a sampling algorithm to reduce a point cloud's density. Sampling methods are prefixed by \code{smp}. 19 | } 20 | \examples{ 21 | file = system.file("extdata", "pine.laz", package="TreeLS") 22 | tls = readTLS(file) 23 | nrow(tls@data) 24 | 25 | ### sample points systematically from a 3D voxel grid 26 | vx = tlsSample(tls, smp.voxelize(0.05)) 27 | nrow(vx@data) 28 | 29 | ### sample half of the points randomly 30 | rd = tlsSample(tls, smp.randomize(0.5)) 31 | nrow(rd@data) 32 | 33 | } 34 | -------------------------------------------------------------------------------- /man/tlsTransform.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{tlsTransform} 4 | \alias{tlsTransform} 5 | \title{Simple operations on point cloud objects} 6 | \usage{ 7 | tlsTransform( 8 | las, 9 | xyz = c("X", "Y", "Z"), 10 | bring_to_origin = FALSE, 11 | rotate = FALSE 12 | ) 13 | } 14 | \arguments{ 15 | \item{las}{\code{\link[lidR:LAS]{LAS}} object.} 16 | 17 | \item{xyz}{\code{character} vector of length 3 - \code{LAS}' columns to be reassigned as XYZ, respectively. 18 | Use minus signs to mirror an axis` coordinates - more details in the sections below.} 19 | 20 | \item{bring_to_origin}{\code{logical} - force point cloud origin to match \code{c(0,0,0)}? If \code{TRUE}, 21 | clears the header of the \code{LAS} object.} 22 | 23 | \item{rotate}{\code{logical} - rotate the point cloud to align the ground points horizontally (as in \code{\link{tlsRotate}})?} 24 | } 25 | \value{ 26 | \code{\link[lidR:LAS]{LAS}} object. 27 | } 28 | \description{ 29 | Apply transformations to the XYZ axes of a point cloud. 30 | } 31 | \section{XYZ Manipulation}{ 32 | 33 | 34 | The \code{xyz} argument can take a few different forms. It is useful for shifting axes positions in a point cloud or 35 | to mirror an axis' coordinates. All axes characters can be entered in lower or uppercase and also be preceded 36 | by a minus sign ('-') to reverse its coordinates. 37 | } 38 | 39 | \examples{ 40 | file = system.file("extdata", "pine.laz", package="TreeLS") 41 | tls = readTLS(file) 42 | bbox(tls) 43 | range(tls$Z) 44 | 45 | ### swap the Y and Z axes 46 | zy = tlsTransform(tls, c('x', 'z', 'y')) 47 | bbox(zy) 48 | range(zy$Z) 49 | 50 | ### return an upside down point cloud 51 | ud = tlsTransform(tls, c('x', 'y', '-z')) 52 | bbox(ud) 53 | range(ud$Z) 54 | plot(zy) 55 | 56 | ### mirror all axes, then set the point cloud's starting point as the origin 57 | rv = tlsTransform(tls, c('-x', '-y', '-z'), bring_to_origin=TRUE) 58 | bbox(rv) 59 | range(rv$Z) 60 | } 61 | -------------------------------------------------------------------------------- /man/treeMap.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{treeMap} 4 | \alias{treeMap} 5 | \title{Map tree occurrences from TLS data} 6 | \usage{ 7 | treeMap(las, method = map.hough(), merge = 0.2, positions_only = FALSE) 8 | } 9 | \arguments{ 10 | \item{las}{\code{\link[lidR:LAS]{LAS}} object.} 11 | 12 | \item{method}{tree mapping algorithm. Currently available: \code{\link{map.hough}}, \code{\link{map.eigen.knn}}, \code{\link{map.eigen.voxel}} and \code{\link{map.pick}}.} 13 | 14 | \item{merge}{\code{numeric} - parameter passed down to \code{\link{treeMap.merge}} (if \code{merge > 0}).} 15 | 16 | \item{positions_only}{\code{logical} - if \code{TRUE} returns only a 2D tree map as a \code{data.table}.} 17 | } 18 | \value{ 19 | signed \code{LAS} or \code{data.table}. 20 | } 21 | \description{ 22 | Estimates tree occurrence regions from a \strong{normalized} point cloud. Tree mapping methods are prefixed by \code{map}. 23 | } 24 | \examples{ 25 | file = system.file("extdata", "pine_plot.laz", package="TreeLS") 26 | tls = readTLS(file) \%>\% 27 | tlsNormalize \%>\% 28 | tlsSample 29 | 30 | x = plot(tls) 31 | 32 | map = treeMap(tls, map.hough(h_step = 1, max_h = 4)) 33 | add_treeMap(x, map, color='red') 34 | 35 | xymap = treeMap.positions(map) 36 | } 37 | -------------------------------------------------------------------------------- /man/treeMap.merge.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{treeMap.merge} 4 | \alias{treeMap.merge} 5 | \title{Merge tree coordinates too close on \code{treeMap} outputs.} 6 | \usage{ 7 | treeMap.merge(map, d = 0.2) 8 | } 9 | \arguments{ 10 | \item{map}{object generated by \code{\link{treeMap}}.} 11 | 12 | \item{d}{\code{numeric} - distance threshold.} 13 | } 14 | \description{ 15 | Check all tree neighborhoods and merge TreeIDs which are too close in a \code{treeMap}'s object. 16 | } 17 | \details{ 18 | The \code{d} parameter is a relative measure of close neighbors. Sorting all possible pairs by distance from a tree map, 19 | the merge criterion is that none of the closest pairs should be distant less than the next closest pair's distance minus \code{d}. 20 | This method is useful when merging forked stems or point clusters from plots with too much understory, especially if those are 21 | from forest stands with regularly spaced trees. 22 | } 23 | -------------------------------------------------------------------------------- /man/treeMap.positions.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{treeMap.positions} 4 | \alias{treeMap.positions} 5 | \title{Convert a tree map to a 2D \code{data.table}} 6 | \usage{ 7 | treeMap.positions(map, plot = TRUE) 8 | } 9 | \arguments{ 10 | \item{map}{object generated by \code{\link{treeMap}}.} 11 | 12 | \item{plot}{\code{logical} - plot the tree map?} 13 | } 14 | \value{ 15 | signed \code{data.table} of tree IDs and XY coordinates. 16 | } 17 | \description{ 18 | Extracts the tree XY positions from a \emph{treeMap} output. 19 | } 20 | \examples{ 21 | file = system.file("extdata", "pine_plot.laz", package="TreeLS") 22 | tls = readTLS(file) \%>\% 23 | tlsNormalize \%>\% 24 | tlsSample 25 | 26 | x = plot(tls) 27 | 28 | map = treeMap(tls, map.hough(h_step = 1, max_h = 4)) 29 | add_treeMap(x, map, color='red') 30 | 31 | xymap = treeMap.positions(map) 32 | } 33 | -------------------------------------------------------------------------------- /man/treePoints.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{treePoints} 4 | \alias{treePoints} 5 | \title{Classify individual tree regions in a point cloud} 6 | \usage{ 7 | treePoints(las, map, method = trp.voronoi()) 8 | } 9 | \arguments{ 10 | \item{las}{\code{\link[lidR:LAS]{LAS}} object.} 11 | 12 | \item{map}{object generated by \code{\link{treeMap}}.} 13 | 14 | \item{method}{tree region algorithm. Currently available: \code{\link{trp.voronoi}} and \code{\link{trp.crop}}.} 15 | } 16 | \value{ 17 | \code{\link[lidR:LAS]{LAS}} object. 18 | } 19 | \description{ 20 | Assigns \code{TreeID}s to a \code{LAS} object based on coordinates extracted from a 21 | \code{\link{treeMap}} object. Tree region segmentation methods are prefixed by \code{trp}. 22 | } 23 | \examples{ 24 | file = system.file("extdata", "pine_plot.laz", package="TreeLS") 25 | tls = readTLS(file) \%>\% 26 | tlsNormalize \%>\% 27 | tlsSample 28 | 29 | map = treeMap(tls, map.hough()) 30 | tls = treePoints(tls, map, trp.crop(circle=FALSE)) 31 | 32 | x = plot(tls, size=1) 33 | add_treePoints(x, tls, size=2) 34 | add_treeIDs(x, tls, color='yellow', cex=2) 35 | } 36 | -------------------------------------------------------------------------------- /man/trp.crop.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tree_points_methods.R 3 | \name{trp.crop} 4 | \alias{trp.crop} 5 | \title{Tree points algorithm: fixed size patches.} 6 | \usage{ 7 | trp.crop(l = 1, circle = TRUE) 8 | } 9 | \arguments{ 10 | \item{l}{\code{numeric} - circle radius or square side length.} 11 | 12 | \item{circle}{\code{logical} - assign \code{TreeID}s to circular (\code{TRUE}) or squared (\code{FALSE}) patches.} 13 | } 14 | \description{ 15 | This function is meant to be used inside \code{\link{treePoints}}. Assign points to a \code{TreeID} inside circles/squares of fixed area around \code{\link{treeMap}} coordinates. 16 | } 17 | -------------------------------------------------------------------------------- /man/trp.voronoi.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tree_points_methods.R 3 | \name{trp.voronoi} 4 | \alias{trp.voronoi} 5 | \title{Tree points algorithm: voronoi polygons.} 6 | \usage{ 7 | trp.voronoi() 8 | } 9 | \description{ 10 | This function is meant to be used inside \code{\link{treePoints}}. Assign **all** points to a \code{TreeID} based on their closest \code{\link{treeMap}} coordinate. 11 | } 12 | -------------------------------------------------------------------------------- /man/writeTLS.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{writeTLS} 4 | \alias{writeTLS} 5 | \title{Export \emph{TreeLS} point clouds to las/laz files} 6 | \usage{ 7 | writeTLS(las, file, col_names = NULL, index = FALSE) 8 | } 9 | \arguments{ 10 | \item{las}{\code{\link[lidR:LAS]{LAS}} object.} 11 | 12 | \item{file}{file path.} 13 | 14 | \item{col_names}{column names from \emph{las} that you wish to export. If left empty, all columns not listed among 15 | \code{\link[lidR:LAS]{the standard LAS attributes}} are added to the file.} 16 | 17 | \item{index}{\code{logical} - write lax file also.} 18 | } 19 | \description{ 20 | Wrapper to \code{\link[lidR:writeLAS]{writeLAS}}. This function automatically adds new data columns as extra bytes 21 | to the written las/laz file using \code{\link[lidR:add_lasattribute]{add_lasattribute}} internally. 22 | } 23 | \examples{ 24 | file = system.file("extdata", "pine.laz", package="TreeLS") 25 | tls = readTLS(file) \%>\% fastPointMetrics#' 26 | tls_file = tempfile(fileext = '.laz') 27 | writeTLS(tls, tls_file) 28 | 29 | up_tls = readTLS(tls_file) 30 | summary(up_tls) 31 | } 32 | -------------------------------------------------------------------------------- /src/Makevars: -------------------------------------------------------------------------------- 1 | SOURCES = ./utils.cpp ./algorithms.cpp ./methods.cpp ./r_interface.cpp ./RcppExports.cpp 2 | CXX_STD = CXX17 3 | PKG_CXXFLAGS = $(SHLIB_OPENMP_CXXFLAGS) -I. -I../inst/include/ 4 | PKG_LIBS = $(SHLIB_OPENMP_CXXFLAGS) $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) 5 | -------------------------------------------------------------------------------- /src/Makevars.win: -------------------------------------------------------------------------------- 1 | SOURCES = ./utils.cpp ./algorithms.cpp ./methods.cpp ./r_interface.cpp ./RcppExports.cpp 2 | CXX_STD = CXX17 3 | PKG_CXXFLAGS = $(SHLIB_OPENMP_CXXFLAGS) -I. -I../inst/include/ 4 | PKG_LIBS = $(SHLIB_OPENMP_CXXFLAGS) $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) 5 | -------------------------------------------------------------------------------- /src/algorithms.hpp: -------------------------------------------------------------------------------- 1 | // =============================================================================== 2 | // 3 | // Developers: 4 | // 5 | // Tiago de Conto - tdc.florestal@gmail.com - https://github.com/tiagodc/ 6 | // 7 | // COPYRIGHT: Tiago de Conto, 2020 8 | // 9 | // This piece of software is open and free to use, redistribution and modifications 10 | // should be done in accordance to the GNU General Public License >= 3 11 | // 12 | // Use this software as you wish, but no warranty is provided whatsoever. For any 13 | // comments or questions on TreeLS, please contact the developer (prefereably through my github account) 14 | // 15 | // If publishing any work/study/research that used the tools in TreeLS, 16 | // please don't forget to cite the proper sources! 17 | // 18 | // Enjoy! 19 | // 20 | // =============================================================================== 21 | 22 | #include 23 | 24 | #ifndef ALGORITHMS_HPP 25 | #define ALGORITHMS_HPP 26 | 27 | #include "utils.hpp" 28 | 29 | vector circleDists(vector >& xyz, arma::vec& pars); 30 | 31 | vector cylDists(vector >& xyz, arma::vec& pars); 32 | 33 | vector eigenCircle(vector >& cloud); 34 | 35 | vector irlsCircle(vector >& las, vector initPars, double err_tol = 1E-06, unsigned int max_iter = 100); 36 | 37 | vector irlsCircleFit(NumericMatrix& cloud); 38 | 39 | vector irlsCylinder(vector >& las, vector initPars, double err_tol = 1E-06, unsigned int max_iter = 100); 40 | 41 | double nmCircleDist(const arma::vec& vals_inp, arma::vec* grad_out, void* opt_data); 42 | 43 | vector nmCircleFit(vector >& las); 44 | 45 | double nmCylinderDist(const arma::vec& vals_inp, arma::vec* grad_out, void* opt_data); 46 | 47 | vector nmCylinderFit(vector >& las); 48 | 49 | vector nmCylinderInit(vector >& las); 50 | 51 | vector ransacCircle(vector >& cloud, unsigned int nSamples = 5, double pConfidence = 0.99, double pInliers = 0.8, unsigned int nBest = 0); 52 | 53 | vector ransacCylinder(vector >& las, unsigned int nSamples=10, double pConfidence=0.99, double pInliers=0.8); 54 | 55 | Eigen::Matrix stl2eigenmat(vector >& xyz); 56 | 57 | Eigen::Matrix rotationMatrix(double ax, double ay, double az); 58 | 59 | vector > eigenmat2stl(Eigen::Matrix& mat); 60 | 61 | vector > rotateCloud(vector >& xyz, double ax, double ay, double az); 62 | 63 | vector > bruteForceRansacCylinder(vector >& cloud, unsigned int nSamples, double pConfidence, double pInliers, unsigned int nBest, double maxAngle = 45.0, bool bestOnly = false); 64 | 65 | #endif // ALGORITHMS_HPP -------------------------------------------------------------------------------- /src/methods.hpp: -------------------------------------------------------------------------------- 1 | // =============================================================================== 2 | // 3 | // Developers: 4 | // 5 | // Tiago de Conto - tdc.florestal@gmail.com - https://github.com/tiagodc/ 6 | // 7 | // COPYRIGHT: Tiago de Conto, 2020 8 | // 9 | // This piece of software is open and free to use, redistribution and modifications 10 | // should be done in accordance to the GNU General Public License >= 3 11 | // 12 | // Use this software as you wish, but no warranty is provided whatsoever. For any 13 | // comments or questions on TreeLS, please contact the developer (prefereably through my github account) 14 | // 15 | // If publishing any work/study/research that used the tools in TreeLS, 16 | // please don't forget to cite the proper sources! 17 | // 18 | // Enjoy! 19 | // 20 | // =============================================================================== 21 | 22 | #ifndef METHODS_HPP 23 | #define METHODS_HPP 24 | 25 | #include "algorithms.hpp" 26 | 27 | void assignTreeId(vector& disks, double distmax, double countDensity, unsigned int minLayers=1); 28 | 29 | vector getCenters(Raster* raster, double max_radius=0.25, double min_den=0.1, unsigned int min_votes=3); 30 | 31 | Raster getCounts(vector >& slice, double pixel_size); 32 | 33 | HoughCenters getSingleCenter(Raster* raster, double max_radius=0.25, double min_den=0.1, unsigned int min_votes=3); 34 | 35 | vector > > irlsPlotCircles(vector >& cloud, vector& treeId, vector& segments, vector& radii, unsigned int nPoints=100, double tolerance=0.05); 36 | 37 | vector > > irlsPlotCylinders(vector >& cloud, vector& treeId, vector& segments, vector& radii, unsigned int nPoints=100, double tolerance=0.05); 38 | 39 | vector > irlsStemCircle(vector >& cloud, vector& segments, vector& radii, unsigned int nPoints=0, double tolerance=0.05); 40 | 41 | vector > irlsStemCylinder(vector >& cloud, vector& segments, vector& radii, unsigned int nPoints=100, double tolerance=0.05); 42 | 43 | vector > > ransacPlotCircles(vector >& cloud, vector& treeId, vector& segments, vector& radii, unsigned int nSamples = 5, double pConfidence = 0.99, double pInliers = 0.8, double tolerance = 0.05); 44 | 45 | vector > > ransacPlotCylinders(vector >& cloud, vector& treeId, vector& segments, vector& radii, unsigned int nSamples=10, double pConfidence=0.95, double pInliers=0.9, double tolerance=0.05); 46 | 47 | vector< vector > ransacStemCircle(vector >& cloud, std::vector& segments, std::vector& radii, unsigned int nSamples = 5, double pConfidence = 0.99, double pInliers = 0.8, double tolerance = 0.05); 48 | 49 | vector > ransacStemCylinder(vector >& cloud, vector& segments, vector& radii, unsigned int nSamples=10, double pConfidence=0.95, double pInliers=0.9, double tolerance=0.05); 50 | 51 | vector treeHough(vector >& cppCloud, double h1 = 1, double h2 = 3, double hstep=0.5, double radius=0.25, double pixel=0.025, double density=0.1, unsigned int votes=3); 52 | 53 | vector > pointMetrics(vector >& cloud, vector >& idx, vector which_metrics); 54 | 55 | vector > voxelMetrics(vector >& cloud, vector >& idx, vector which_metrics); 56 | 57 | vector voxelIndex(vector >& cloud, double voxel_spacing=0.05); 58 | 59 | vector > > treeEigenHough(vector >& cppEigenCloud, vector& pointId, vector& segId, double voxel_size, double max_rad, bool is2d = true, bool getSpace = false); 60 | 61 | vector > > plotEigenHough(vector >& cppEigenCloud, vector& pointId, vector& treeId, vector& segId, double voxel_size, double max_rad, bool is2d = true, bool getSpace = false); 62 | 63 | vector treeIdsFromMap(vector >& xy, vector >& xymap, vector ids, double length = 2.5, bool circle = true); 64 | 65 | vector > bfStemCylinder(vector >& cloud, vector& segments, vector& radii, unsigned int nSamples = 10, double pConfidence = 0.99, double pInliers = 0.8, double max_angle = 30, double tolerance = 0.05); 66 | 67 | vector > > bfPlotCylinders(vector >& cloud, vector& treeId, vector& segments, vector& radii, unsigned int nSamples=10, double pConfidence = 0.95, double pInliers = 0.8, double max_angle = 30, double tolerance = 0.05); 68 | 69 | #endif // METHODS_HPP 70 | -------------------------------------------------------------------------------- /src/misc/determine_bounds_type.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * Determine the upper-lower bounds combo type 23 | */ 24 | 25 | // note: std::isfinite is not true for: NaN, - Inf, or + Inf 26 | 27 | inline 28 | arma::uvec 29 | determine_bounds_type(const bool vals_bound, const size_t n_vals, const arma::vec& lower_bounds, const arma::vec& upper_bounds) 30 | { 31 | arma::uvec ret_vec(n_vals); 32 | 33 | ret_vec.fill(1); // base case: 1 - no bounds imposed 34 | 35 | if (vals_bound) 36 | { 37 | for (size_t i=0; i < n_vals; i++) 38 | { 39 | if ( std::isfinite(lower_bounds(i)) && std::isfinite(upper_bounds(i)) ) { 40 | // lower and upper bound imposed 41 | ret_vec(i) = 4; 42 | } else if ( std::isfinite(lower_bounds(i)) && !std::isfinite(upper_bounds(i)) ) { 43 | // lower bound only 44 | ret_vec(i) = 2; 45 | } else if ( !std::isfinite(lower_bounds(i)) && std::isfinite(upper_bounds(i)) ) { 46 | // upper bound only 47 | ret_vec(i) = 3; 48 | } 49 | } 50 | } 51 | 52 | // 53 | 54 | return ret_vec; 55 | } 56 | -------------------------------------------------------------------------------- /src/misc/error_reporting.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * Error reporting 23 | */ 24 | 25 | #ifndef _optim_error_reporting_HPP 26 | #define _optim_error_reporting_HPP 27 | 28 | void error_reporting(arma::vec& out_vals, const arma::vec& x_p, std::function opt_objfn, void* opt_data, 29 | bool& success, const double err, const double err_tol, const int iter, const int iter_max, const int conv_failure_switch, algo_settings_t* settings_inp); 30 | 31 | void error_reporting(arma::vec& out_vals, const arma::vec& x_p, std::function opt_objfn, void* opt_data, 32 | bool& success, const int conv_failure_switch, algo_settings_t* settings_inp); 33 | 34 | void error_reporting(arma::vec& out_vals, const arma::vec& x_p, std::function opt_objfn, void* opt_data, 35 | bool& success, const double err, const double err_tol, const int iter, const int iter_max, const int conv_failure_switch, algo_settings_t* settings_inp); 36 | 37 | // 38 | 39 | void error_reporting(arma::vec& out_vals, const arma::vec& x_p, std::function opt_objfn, void* opt_data, 40 | bool& success, const double err, const double err_tol, const int iter, const int iter_max, const int conv_failure_switch, algo_settings_t* settings_inp); 41 | 42 | // 43 | 44 | #include "error_reporting.ipp" 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/misc/error_reporting.ipp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * Error reporting 23 | */ 24 | 25 | inline 26 | void 27 | error_reporting(arma::vec& out_vals, const arma::vec& x_p, std::function opt_objfn, void* opt_data, 28 | bool& success, const double err, const double err_tol, const int iter, const int iter_max, const int conv_failure_switch, algo_settings_t* settings_inp) 29 | { 30 | success = false; 31 | 32 | if (conv_failure_switch == 0) { 33 | out_vals = x_p; 34 | 35 | if (err <= err_tol && iter <= iter_max) { 36 | success = true; 37 | } 38 | } else if (conv_failure_switch == 1) { 39 | out_vals = x_p; 40 | 41 | if (err <= err_tol && iter <= iter_max) { 42 | success = true; 43 | } else { 44 | Rprintf("optim failure: iter_max reached before convergence could be achieved.\n"); 45 | Rprintf("optim failure: returned best guess.\n"); 46 | 47 | Rcpp::Rcout << "iterations: " << iter << ". error: " << err << std::endl; 48 | } 49 | } else if (conv_failure_switch == 2) { 50 | if (err <= err_tol && iter <= iter_max) { 51 | out_vals = x_p; 52 | success = true; 53 | } else { 54 | Rprintf("optim failure: iter_max reached before convergence could be achieved.\n"); 55 | Rprintf("optim failure: best guess:\n"); 56 | 57 | // arma::cout << x_p.t() << arma::endl; 58 | Rcpp::Rcout << "iterations: " << iter << ". error: " << err << std::endl; 59 | } 60 | } else { 61 | Rprintf("optim failure: unrecognized conv_failure_switch value.\n"); 62 | success = false; 63 | } 64 | // 65 | if (settings_inp) { 66 | settings_inp->opt_value = opt_objfn(x_p,nullptr,opt_data); 67 | settings_inp->opt_iter = iter; 68 | settings_inp->opt_err = err; 69 | } 70 | } 71 | 72 | inline 73 | void 74 | error_reporting(arma::vec& out_vals, const arma::vec& x_p, std::function opt_objfn, void* opt_data, 75 | bool& success, const int conv_failure_switch, algo_settings_t* settings_inp) 76 | { 77 | if (conv_failure_switch == 0 || conv_failure_switch == 1) { 78 | out_vals = x_p; 79 | } else if (conv_failure_switch == 2) { 80 | if (success) { 81 | out_vals = x_p; 82 | } 83 | } else { 84 | Rprintf("optim failure: unrecognized conv_failure_switch value.\n"); 85 | success = false; 86 | } 87 | // 88 | if (settings_inp) { 89 | settings_inp->opt_value = opt_objfn(x_p,nullptr,opt_data); 90 | } 91 | } 92 | 93 | inline 94 | void 95 | error_reporting(arma::vec& out_vals, const arma::vec& x_p, std::function opt_objfn, void* opt_data, 96 | bool& success, const double err, const double err_tol, const int iter, const int iter_max, const int conv_failure_switch, algo_settings_t* settings_inp) 97 | { 98 | success = false; 99 | 100 | if (conv_failure_switch == 0) { 101 | out_vals = x_p; 102 | 103 | if (err <= err_tol && iter <= iter_max) { 104 | success = true; 105 | } 106 | } else if (conv_failure_switch == 1) { 107 | out_vals = x_p; 108 | 109 | if (err <= err_tol && iter <= iter_max) { 110 | success = true; 111 | } else { 112 | Rprintf("optim failure: iter_max reached before convergence could be achieved.\n"); 113 | Rprintf("optim failure: returned best guess.\n"); 114 | 115 | Rcpp::Rcout << "error: " << err << std::endl; 116 | } 117 | } else if (conv_failure_switch == 2) { 118 | if (err <= err_tol && iter <= iter_max) { 119 | out_vals = x_p; 120 | success = true; 121 | } else { 122 | Rprintf("optim failure: iter_max reached before convergence could be achieved.\n"); 123 | Rprintf("optim failure: best guess:\n"); 124 | 125 | // arma::cout << x_p.t() << arma::endl; 126 | Rcpp::Rcout << "error: " << err << std::endl; 127 | } 128 | } else { 129 | Rprintf("optim failure: unrecognized conv_failure_switch value.\n"); 130 | success = false; 131 | } 132 | // 133 | if (settings_inp) { 134 | settings_inp->zero_values = opt_objfn(x_p,opt_data); 135 | settings_inp->opt_iter = iter; 136 | settings_inp->opt_err = err; 137 | } 138 | } 139 | 140 | // 141 | 142 | inline 143 | void 144 | error_reporting(arma::vec& out_vals, const arma::vec& x_p, std::function opt_objfn, void* opt_data, 145 | bool& success, const double err, const double err_tol, const int iter, const int iter_max, const int conv_failure_switch, algo_settings_t* settings_inp) 146 | { 147 | std::function lam_objfn = [opt_objfn] (const arma::vec& vals_inp, arma::vec* grad_out, void* opt_data) 148 | -> double 149 | { 150 | return opt_objfn(vals_inp,grad_out,nullptr,opt_data); 151 | }; 152 | 153 | // 154 | 155 | error_reporting(out_vals,x_p,lam_objfn,opt_data,success,err,err_tol,iter,iter_max,conv_failure_switch,settings_inp); 156 | } -------------------------------------------------------------------------------- /src/misc/jacobian_adjust.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * Jacobian adjustment 23 | */ 24 | 25 | inline 26 | arma::mat 27 | jacobian_adjust(const arma::vec& vals_trans_inp, const arma::uvec& bounds_type, const arma::vec& lower_bounds, const arma::vec& upper_bounds) 28 | { 29 | const size_t n_vals = bounds_type.n_elem; 30 | 31 | arma::mat ret_mat = arma::eye(n_vals,n_vals); 32 | 33 | for (size_t i=0; i < n_vals; i++) 34 | { 35 | switch (bounds_type(i)) 36 | { 37 | case 2: // lower bound only 38 | ret_mat(i,i) = std::exp(vals_trans_inp(i)); 39 | break; 40 | case 3: // upper bound only 41 | ret_mat(i,i) = std::exp(-vals_trans_inp(i)); 42 | break; 43 | case 4: // upper and lower bounds 44 | ret_mat(i,i) = std::exp(vals_trans_inp(i))*(upper_bounds(i) - lower_bounds(i)) / std::pow(std::exp(vals_trans_inp(i)) + 1,2); 45 | break; 46 | } 47 | } 48 | // 49 | return ret_mat; 50 | } 51 | -------------------------------------------------------------------------------- /src/misc/misc.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | #include "determine_bounds_type.hpp" 22 | #include "error_reporting.hpp" 23 | #include "jacobian_adjust.hpp" 24 | #include "numerical_gradient.hpp" 25 | #include "numerical_hessian.hpp" 26 | #include "transform_vals.hpp" 27 | #include "unit_vec.hpp" 28 | -------------------------------------------------------------------------------- /src/misc/numerical_gradient.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * Numerical Gradient, using Abramowitz and Stegun (1972, p. 883, 25.3.21) 23 | */ 24 | 25 | inline 26 | arma::vec 27 | numerical_gradient(const arma::vec& vals_inp, const double* step_size_inp, std::function objfn, void* objfn_data) 28 | { 29 | const size_t n_vals = vals_inp.n_elem; 30 | 31 | const double step_size = (step_size_inp) ? *step_size_inp : 1e-04; 32 | const double mach_eps = std::numeric_limits::epsilon(); 33 | 34 | const arma::vec step_vec = arma::max(arma::abs(vals_inp), std::sqrt(step_size)*arma::ones(n_vals,1)) * std::pow(mach_eps,1.0/6.0); 35 | 36 | arma::vec x_orig = vals_inp, x_term_1, x_term_2; 37 | arma::vec grad_vec = arma::zeros(n_vals,1); 38 | 39 | // 40 | 41 | for (size_t i=0; i < n_vals; i++) 42 | { 43 | x_term_1 = x_orig; 44 | x_term_2 = x_orig; 45 | 46 | x_term_1(i) += step_vec(i); 47 | x_term_2(i) -= step_vec(i); 48 | 49 | 50 | // 51 | 52 | double term_1 = objfn(x_term_1, nullptr, objfn_data); 53 | double term_2 = -objfn(x_term_2, nullptr, objfn_data); 54 | 55 | double denom_term = 2.0 * step_vec(i); 56 | 57 | grad_vec(i) = (term_1 + term_2) / denom_term; 58 | } 59 | 60 | // 61 | 62 | return grad_vec; 63 | } 64 | -------------------------------------------------------------------------------- /src/misc/numerical_hessian.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * Numerical Hessian, using Abramowitz and Stegun (1972, p. 884, 25.3.24 and 25.3.26) 23 | */ 24 | 25 | inline 26 | arma::mat 27 | numerical_hessian(const arma::vec& vals_inp, const double* step_size_inp, std::function objfn, void* objfn_data) 28 | { 29 | const size_t n_vals = vals_inp.n_elem; 30 | 31 | const double step_size = (step_size_inp) ? *step_size_inp : 1e-04; 32 | const double mach_eps = std::numeric_limits::epsilon(); 33 | 34 | const arma::vec step_vec = arma::max(arma::abs(vals_inp), std::sqrt(step_size)*arma::ones(n_vals,1)) * std::pow(mach_eps,1.0/6.0); 35 | 36 | arma::vec x_orig = vals_inp, x_term_1, x_term_2, x_term_3, x_term_4; 37 | arma::mat hessian_mat = arma::zeros(n_vals,n_vals); 38 | 39 | const double f_orig = -30.0*objfn(x_orig, nullptr, objfn_data); 40 | 41 | // 42 | 43 | for (size_t i=0; i < n_vals; i++) 44 | { 45 | for (size_t j=i; j < n_vals; j++) 46 | { 47 | x_term_1 = x_orig; 48 | x_term_2 = x_orig; 49 | x_term_3 = x_orig; 50 | x_term_4 = x_orig; 51 | 52 | if (i==j) 53 | { 54 | x_term_1(i) += 2*step_vec(i); 55 | x_term_2(i) += step_vec(i); 56 | x_term_3(i) -= step_vec(i); 57 | x_term_4(i) -= 2*step_vec(i); 58 | 59 | // 60 | 61 | double term_1 = - objfn(x_term_1, nullptr, objfn_data); 62 | double term_2 = 16.0*objfn(x_term_2, nullptr, objfn_data); 63 | double term_3 = 16.0*objfn(x_term_3, nullptr, objfn_data); 64 | double term_4 = - objfn(x_term_4, nullptr, objfn_data); 65 | 66 | double denom_term = 12.0 * step_vec(i) * step_vec(i); 67 | 68 | hessian_mat(i,j) = (term_1 + term_2 + f_orig + term_3 + term_4) / denom_term; 69 | } 70 | else 71 | { 72 | x_term_1(i) += step_vec(i); 73 | x_term_1(j) += step_vec(j); 74 | 75 | x_term_2(i) += step_vec(i); 76 | x_term_2(j) -= step_vec(j); 77 | 78 | x_term_3(i) -= step_vec(i); 79 | x_term_3(j) += step_vec(j); 80 | 81 | x_term_4(i) -= step_vec(i); 82 | x_term_4(j) -= step_vec(j); 83 | 84 | // 85 | 86 | double term_1 = objfn(x_term_1, nullptr, objfn_data); 87 | double term_2 = -objfn(x_term_2, nullptr, objfn_data); 88 | double term_3 = -objfn(x_term_3, nullptr, objfn_data); 89 | double term_4 = objfn(x_term_4, nullptr, objfn_data); 90 | 91 | double denom_term = 4.0 * step_vec(i) * step_vec(j); 92 | 93 | hessian_mat(i,j) = (term_1 + term_2 + term_3 + term_4) / denom_term; 94 | hessian_mat(j,i) = hessian_mat(i,j); 95 | } 96 | } 97 | } 98 | 99 | // 100 | 101 | return hessian_mat; 102 | } 103 | -------------------------------------------------------------------------------- /src/misc/optim_options.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | #pragma once 22 | 23 | // version 24 | 25 | #ifndef OPTIM_VERSION_MAJOR 26 | #define OPTIM_VERSION_MAJOR 1 27 | #endif 28 | 29 | #ifndef OPTIM_VERSION_MINOR 30 | #define OPTIM_VERSION_MINOR 2 31 | #endif 32 | 33 | #ifndef OPTIM_VERSION_PATCH 34 | #define OPTIM_VERSION_PATCH 0 35 | #endif 36 | 37 | // 38 | 39 | #if defined(_OPENMP) && !defined(OPTIM_DONT_USE_OPENMP) 40 | #undef OPTIM_USE_OPENMP 41 | #define OPTIM_USE_OPENMP 42 | #endif 43 | 44 | #if !defined(_OPENMP) && defined(OPTIM_USE_OPENMP) 45 | #undef OPTIM_USE_OPENMP 46 | 47 | #undef OPTIM_DONE_USE_OPENMP 48 | #define OPTIM_DONE_USE_OPENMP 49 | #endif 50 | 51 | #ifdef OPTIM_USE_OPENMP 52 | // #include "omp.h" // OpenMP 53 | #ifndef ARMA_USE_OPENMP 54 | #define ARMA_USE_OPENMP 55 | #endif 56 | #endif 57 | 58 | #ifdef OPTIM_DONT_USE_OPENMP 59 | #ifdef OPTIM_USE_OPENMP 60 | #undef OPTIM_USE_OPENMP 61 | #endif 62 | 63 | #ifndef ARMA_DONT_USE_OPENMP 64 | #define ARMA_DONT_USE_OPENMP 65 | #endif 66 | #endif 67 | 68 | // 69 | 70 | #ifdef USE_RCPP_ARMADILLO 71 | #include 72 | #else 73 | #ifndef ARMA_DONT_USE_WRAPPER 74 | #define ARMA_DONT_USE_WRAPPER 75 | #endif 76 | #include "armadillo" 77 | #endif 78 | 79 | #ifndef optimlib_inline 80 | #define optimlib_inline 81 | #endif 82 | 83 | namespace optim 84 | { 85 | static const double eps_dbl = std::numeric_limits::epsilon(); 86 | static const double inf = std::numeric_limits::infinity(); 87 | using uint_t = unsigned int; 88 | } 89 | -------------------------------------------------------------------------------- /src/misc/optim_structs.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * Optimization control parameters 23 | */ 24 | 25 | #ifndef optim_structs_HPP 26 | #define optim_structs_HPP 27 | 28 | struct gd_settings_t 29 | { 30 | // step size, or 'learning rate' 31 | double step_size = 0.1; 32 | 33 | // decay 34 | bool step_decay = false; 35 | 36 | uint_t step_decay_periods = 10; 37 | double step_decay_val = 0.5; 38 | 39 | // momentum parameter 40 | double momentum_par = 0.9; 41 | 42 | // Ada parameters 43 | double norm_term = 10e-08; 44 | 45 | double ada_rho = 0.9; 46 | 47 | bool ada_max = false; 48 | 49 | // Adam parameters 50 | double adam_beta_1 = 0.9; 51 | double adam_beta_2 = 0.999; 52 | }; 53 | 54 | struct algo_settings_t 55 | { 56 | // general 57 | int verbose_print_level = 0; 58 | int conv_failure_switch = 0; 59 | int iter_max = 2000; 60 | double err_tol = 1E-08; 61 | 62 | bool vals_bound = false; 63 | 64 | arma::vec lower_bounds; 65 | arma::vec upper_bounds; 66 | 67 | // returned by algorithms 68 | double opt_value; // will be returned by the optimization algorithm 69 | arma::vec zero_values; // will be returned by the root-finding method 70 | 71 | int opt_iter; 72 | double opt_err; 73 | 74 | // SUMT parameter 75 | double sumt_par_eta = 10.0; 76 | 77 | // CG 78 | int cg_method = 2; 79 | double cg_restart_threshold = 0.1; 80 | 81 | // DE 82 | int de_n_pop = 200; 83 | int de_n_pop_best = 6; 84 | int de_n_gen = 1000; 85 | 86 | int de_pmax = 4; 87 | int de_max_fn_eval = 100000; 88 | 89 | int de_mutation_method = 1; // 1 = rand; 2 = best 90 | 91 | int de_check_freq = -1; 92 | 93 | double de_par_F = 0.8; 94 | double de_par_CR = 0.9; 95 | 96 | double de_par_F_l = 0.1; 97 | double de_par_F_u = 1.0; 98 | 99 | double de_par_tau_F = 0.1; 100 | double de_par_tau_CR = 0.1; 101 | 102 | arma::vec de_initial_lb; // this will default to -0.5 103 | arma::vec de_initial_ub; // this will default to 0.5 104 | 105 | // GD 106 | int gd_method = 0; 107 | gd_settings_t gd_settings; 108 | 109 | // L-BFGS 110 | int lbfgs_par_M = 10; 111 | 112 | // Nelder-Mead 113 | bool nm_adaptive= true; 114 | 115 | double nm_par_alpha = 1.0; // reflection parameter 116 | double nm_par_beta = 0.5; // contraction parameter 117 | double nm_par_gamma = 2.0; // expansion parameter 118 | double nm_par_delta = 0.5; // shrinkage parameter 119 | 120 | // PSO 121 | bool pso_center_particle = true; 122 | 123 | int pso_n_pop = 100; 124 | int pso_n_gen = 1000; 125 | 126 | int pso_inertia_method = 1; // 1 for linear decreasing between w_min and w_max; 2 for dampening 127 | 128 | int pso_check_freq = -1; 129 | 130 | double pso_par_initial_w = 1.0; 131 | double pso_par_w_damp = 0.99; 132 | 133 | double pso_par_w_min = 0.10; 134 | double pso_par_w_max = 0.99; 135 | 136 | int pso_velocity_method = 1; // 1 for fixed; 2 for linear 137 | 138 | double pso_par_c_cog = 2.0; 139 | double pso_par_c_soc = 2.0; 140 | 141 | double pso_par_initial_c_cog = 2.5; 142 | double pso_par_final_c_cog = 0.5; 143 | double pso_par_initial_c_soc = 0.5; 144 | double pso_par_final_c_soc = 2.5; 145 | 146 | arma::vec pso_initial_lb; // this will default to -0.5 147 | arma::vec pso_initial_ub; // this will default to 0.5 148 | }; 149 | 150 | #endif 151 | -------------------------------------------------------------------------------- /src/misc/transform_vals.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * transform values 23 | */ 24 | 25 | inline 26 | arma::vec 27 | transform(const arma::vec& vals_inp, const arma::uvec& bounds_type, const arma::vec& lower_bounds, const arma::vec& upper_bounds) 28 | { 29 | const size_t n_vals = bounds_type.n_elem; 30 | 31 | arma::vec vals_trans_out(n_vals); 32 | 33 | for (size_t i=0; i < n_vals; i++) 34 | { 35 | switch (bounds_type(i)) 36 | { 37 | case 1: // no bounds 38 | vals_trans_out(i) = vals_inp(i); 39 | break; 40 | case 2: // lower bound only 41 | vals_trans_out(i) = std::log(vals_inp(i) - lower_bounds(i) + eps_dbl); 42 | break; 43 | case 3: // upper bound only 44 | vals_trans_out(i) = - std::log(upper_bounds(i) - vals_inp(i) + eps_dbl); 45 | break; 46 | case 4: // upper and lower bounds 47 | vals_trans_out(i) = std::log(vals_inp(i) - lower_bounds(i) + eps_dbl) - std::log(upper_bounds(i) - vals_inp(i) + eps_dbl); 48 | break; 49 | } 50 | } 51 | 52 | // 53 | 54 | return vals_trans_out; 55 | } 56 | 57 | inline 58 | arma::vec 59 | inv_transform(const arma::vec& vals_trans_inp, const arma::uvec& bounds_type, const arma::vec& lower_bounds, const arma::vec& upper_bounds) 60 | { 61 | const size_t n_vals = bounds_type.n_elem; 62 | 63 | arma::vec vals_out(n_vals); 64 | 65 | for (size_t i=0; i < n_vals; i++) 66 | { 67 | switch (bounds_type(i)) 68 | { 69 | case 1: // no bounds 70 | vals_out(i) = vals_trans_inp(i); 71 | break; 72 | case 2: // lower bound only 73 | if (!std::isfinite(vals_trans_inp(i))) 74 | { 75 | vals_out(i) = lower_bounds(i) + eps_dbl; 76 | } 77 | else 78 | { 79 | vals_out(i) = lower_bounds(i) + eps_dbl + std::exp(vals_trans_inp(i)); 80 | } 81 | break; 82 | case 3: // upper bound only 83 | if (!std::isfinite(vals_trans_inp(i))) 84 | { 85 | vals_out(i) = upper_bounds(i) - eps_dbl; 86 | } 87 | else 88 | { 89 | vals_out(i) = upper_bounds(i) - eps_dbl - std::exp(-vals_trans_inp(i)); 90 | } 91 | break; 92 | case 4: // upper and lower bounds 93 | if (!std::isfinite(vals_trans_inp(i))) 94 | { 95 | if (std::isnan(vals_trans_inp(i))) 96 | { 97 | vals_out(i) = (upper_bounds(i) - lower_bounds(i)) / 2.0; 98 | } 99 | else if (vals_trans_inp(i) < 0.0) 100 | { 101 | vals_out(i) = lower_bounds(i) + eps_dbl; 102 | } 103 | else 104 | { 105 | vals_out(i) = upper_bounds(i) - eps_dbl; 106 | } 107 | } 108 | else 109 | { 110 | vals_out(i) = ( lower_bounds(i) + eps_dbl + (upper_bounds(i) - eps_dbl)*std::exp(vals_trans_inp(i)) ) \ 111 | / ( 1.0 + std::exp(vals_trans_inp(i)) ); 112 | 113 | if (!std::isfinite(vals_out(i))) 114 | { 115 | vals_out(i) = upper_bounds(i) - eps_dbl; 116 | } 117 | } 118 | break; 119 | } 120 | } 121 | 122 | // 123 | 124 | return vals_out; 125 | } 126 | -------------------------------------------------------------------------------- /src/misc/unit_vec.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * unit vector 23 | */ 24 | 25 | #ifndef _optim_unit_vec_HPP 26 | #define _optim_unit_vec_HPP 27 | 28 | inline arma::vec unit_vec(const size_t j, const size_t n); 29 | 30 | #include "unit_vec.ipp" 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/misc/unit_vec.ipp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * unit vector 23 | */ 24 | 25 | inline 26 | arma::vec 27 | unit_vec(const size_t j, const size_t n) 28 | { 29 | arma::vec ret = arma::zeros(n,1); 30 | ret(j) = 1; 31 | 32 | return ret; 33 | } 34 | -------------------------------------------------------------------------------- /src/optim.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | #ifndef OPTIMLIB_INCLUDES 22 | #define OPTIMLIB_INCLUDES 23 | 24 | #include "misc/optim_options.hpp" 25 | 26 | namespace optim 27 | { 28 | // structs 29 | #include "misc/optim_structs.hpp" 30 | 31 | // misc files 32 | #include "misc/misc.hpp" 33 | 34 | // line search 35 | #include "line_search/more_thuente.hpp" 36 | 37 | // unconstrained optimization 38 | #include "unconstrained/bfgs.hpp" 39 | #include "unconstrained/lbfgs.hpp" 40 | #include "unconstrained/newton.hpp" 41 | #include "unconstrained/cg.hpp" 42 | #include "unconstrained/gd.hpp" 43 | #include "unconstrained/de.hpp" 44 | #include "unconstrained/de_prmm.hpp" 45 | #include "unconstrained/nm.hpp" 46 | #include "unconstrained/pso.hpp" 47 | #include "unconstrained/pso_dv.hpp" 48 | 49 | // constrained optimization 50 | #include "constrained/sumt.hpp" 51 | 52 | // solving systems of nonlinear equations 53 | #include "zeros/broyden.hpp" 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/unconstrained/newton.hpp: -------------------------------------------------------------------------------- 1 | /*################################################################################ 2 | ## 3 | ## Copyright (C) 2016-2018 Keith O'Hara 4 | ## 5 | ## This file is part of the OptimLib C++ library. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ## 19 | ################################################################################*/ 20 | 21 | /* 22 | * Newton's method for non-linear optimization 23 | */ 24 | 25 | #ifndef _optim_newton_HPP 26 | #define _optim_newton_HPP 27 | 28 | bool newton_int(arma::vec& init_out_vals, std::function opt_objfn, void* opt_data, algo_settings_t* settings_inp); 29 | 30 | bool newton(arma::vec& init_out_vals, std::function opt_objfn, void* opt_data); 31 | bool newton(arma::vec& init_out_vals, std::function opt_objfn, void* opt_data, algo_settings_t& settings); 32 | 33 | // 34 | 35 | inline 36 | bool 37 | newton_int(arma::vec& init_out_vals, std::function opt_objfn, void* opt_data, algo_settings_t* settings_inp) 38 | { 39 | // notation: 'p' stands for '+1'. 40 | 41 | bool success = false; 42 | 43 | const size_t n_vals = init_out_vals.n_elem; 44 | 45 | // 46 | // Newton settings 47 | 48 | algo_settings_t settings; 49 | 50 | if (settings_inp) 51 | { 52 | settings = *settings_inp; 53 | } 54 | 55 | const uint_t conv_failure_switch = settings.conv_failure_switch; 56 | const uint_t iter_max = settings.iter_max; 57 | const double err_tol = settings.err_tol; 58 | 59 | // 60 | // initialization 61 | 62 | arma::vec x = init_out_vals; 63 | 64 | if (!x.is_finite()) 65 | { 66 | Rprintf("newton error: non-finite initial value(s).\n"); 67 | return false; 68 | } 69 | 70 | arma::mat H(n_vals,n_vals); // hessian matrix 71 | arma::vec grad(n_vals); // gradient vector 72 | opt_objfn(x,&grad,&H,opt_data); 73 | 74 | double err = arma::norm(grad, 2); 75 | if (err <= err_tol) { 76 | return true; 77 | } 78 | 79 | // 80 | // if ||gradient(initial values)|| > tolerance, then continue 81 | 82 | arma::vec d = - arma::solve(H,grad); // Newton direction 83 | 84 | arma::vec x_p = x + d; // no line search used here 85 | 86 | opt_objfn(x_p,&grad,&H,opt_data); 87 | 88 | err = arma::norm(grad, 2); 89 | if (err <= err_tol) 90 | { 91 | init_out_vals = x_p; 92 | return true; 93 | } 94 | 95 | // 96 | // begin loop 97 | 98 | uint_t iter = 0; 99 | 100 | while (err > err_tol && iter < iter_max) 101 | { 102 | iter++; 103 | 104 | // 105 | 106 | d = - arma::solve(H,grad); 107 | x_p = x + d; 108 | 109 | opt_objfn(x_p,&grad,&H,opt_data); 110 | 111 | // 112 | 113 | err = arma::norm(grad, 2); 114 | if (err <= err_tol) { 115 | break; 116 | } 117 | 118 | err = arma::norm(x_p - x, 2); 119 | 120 | // 121 | 122 | x = x_p; 123 | } 124 | 125 | // 126 | 127 | error_reporting(init_out_vals,x_p,opt_objfn,opt_data,success,err,err_tol,iter,iter_max,conv_failure_switch,settings_inp); 128 | 129 | return success; 130 | } 131 | 132 | inline 133 | bool 134 | newton(arma::vec& init_out_vals, std::function opt_objfn, void* opt_data) 135 | { 136 | return newton_int(init_out_vals,opt_objfn,opt_data,nullptr); 137 | } 138 | 139 | inline 140 | bool 141 | newton(arma::vec& init_out_vals, std::function opt_objfn, void* opt_data, algo_settings_t& settings) 142 | { 143 | return newton_int(init_out_vals,opt_objfn,opt_data,&settings); 144 | } 145 | 146 | #endif 147 | -------------------------------------------------------------------------------- /src/utils.hpp: -------------------------------------------------------------------------------- 1 | // =============================================================================== 2 | // 3 | // Developers: 4 | // 5 | // Tiago de Conto - tdc.florestal@gmail.com - https://github.com/tiagodc/ 6 | // 7 | // COPYRIGHT: Tiago de Conto, 2020 8 | // 9 | // This piece of software is open and free to use, redistribution and modifications 10 | // should be done in accordance to the GNU General Public License >= 3 11 | // 12 | // Use this software as you wish, but no warranty is provided whatsoever. For any 13 | // comments or questions on TreeLS, please contact the developer (prefereably through my github account) 14 | // 15 | // If publishing any work/study/research that used the tools in TreeLS, 16 | // please don't forget to cite the proper sources! 17 | // 18 | // Enjoy! 19 | // 20 | // =============================================================================== 21 | 22 | #ifndef UTILS_HPP 23 | #define UTILS_HPP 24 | 25 | #include "classes.hpp" 26 | using namespace Rcpp; 27 | 28 | void bringOrigin(vector >& las); 29 | 30 | vector > cropCloud(vector > cloud, double xCenter, double yCenter, double len = 1, bool circle = true, bool negative = false); 31 | 32 | vector cropCloudFilter(vector > cloud, double xCenter, double yCenter, double len = 1, bool circle = true, bool negative = false); 33 | 34 | vector > > getChunks(vector >& cloud, vector& identifier); 35 | 36 | vector > > getFullChunks(vector >& cloud, vector& identifier); 37 | 38 | vector getMinMax(vector >& xyz); 39 | 40 | vector > > getSlices(vector >& cloud, double zmin = 1, double zmax=3, double zstep = 0.5); 41 | 42 | vector > > getSlices(NumericMatrix& cloud, double zmin = 1, double zmax=3, double zstep = 0.5); 43 | 44 | vector idSortUnique(vector& identifier, vector& values); 45 | 46 | vector idSortUnique(vector& identifier, vector& values); 47 | 48 | double mad(vector x, double c = 1.4826); 49 | 50 | double median(vector x); 51 | 52 | double variance(vector& x); 53 | 54 | vector > partitionIndex(vector& identifier, vector& partitioner); 55 | 56 | vector > partitionIndex(vector& identifier, vector& partitioner); 57 | 58 | vector > randomPoints(vector >& cloud, double p = 0.5); 59 | 60 | vector > rmatrix2cpp(NumericMatrix& cloud); 61 | 62 | void tukeyBiSq(vector& werrors, double b = 5); 63 | 64 | vector voxelFilter(vector >& cloud, double voxel_spacing = 0.025); 65 | 66 | vector xprod(vector& a, vector& b); 67 | 68 | void eigenDecomposition(vector >& cloud, vector* eiVals, vector >* eiVecs); 69 | 70 | vector pointDistances(vector >& cloud); 71 | 72 | vector nnMetrics(vector >& xyz, vector which); 73 | 74 | vector > intmatrix2cpp(NumericMatrix& idxMatrix); 75 | 76 | double vecAngle(vector& a, vector& b); 77 | 78 | vector > voxelCounter(vector >& xyzNormals, double voxel, double max_rad, bool is2d = false, bool sendSpace = false); 79 | 80 | vector > splitVector(vector& to_split, vector& split_by); 81 | 82 | vector > fastApply(vector >& matrix, vector& funcList); 83 | 84 | vector sortIndexes(vector& values); 85 | 86 | unsigned int uniqueTotalCounter(vector input); 87 | 88 | void progressPrinter(string units, unsigned int n, unsigned int total); 89 | 90 | #endif // UTILS_HPP 91 | -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | // [[Rcpp::export]] 10 | void unique_vec(){ 11 | vector uq = {1,2,3,4,5,1,2,3,4,5,6,6,6,1,1}; 12 | unordered_set uqs(uq.begin(), uq.end()); 13 | cout << uq.size() << " : " << uqs.size() << endl; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /tests.R: -------------------------------------------------------------------------------- 1 | Rcpp::sourceCpp('src/r_interface.cpp', rebuild = T) 2 | source('R/sample_methods.R') 3 | source('R/map_methods.R') 4 | source('R/stem_points_methods.R') 5 | source('R/stem_segmentation_methods.R') 6 | source('R/tree_points_methods.R') 7 | source('R/point_metrics_methods.R') 8 | source('R/plot_extras.R') 9 | source('R/methods.R') 10 | 11 | require(magrittr) 12 | require(lidR) 13 | require(rgl) 14 | require(data.table) 15 | require(dismo) 16 | require(deldir) 17 | require(nabor) 18 | require(benchmarkme) 19 | require(glue) 20 | 21 | rm(list = c('X','Y','Z','Classification','TreePosition','TreeID','Stem','Segment','gpstime','AvgHeight','Radius','N','Curvature','Verticality','MeanDist','PX','PY','PZ','h_radius','PointID','VoxelID','StemID','EigenVector13','EigenVector23','EigenVector33','Votes','absRatio','clt','r','v','x','y')) 22 | 23 | ################### 24 | # require(TreeLS) 25 | --------------------------------------------------------------------------------