classify_with_csf() no longer reads one element past the end of the ground-index vector once all ground points have been matched, which caused an out-of-bounds heap read on nearly every call (#321)classify_with_ivf gains a parameter filter (#289)drop_noise() and keep_noise() now filter classes 7 and 18 instead of 18 only (#283)use_attribute as a field in local_maximum() output (#310)= in transform_with() to assign a field (#314)classify_with_ptd (#288)url <- "https://s3.amazonaws.com/hobu-lidar/autzen-classified.copc.laz"
pipeline <- reader_circles(637368.8, 851944.8, 15) + summarise()
ans <- exec(pipeline, on = url)
classify_with_ptd()spikefree() + locally adaptative spikefree|x| modifier to compute on the absolue value. It is now possible to write e.g. rasterize(5, c("a_mean", "|a|_mean"))summarize() for bins != 2always_up in geometry_features().remove_attributes that deprecated remove_attribute (no s).keep_attributesremove_rgb()classify_with_ipf() to classify points with isolated point filter.temppcd()version and pdrf in write_las() to enforce a specific LAS version and point format.classify_with_ivf() supports non cubic voxels with e.g. classify_with_ivf(res = c(1,1,2))hulls() is computed more robustly with GEOS.store_in_attribute in local_maximumexec(..., progress_file = "path/to/progress.ext", log_file = "path/to/log.ext")
Accessible in the C++ API via two members
Pipeline::set_progress_file(std::string);
Pipeline::set_profile_file(std::string);
write_vpc were broken since 0.17.0sor when executed in parallel on multiple files.local_maximum() after normalize() or delete_points()info() prints informations for each processed chunk. Not only the first one.lasR 0.17.0 does not bring new features. However it has been redesigned internally to provided a C++ API. The R API (the lasR package) now uses the C++ API. And we have now a python package (pylasr) that leverage the C++ API as well. It is now possible to integrate lasR into your own API in matlab, juliaor any language that supports a C++ binding
Below a simple pipeline with 3 stage using the C++, R and python API. The variable on is a list of file on which to apply the pipeline.
in C++:
#include "api.h"
using namespace api;
// platform independent tmp file
std::filesystem::path temp_dir = std::filesystem::temp_directory_path();
std::filesystem::path temp_file = temp_dir / "test.las";
Pipeline p;
p.set_files(on);
p.set_concurrent_files_strategy(8);
p.set_progress(true);
p += info() +
delete_points({"Z < 1.37"}) +
write_las(temp_file);
std::string file = p.write_json();
execute(file);
in R:
library(lasR)
pipeline = info() +
delete_points("Z < 1.37") +
write_las()
execute(pipeline, on, ncores = 8, progress = TRUE);
in python:
import pylasr
# Use example file from the package
example_file = "inst/extdata/Example.las"
output_file = "filtered_output.las"
pipeline = (pylasr.info() +
pylasr.delete_points(["Z < 1.37"]) +
pylasr.write_las(output_file))
pipeline.set_progress(True)
result = pipeline.execute(example_file)
delete_points behavior: The stage delete_points now works consistently with other stages’ filter arguments. Previously, delete_points("Z < 4") kept points below 4, which allowed for commands like delete_points(keep_z_below(4)) but was counter-intuitive.Now, points matching the filter are processed. In the case of delete_points(), this means deleted.geometry_features when running after points had been deleted by delete_points().lasR is now as fast as it should be. For an unknown reason, it had become extremely slow with some stages
involving spatial queries such as normalize(), transform_with(), sor(), and geometry_feature(). lasR
performance has been restored.kdtree for spatial indexing can take significant time (several seconds). Spatial
indexes are now built only when required. Thus, a pipeline using only rasterize() will no longer build a spatial index.lasR at the cost of increased memory usage. lasR now consumes more memory.reader_circles() and reader_rectangles() are skipping queries outside the file collectionsort_points() works with deleted points in previous stagesclassify_with_sor() is flagged as parallelized and should use multiple coresnanoflann; stages relying on KNN search are now much fasteredit_attribute()remove_attribute()keep_z_between() and drop_z_between()filter argumentadd_extrabytes()add_attributes() checks for reserved names (#159)geometry_feature() is now called inclination instead of angle, as angle is a reserved nameadd_attribute() overwrite previous attribute rather that duplicating them.callback with deleted pointslasR now supports the PCD format. The reader() function can read PCD files, and a new stage, write_pcd(), is available. However, due to the current state of the software and limitations of the format itself, functionality is restricted: lasR cannot read multiple PCD files, and thus cannot buffer or merge them. Additionally, write_pcd() does not support streaming data.info() now prints useful COPC metadata.chm() function has been replaced by dsm().write_las() drops circular buffers properlywrite_las() preserves dates and writes generating softwarewrite_copc() function with extra arguments to control hierarchy depth and density.geometry_feature() overwrite attributes if they are already existing.check in load_matrix() to disable orthogonality checkinfo() is reporting the point density..tif for a local maximum output instead of .shpor gpkg returned a non helpful error:
Erreur : error 1 while creating GDAL dataset. Attempt to create 0x0 dataset is illegal,sizes must be larger than zero. It now returns Expecting a vector format for: file.tiffilter argument with negative numbersexec() with 0 file no longer crashes.load_matrix()write_las() properly writes return number and number of return in LAS 1.4 format 6info() no longer prints for every point in streamable pipelineswrite_las(). It will write the same LAS file version and format than the input.info() prints the source format (LAS, PCD) and its version (1.4, 0.7).transform_with when used with a raster, bilinear interpolation can be deactivatedskew and kurt in the metric engine.write_las() now automatically writes LAS 1.4 format if required.region_growing() that could cause edge effects across two tiles or chunks effectively splitting some trees in two parts with different IDs in high-resolution CHM.region_growing() states that the max_cr parameter represents the "Maximum value of the crown diameter of a detected tree". In practice, it was used as the maximum radius, resulting in trees larger than expected. This has been corrected.update_header() updates the bounding box. Bug probably invisible to users.lasR 0.13.0 is a massive rewrite of the internal engine to conform to third-party libraries licenses. With this version lasR is no longer tight to the LAS/LAZ format and will be able to support any point cloud format. It already partially supports the PCD file format.
I'm expecting users to encounter some bugs in the near future. However, all the unit tests are passing.
LASlib filters such as -drop_z_above 5 in the stages (except the reader stage). Users must use conditional commands introduced in 0.12.0, such as "Z > 5".sort_points() no longer sorts by GPS time and return number. It performs a spatial sort only, and the parameter spatial has been removed.classify_with_csf() no longer uses the last return only.write_las() no longer preserves VLR and EVLR. This will be fixed later.New: Ability to pre-read a point cloud in R using an external pointer. See ?read_cloud(). See the tutorial.
New: Stages can now be applied one by one to a point cloud loaded in memory.
f <- system.file("extdata", "Topography.las", package="lasR")
pc <- read_cloud(f)
u = exec(chm(5), on = pc)
New: reader() replace reader_las() because lasR is not intended to be limited to LAS/LAZ. reader_las() is deprecated. reader() is supposed to support any format in the future.
New: reader() has a new argument copc_depth
sampling_poisson(1, filter = keep_ground())
Previously, this filtered the point cloud to retain only Poisson-sampled ground points. Now, it correctly Poisson-samples the ground points while preserving all other points.info(), to print useful information about a file.install_cmd_tools(), then commands like these become available:
lasr info -i path/to/file.las
lasr vpc -i path/to/folder
lasr lax -i path/to/folder -ncores 8
lasr help
lasr chm -i path/to/folder -o path/to/chm.tif -res 1 -ncore 4
lasr dtm -i path/to/folder -o path/to/chm.tif -res 0.5 -ncore 4
transform_with() now supports a 4x4 Affine Transformation Matrix to translate and rotate the point cloud.Eigen library has replaced the Armadillo library for linear algebra. This change may affect the sign of some vectors in geometry_feature().filter argument, available in many stages, now accepts programming-style strings such as Z < 3, Classification == 2, UserData == 0, Intensity > 100, Classification %in% 2 3 4, and Classification %out% 0 1 2. This approach is now the preferred way to assign filters, allowing filtering on extrabyte attributes by name, e.g., Amplitude > 10.transform_with() a raster (typically normalization) now performs bilinear interpolation.use_attribute argument now accept any attribute including extrabytes attribute.sampling_pixel() gained an argument method and use_attribute to retain specific points of interest.Change: normalize() loose its argument extrabytes in favor of a new function hag() that is equivalent to normalize(TRUE)
New: add stages delete_noise(), delete_ground()
Fix: The local_maximum function previously experienced significant delays when writing points to disk, taking up to 2 seconds on Linux and up to 30 seconds on Windows. This issue severely hindered parallelization capabilities. The new fix dramatically reduces the write time to around 0.1 seconds, greatly improving overall performance.
stop_if() before reader_las(). Previously, the buffer was being read even when points were meant to be skipped, leading to unnecessary processing time (a few seconds per skipped file).classify_with_sor() to classify outliers with statistical outlier removal.focal() to post-process rasters in the pipeline.filter_with_grid() to keep the lowest or highest point per cell of a grid.geometry_feature, r = 5 was equal to 5 but r = 4.5 was equal to 4.region_growing() for individual tree segmentation were inverted.-keep_last, -keep_class 128) are now functional with LAS 1.4..copc.las extension; .copc is automatically discarded.classify_with_csf() stage has gained a filter argument.load_raster() if the raster does not have an extent that overlaps with the point cloud.sort() now handles duplicated gpstime properly.local_maximum() could return multiple too-close local maximum points if two close points have the exact same Z coordinates and the exact same X or Y coordinates (but not both X and Y; duplicated points were properly handled). This particularly affected local_maximum_raster(), where two pixels can easily have the same Z and the same X or Y.region_growing() the th_tree argument was not properly respected.transform_with with a TIN won't fail if there is no TIN. Instead all points will be removed.exec() accepts the path to a json file produced by a UI (non documented)keep_ground_and_water()normalize uses keep_ground_and_water()triangulation fails with < 3 pointssort_points() to optimize compression.write_lax() is 2x faster when used as a single stagewrite_lax() for LAS 1.4.write_lax() is now parallelizeduse_gpstime in write_vpc()write_vpc()write_vpc() writes valid files readable by QGISivf is faster.New stage classify_with_csf() to classify ground points.
The metric engine introduced in v0.6.0 can now compute metrics on extrabytes attributes. e.g. Amplitude_mean
New stage sampling_poisson to perform Poisson Disk Sampling
sampling_pixel and sampling_voxel are faster.
sampling_* stages respect the filter argument
Fix #63 crash when some chunk are skipped either because they have 0 points of because of the stop_if stage.
Fix #64 metrics on RGB were actually computed on RRR
classify_isolated_voxels() renamed into classify_with_ivf() for consistency.*cv and sd that were not computed properly.cv and sd that return NAs instead of Inf in the edges case where they are undefined.reader_las() stage. It now displays the correct percentage.write_las() without wildcard (merge mode) works with files that have different formats and scales/offsetsNew stage stop_if to conditionally escape the pipeline. New section about stop_if in the online tutorial.
New stage write_lax. This stage was automatically added by the engine but can now be explicitly added by users.
New internal "metric engine". The metric engine is used to compute metrics in, e.g., rasterize() with operators like zmean, imean, and so on. The metric engine has been redesigned and allows any string with the format attribute_metric such as z_sd, i_mean, c_mode, a_mean, intensity_max, classification_mode, angle_mean, and any other combinations. All attributes are mapped, and new functions are available such as sum, mode. Many more could be added easily. Former strings such as zmean or imax are no longer valid and should be replaced by z_mean and i_max but are backward compatible.
rasterize gained access to the new metric engine and can compute many more metrics natively.
summarize() gained access to the metric engine and can compute metrics for each file or each chunk. Used in conjunction with reader_las_circle(), it can be used, for example, to compute plot inventory metrics. The online tutorial has been updated. The section "plot inventory" no longer uses callback() and is preceded by a new section "summarize".
The package no longer assigns set_parallel_strategy(concurrent_points(half_core())) when loading. Instead, if nothing is provided, this is interpreted as concurrent_points(half_core()). Thus, users can now write exec(pipeline, on = file, ncores = 8). The engine will now respect ncores = 8 because no global settings with global precedence were assigned. The multi-threading vignette has been updated.
Pipelines that include R-based stages (rasterize with R function, callback) are no longer parallelizable with the concurrent-file strategy. Parallelizing a pipeline that involves the R C API is terribly complex and eventually leads only to pseudo-parallelism with a lot of troubleshooting to deal with (especially to abort the pipeline). Consequently, we removed parallelism capabilities. The numerous new native metrics added in the metric engine compensate for that loss. The online documentation has been updated accordingly.
lasR from R. lasR can now be compiled as standalone software. A Makefile has been added to the repository. At the R level, the pipeline and the processing options are passed to the C++ engine via a JSON file instead of being passed via the R's C API, effectively separating lasR from R itself. The R side of lasR is now purely an API to the standalone engine. A JSON file produced by the lasR package can be executed with the standalone software: lasr pipeline.json. However, the syntax of the JSON file is not documented and is not intended to be documented. Rather, the JSON file should be produced by an API such as the lasR package, a QGIS plugin, or a Python package. Obviously, there is currently no such thing.reader_las() with COPC files, depth query (-max_depth), and buffer. The depth query was not performed at all. The fix is temporary: it breaks the progress bar of reader_las() but this is a less serious bug.reader_las() with very large files.load_raster() is thread-saferasterize() accepts a new argument default_value. When rasterizing with an operator and a filter (e.g. -keep_z_above 2) some pixels that are covered by points may no longer contain any point that pass the filter criteria and are assigned NA. To differentiate NAs from non covered pixels and NAs from covered pixels but without point that pass the filter, the later case can be assigned another value such as 0.write_vpc() properly reprojects the bounding boxes in WGS84write_vpc() writes zmin and zmax for each file.local_maximum() no longer fails with ofile = ""reader_las() for COPC files.zsd and isd were incorrect due to wrong parenthesis in the code.delete_points() when 0 points left.list.list returned by exec is named and duplicated names are made unique with make.names()geometry_features() to address question in #45set_crs() no longer forces the pipeline to read the files.exec() normalizes the path so users do not get an error when providing a path with a ~.rasterize() gained a metric zaboveX to compute canopy cover.geometry_features after delete_points()local_maximum() was processing deleted points.write_vpc write the datetimedelete_points can now physically remove the deleted points if the number of points deleted is important. Before they were flagged but kept in memory. It can also free available memory.write_vpc() gained an argument absolute_pathwrite_vpc() orders the long/lat coordinates properly on Linuxwrite_vpc() writes the absolute path of the relative path does not exist on Windowstriangulate() with 0 point chunk.geometry_feature works if the file already contains some extrabytes attributesdelete_points() removes all the points, the pipeline is stopped for the current chunk/file but the computation keep going for others. This was not the case for all stages and some stages could either crash or stop the computation.write_vpc() does not crash with files without CRSwrite_vpc() write the CRS set upstream by set_crs()geometry_features() to compute point wise geometry features based on k-nearest neighbors.callback() can load more than 10 extrabyte attributes. Using the flag E all the extrabytes are loaded.set_crs() to assign a coordinate reference system at some point of the pipeline.GeoTiff format are now created with COMPRESS=DEFLATE, PREDICTOR=2,TILED=YES effectively reducing the size of the rasterssummarize() output includes the CRS.local_maximum() gained a record_attributes argument to chose if the attribute of the points are recorded in the vector file.local_maximum_raster() no longer record zeroed LAS point attributeslax included into laz file were not working.rasterize() produced corrupted output.set_parallel_strategy(nested(ncores = 4, ncores2 = 4)).datatime is datetime in VPC files.write_vpc() writes the correct number of points for LAS 1.4 files.record_length_after_header).add_attribute() was incorrectly reallocating memory causing potential crashes, especially when adding several attributes.reader_las() crashing if the header of the LAS file did not record the correct number of points.local_maximum_raster.?multithreadinglocal_maximum_raster to compute local maximum on a rasterwith in exec to pass processing options that should be preferred over direct naming.set_exec_options() to assign global processing options and override arguments potentially hardcoded in exec()load_raster to read a raster instead of producing it on the fly from the point cloud.add_rgb to modify the point data format?multithreading?exec and ?set_exec_optionspoint_in_triangle.transform_with can be used with pit_fillpit_fill producing corrupted outputpit_fill was not respecting the parameters given by the userpit_fill in combination with rasterize("max") was not working properlylibrary(lasR) transparently checks for latest version on Windows.processor() and reader() are deprecated and are replaced by exec() and reader_las(). This intends to provide a more consistent and natural way to separate the pipeline. i.e the stages and the global processing options i.e. the buffer, the chunking, the progress bar. For example the following now respects the LAScatalog processing options and this was not possible with the previous syntax.
ctg = lidR::readLAScatalog()
pipeline = reader_las() + rasterize(...)
exec(pipeline, on = ctg)
lidR
pipeline = reader_las() + rasterize(...)
exec(pipeline, on = file, chunk = 500)
delete_points() to remove some points in the pipeline.dtm = dtm()
pipeline <- read + dtm + transform_with(dtm[[2]])
pipeline = rasterize(...)
exec(pipeline, on = ctg)
summarize(), rasterize() and write_las() no longer process withheld points in streaming mode.callback() properly handles errors from the injected functiontempxyz() to generate temp files with extension .xyz.rasterize() is now parallelized with internal metrics including for buffered area based approachrasterize() gained a progress bar with internal metrics.rasterize() gains the ability to perform a multi-resolution or buffered rasterization. See documentation.rasterize() gains numerous native metrics such as zmax, zmean, zmedian, imax, imean and so on.LAScatalog from lidR respecting the processed attribute used in lidRLAScatalog) can be enabled with progress = TRUEncores in processor(), which incorrectly mentioned that it was not supported.ncores() and half_cores().