I have an ALS point cloud. I have been able to successfully normalize the height, but am wondering if there's any way to remove/filter some points that are obviously errors/outliers (points below 0 and a handful that are 30-50m or even 100m above the tallest trees). The data I'm using was downloaded from the USGS National Map with only ground points already classified.

If I normalize with the tin() algorithm and create my chm straight from the normalize point cloud, my chm min/max values are:

values     : -5.23, 129.98  (min, max)

and if I normalize with a dtm:

values     : -14.65, 129.91  (min, max)

Ultimately, I'm trying to segment trees and generate products of tree heights, canopy cover, tree density, etc. But I can't run my analysis when I know the max tree height will be < 30m across my study site.

If I try to reclassify the ground, will that help with the points below 0? But that won't address the 129m max...

I was thinking maybe I'd be better off smoothing my chm and using the chm/tree tops to segment trees as I was having trouble finding a good way to utilize the li2012() algorithm.


2 Answers 2


There is no 'advanced' outlier filtering in lidR yet. But for simple cases you can built a simple method yourself. Here are some hints and you can modify the examples to fit your need.

Filter point of interest using thresholds

las <- filter_poi(las, Z >= 0, Z <= 30)

Filter high outliers using 95th percentile CHM

This is an example taken from this vignette. It builds a raster of 95th percentile and removes what is too high relatively to this height map.

filter_noise = function(las, sensitivity)
  p95 <- grid_metrics(las, ~quantile(Z, probs = 0.95), 10)
  las <- merge_spatial(las, p95, "p95")
  las <- filter_poi(las, Z < p95*sensitivity)
  las$p95 <- NULL

las <- filter_noise(las, sensitivity = 1.2)

Filter outliers using point based metrics

There is no example given but at the end of this chapter there is a section that explains how to build a pretty advanced outlier filter method with point_metrics()

classify_noise() in v3.1.0

I put this information here for future readers. Starting from v3.1.0 lidR will have (or 'already has' depending on when you are reading) a function classify_noise() with several possible algorithms.


As JRR mentioned, lidr now allows one to classify noise using classify_noise. Two algorithms are implemented: sor and ivf

However, a quick and dirty way is normalize the point cloud, then filter by removing points below zero and points above a reasonable estimate of the tallest trees in the study area, or use some quantile based metric.

for example:

norm<- normalize_height(las, knnidw())
#keep everything above zero and below the 99.99th quantile
filtered <- filter_poi(norm, Z >= 0 & Z < quantile(Z, .9999)) 
#use Z values (60 m) instead of quantiles
filtered <- filter_poi(norm, Z >= 0 & Z < 60) 

You could then unnormalize_height() the file if you wanted to.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.