Airborne LiDAR Data Manipulation and Visualization for Forestry Applications

Airborne LiDAR (Light Detection and Ranging) interface for data manipulation and visualization. Read/write 'las' and 'laz' files, computation of metrics in area based approach, point filtering, artificial point reduction, classification from geographic data, normalization, individual tree segmentation and other manipulations.

CRAN Github licence

R package for Airborne LiDAR Data Manipulation and Visualization for Forestry Applications

The lidR package provides functions to read and write .las and .laz files, plot point clouds, compute metrics using an area-based approach, compute digital canopy models, thin lidar data, manage a catalog of datasets, automatically extract ground inventories, process a set of tiles using multicore processing, individual tree segmentation, classify data from geographic data, and provides other tools to manipulate LiDAR data in a research and development context.

Development of the lidR package between 2015 and 2018 was made possible thanks to the financial support of the AWARE project (NSERC CRDPJ 462973-14); grantee Prof Nicholas Coops.

  1. Key features
  2. Some examples
  3. Install lidR
  4. Changelog

Key features

Some examples

Read and display a las file

In R-fashion style the function plot, based on rgl, enables the user to display, rotate and zoom a point cloud. Because rgl has limited capabilities with respect to large datasets, we also made a package PointCloudViewer with greater display capabilites.

las = readLAS("<file.las>")

Compute a canopy height model

lidR has several algorithms from the literature to compute canopy height models either point-to-raster based (grid_canopy) or triangulation based (grid_tincanopy). This allows testing and comparison of some methods that rely on a CHM, such as individual tree segmentation or the computation of a canopy roughness index.

las = readLAS("<file.las>")
# Khosravipour et al. pitfree algorithm
th = c(0,2,5,10,15)
edge = c(0, 1.5)
chm = grid_tincanopy(las, thresholds = th, max_edge = edge)

Read and display a catalog of las files

lidR enables the user to manage, use and process a catalog of las files. The function catalog builds a LAScatalog object from a folder. The function plot displays this catalog on an interactive map using the mapview package.

ctg = catalog("<folder/>")
[email protected] = sp::CRS("+proj=utm +zone=17")
# CRS set: will be displayed on an interactive map

From a LAScatalog object the user can (for example) extract some regions of interest (ROI) with lasclip or catalog_queries. Using a catalog for the extraction of the ROI guarantees fast and memory-efficient clipping. LAScatalog objects allow many other manipulations that are usually done with multicore processing, where possible.

Individual tree segmentation

The lastrees function has several algorithms from the literature for individual tree segmentation, based either on the digital canopy model or on the point-cloud. Each algorithm has been coded from the source article to be as close as possible to what was written in the peer-reviwed papers. Our goal is to make published algorithms usable, testable and comparable.

las = readLAS("<file.las>")
lastrees(las, algorithm = "li2012")
col = random.colors(200)
plot(las, color = "treeID", colorPalette = col)

Other tools

lidR has many other tools and is a continuouly improved package. If it does not exist in lidR please ask us for a new feature, and depending on the feasability we will be glad to implement your requested feature.

Install lidR

  • The latest released version from CRAN with
  • The latest stable development version from github with
devtools::install_github("Jean-Romain/rlas", dependencies=TRUE)
devtools::install_github("Jean-Romain/lidR", dependencies=TRUE)
  • The latest unstable development version from github with
devtools::install_github("Jean-Romain/rlas", dependencies=TRUE, ref="devel")
devtools::install_github("Jean-Romain/lidR", dependencies=TRUE, ref="devel")

To install the package from github make sure you have a working development environment.

  • Windows: Install Rtools.exe.
  • Mac: Install Xcode from the Mac App Store.
  • Linux: Install the R development package, usually called r-devel or r-base-dev
  • The latest stable development version from github with


See changelogs on


lidR v1.6.1 (2018-08-21)


  • [#161] Fix tree ID matching.
  • Fix undefined variable in cluster_apply on mac and linux if multicore processing is used.
  • Fix rare case of unit test failure due to the random nature of the test dataset using seeds.
  • [#165] Unexported function in catalog_apply on Windows.

lidR v1.6.0 (2018-07-20)


  • New function tree_hulls that computes a convex or concave hull for each segmented tree.
  • New option stop_early that enables processing of an entire catolog or stops if an error occurs.
  • New function catalog_retile supersedes the function catalog_reshape and performs the same task while adding much more functionality.


  • When processing a LAScatalog, error handling has been seriouly improved. A process can now run until the end even with errors. In this case clusters with errors are skipped.
  • When processing a LAScatalog, the graphical progress now uses 3 colors. green: ok, red: error, gray: null.
  • as.spatial() for LAS object preserves the CRS.
  • All the functions now have strong assertions to check user inputs.
  • plot.LAScatalog always displays the catalog with mapview by default even if the CRS is empty.
  • In lastrees_dalponte the matching between the seeds and the canopy is more tolerant. Rasters can have different resolution and/or extent.
  • lasground uses (as an option) only the last and single returns to perform the segmentation.


  • catalog() displays a message when finding overlaps between files.
  • The LAScatalog class is more thoroughly documented.
  • Clusters now align on (0,0) by default when processing a LAScatalog by cluster.


  • lasscanline() did not compute the scanline because the conditional statement that checked if the field was properly populated was incorrect.
  • [#146] Fix matching between tree tops, raster and canopy raster.
  • tree_detection when used with a point cloud was not properly coded and tended to miss some trees.
  • In lasclip* if ofile was non empty, the function wrote properly the file but returned a non-expected error.
  • [#155] user supplied function was being analysed by future and some function were missing. User supplied function is now manually analysed.
  • [#156] Fix error when lasclip was used with a SpatialPolygonDataFrame.

lidR v1.5.1 (2018-06-14)


  • The area of a LAScatalog was wrongly computed for non square tiles because of a bad copy/paste in the code.
  • [#135] Fix NULL class objects returned by grid_* functions when processing a LAScatalog if the first cluster is empty.
  • [#143] rumple_index returns NA if not computable.

lidR v1.5.0 (2018-05-13)


  • catalog_options() is formally deprecated. Use LAScatalog properties instead (see ?catalog).
  • The package magrittr is no longer loaded with lidR. Thus, piping operators are no longer usable by default. To use piping operators use library(magrittr).


  • New lassmooth function. A point cloud-based smoothing function.
  • New lasfiltersurfacepoints function to filter surface points.
  • New grid_catalog function is a simplified and more powerful function like catalog_apply but specifically dedicated to grid_* outputs.
  • New functions lasadddata, lasaddextrabyte and lasaddextrabyte_manual to add new data in a LAS object.
  • lasclip can clip a SpatialPolygonsDataFrame
  • lasclipRectangle and lasclipCircle can clip multiple selections (non-documented feature).
  • The treeID computed with lastrees_* functions can now be written in a las/laz file by default.


  • LAScatalog objects are processed with a single core by default.
  • lasdecimate is formally deprecated. Use lasfilterdecimate
  • grid_density now returns both the point and the pulse density, where possible.
  • The option P is no longer set by default in readLAS.
  • The documentation of lastrees has been split into several pages.
  • When a catalog is processed using several cores, if an error is raised the process triggers an early signal to stop the loop. In previous releases the entire process was run and the error was raised at the end when the futures were evaluated.


  • grid_metrics(lidar, stdmetrics_i(Intensity)) returned and empty data.table
  • [#128] Fix raster data extraction using the slower and memory-greedy, but safer raster::extract function.
  • [#126] propagate the CRS in filter functions.
  • [#116] Fix clash between function area from lidR and from raster.
  • [#110] Fix out-of-bounds rasterization.

lidR v1.4.2 (2018-04-19)


  • [#103] fix user-defined function not exported in clusters on Windows
  • [#104] fix potential bin exclusion in entropy function
  • [#106] fix wrong count of points below 0
  • Fix wrong type attribution in lasclassify when using the shapefile's table of attributes as data.
  • Fix column addition when field = NULL in lasclassify.
  • Fix NA return in entropy when negative value are found.


  • Li et al algorithm has a new parameter Zu (see reference) that is no longer hard coded.

lidR v1.4.1 (2018-02-01)


  • Removed examples and unit tests that imply the watershed segmentation to make CRAN check happy with the new rules relative to bioconductor packages.


  • Parameter start has been enabled in grid_metrics with catalogs.

lidR v1.4.0 (2018-01-24)


  • lasclip and lasclip* can extract from a catalog.
  • lasclip supports sp::Polygon objects.
  • lastrees gains a new algorithm from Silva et al. (2016).
  • lastrees with the Li et al. (2012) algorithm gains a new parameter to prevent over-segmentation.
  • new function lassnags for classifying points as snag points or for segmenting snags.
  • new function tree_detection to detect individual trees. This feature has been extracted from lastrees's algorithms and it is now up to the users to use lidR's algos or other input sources.
  • plot supports natively the PointCloudViewer package available on github.


  • Fix missing pixel in DTM that made normalization impossible.
  • [#80] fix segfault.
  • [#84] fix bug in lasscanline.


  • lastrees with the Li et al. (2012) algorithm is now 5-6 times faster and much more memory efficient.
  • lastrees with the Li et al. (2012) algorithm no longer sorts the original point cloud.
  • lastrees with the Dalponte et al (2016) algorithm is now computed in linear time and is therefore hundreds to millions times faster.
  • catalog_reshape() streams the data and uses virtually zero memory to run.
  • grid_canopy() has been rewritten entirely in C++ and is now 10 to 20 times faster both with the option subcircle or without it.
  • grid_canopy() with the option subcircle uses only 16 bytes of extra memory to run, while this feature previously required the equivalent of several copies of the point cloud (several hundreds of MB).
  • as.raster() is now three times faster.
  • lasclassify now uses a QuadTree and is therefore faster. This enables several algorithms to run faster, such as lastrees with Silva's algo.


  • lasground with the PMF algorithm now accepts user-defined sequences.
  • lasground with the PMF algorithm has simplified parameter names to make them easier to type and understand, and to prepare the package for new algorithms.
  • lasground documentation is more explicit about the actual algorithm used.
  • lasground now computes the windows size more closely in line with the original Zhang paper.
  • lastrees when used with raster-based methods now accepts a missing las object. In that case extra is turned to true.
  • new parameter p (for power) added to functions that enable spatial interpolation with IDW.

lidR v1.3.1 (Release date: 2017-09-20)


  • Fix a bug of computer precision leading to non interpolated pixels at the boundaries of the QuadTree.

lidR v1.3.0 (Release date: 2017-09-16)

This version is dedicated to extending functions and processes to entire catalogs in a continuous way. Major changes are:

  • How catalog_apply works. More powerful but no longer compatible with previous releases
  • Former existing functions that now natively support a Catalog
  • Management of buffered areas


  • catalog_apply has been entirely re-designed. It is more flexible, more user-friendly and enables loading of buffered data.
  • catalog_queries has now an argument ... to pass any argument of readLAS.
  • catalog_queries has now an argument buffer to load extra buffered points around the region of interest.
  • grid_metrics accepts a catalog as input. It allows users to grid an entire catalog in a continuous way.
  • grid_density also inherits this new feature
  • grid_terrain also inherits this new feature
  • grid_canopy also inherits this new feature
  • grid_tincanopy also inherits this new feature
  • grid_metrics has now has an argument filter for streaming filters when used with a catalog
  • New function catalog_reshape


  • lasnormalize updates the point cloud by reference and avoids making deep copies. An option copy = TRUE is available for compatibility with former versions.
  • readLAS arguments changed. The new syntax is simpler. The previous syntax is still supported.
  • catalog_index is no longer an exported function. It is now an internal function.
  • plot.Catalog accepts the usual plot arguments
  • catalog_queries and catalog_apply do not expect a parameter mc.cores. This is now driven by global options in catalog_options().
  • grid_metrics and lasmetrics do not expect a parameter debug. This is now driven by global options in lidr_options.
  • catalog can build a catalog from a set of paths to files instead of a path to a folder.
  • removed $ access to LAS attribute (incredibly slow)
  • catalog_select is more pleasant an more interactive to use.
  • S3 Catalog class is now a S4 LAScatalog class
  • LAS and LAScatalog class gain a slot crs automatically filled with a proj4 string
  • plot.LAScatalog display a google map background if the catalog has a CRS.
  • plot.LAScatalog gains an argument y to display a either a terrain, road, satellite map.
  • lasarea is deprecated. Use the more generic function area


  • Computer precision errors lead to holes in raster computed from a Delaunay triangulation.
  • Message in writeLAS for skipped fields when no field is skipped is now correct.


  • grid_terrain with delaunay allocates less memory, makes fewer deep copies and is 2 to 3 times faster
  • grid_terrain with knnidw allocates less memory, makes fewer deep copies and is 2 to 3 times faster
  • lasnormalize and lasclassify no longer rely on raster::extract but on internal fast_extract, which is memory efficient and more than 15 times faster.
  • catalog enables a LAScatalog to be built 8 times faster than previously.
  • removed dependencies to RANN package using internal k-nearest neighbor search (2 to 3 times faster)

lidR v1.2.1 (Release date: 2017-06-12)


  • new function tree_metrics.
  • new function stdtreemetrics.
  • grid_tincanopy() gains a parameter subcircle like grid_canopy()
  • new function rumple_index for measuring roughness of a digital model (terrain or canopy)
  • global options to parameterize the package - available with lidr_options()


  • Installation fails if package sp is missing.
  • Memory leak in QuadTree algorithm. Memory is now free after QuadTree deletion.
  • Dalponte's algorithm had a bug due to the use of std::abs which works with integers. Replaced by std::fabs which works with doubles.
  • In grid_tincanopy x > 0 was replaced by x >= 0 to avoid errors in the canopy height models
  • Triangle boundaries are now taken into account in the rasterization of the Delaunay triangulation


  • lastrees Li et al. algorithm for tree segmentation is now ten to a thousand of times faster than in v1.2.0
  • grid_terrain, the interpolation is now done only within the convex hull of the point cloud
  • grid_tincanopy makes the triangulation only for highest return per grid cell.
  • grid_tincanopy and grid_terrain using Delaunay triangulation is now ten to a hundred times faster than in v1.2.0
  • as.raster now relies on sp and is more flexible
  • as.raster automatically returns a RasterStack if no layer is provided.
  • plot.lasmetrics inherits as.raster changes and can display a RasterStack

lidR v1.2.0 (Release date: 2017-03-26)


  • new function lasground for ground segmentation.
  • new function grid_tincanopy. Canopy height model using Khosravipour et al. pit-free algorithm.
  • new function grid_hexametrics. Area-based approach in hexagonal cells.
  • lasnormalize allows for "non-discretized" normalization i.e interpolating each point instead of using a raster.
  • internally lascheck performs more tests to check if the header is in accordance with the data.


  • [#48] gap_fraction_profile() bug with negative values (thanks to Florian de Boissieu)
  • [#49] typo error leading to the wrong metric in stdmetric_i
  • [#50] typo error leading to the wrong metric in stdmetric
  • Fix bug in stdmetric_z when max(Z) = 0
  • [#54] better re-computation of the header of LAS objects.


  • Slightly faster point classification from shapefiles.
  • [#51] in grid_terrain, forcing the lowest point to be retained is now an option keep_lowest = FALSE

lidR v1.1.0 (Release date: 2017-02-05)


  • lastree() for individual tree segmentation
  • readLAS() gains a parameter filter from rlas (>= 1.1.0)
  • catalog_queries() relies on rlas (>= 1.1.0). It saves a lot of memory, is 2 to 6 times faster and supports .lax files.


  • colorPalette parameter in plot.LAS() now expects a list of colors instead of a function. Use height.colors(50) instead of height.colors
  • The header of a LAS object is now an S4 class object called LASheader
  • The spatial interpolation method akima is now called delaunay because it corresponds to what is actually computed.
  • The spatial interpolation method akima lost its parameter linear.
  • The spatial interpolation method kriging now performs a KNN kriging.
  • catalog_queries() lost the parameter ... all the fields are loaded by default.
  • Removed lasterrain() which was not consistent with other functions and not useful.


  • The header of LAS objects automatically updates Number of point records and Number of nth return.
  • lasnormalize() updates the header and returns warnings for some behaviors
  • [#39] interpolation with duplicated ground points

lidR v1.0.2 (Release date: 2016-12-31)

Third submission

  • Change: explain LiDAR in the Description - requested by Kurt Hornik.

lidR v1.0.1 (Release date: 2016-12-30)

Second submission - rejected

  • Change: split the package in two parts. 'lidR' relies on 'rlas' to read binary files.

lidR v1.0.0 (Release date: 201-12-16)

First submission - rejected

Reference manual

It appears you don't have a PDF plugin for this browser. You can click here to download the reference manual.


2.0.0 by Jean-Romain Roussel, 19 days ago

Report a bug at

Browse source code at

Authors: Jean-Romain Roussel [aut, cre, cph] , David Auty [aut, ctb] (Reviews the documentation) , Florian De Boissieu [ctb] (Fixed bugs and improved catalog features) , Andrew Sánchez Meador [ctb] (Implemented lassnags)

Documentation:   PDF Manual  

GPL-3 license

Imports data.table, future, gdalUtils, geometry, glue, grDevices, gstat, lazyeval, imager, Rcpp, RCSF, rgeos, rgdal, rgl, rlas, sf, stats, tools, utils

Depends on methods, raster, sp

Suggests EBImage, concaveman, crayon, hexbin, mapview, progress, testthat, knitr, rmarkdown

Linking to BH, Rcpp

Suggested by uavRst.

See at CRAN