Recently a user of LAStools asked a question in our user forum about how to classify LiDAR data that contains lots of low noise. A sample screen shot of the user’s failed attempt to correctly classify the noise using lasnoise and the ground with lasground is shown below: red points are noise, brown points are ground, and grey points are unclassified. In this article we show how to remove this low noise using a temporary ground surface that we construct from a subset of points at a certain elevation percentile. You can follow along by downloading the data and the sequence of command lines used.
Download the LiDAR data set that was apparently flown with a RIEGL “crossfire” Q1560. You can also download the command line sequence here. We first run lasinfo with option ‘-compute_density’ (or ‘-cd’ for short) to get a rough idea about the last return density which is quite high with an average of over 31 last returns per square meter. We then use lasthin to classify one last return per square meter with the temporary classification code 8, namely the one whose elevation is closest to the 20th percentile per 1 meter by 1 meter grid cell. We then repeat this command line for the 30th, 40th, 50th percentile modifying the command line accordingly. You must use this version of lasthin that will part of a future LAStools release as options ‘-ignore_first_of_many’ and ‘-ignore_intermediate’ were just added this weekend.
lasthin -i crossfire.laz ^ -ignore_first_of_many -ignore_intermediate ^ -step 1 ^ -percentile 20 15 ^ -classify_as 8 ^ -odix _p20 -olaz
Below you see the resulting subset of points marked with the temporary classification code 8 for the four different percentiles 20th, 30th, 40th, and 50th triangulated into a surface and hill-shaded.
Next we reclassify only those points marked with the temporary classification code 8 into ground (2) and unclassified (1) points using lasground by ignoring all points that still have the original classification code 0.
lasground -i crossfire_p20.laz ^ -ignore_class 0 ^ -wilderness ^ -odix g -olaz
Below you see the resulting ground points computed from the subsets of points at four different percentiles 20th, 30th, 40th, and 50th triangulated into a surface and hill-shaded.
Both the ground classification of the 40th and the 50th percentile look reasonable. Only a few down spikes remain in the 40th percentile surface and a few additional bumps appear in the 50th percentile surface. Next we use lasheight with those two reasonable-looking ground surfaces to classify all points that are 20 centimeter below the triangulated ground surface into the noise classification code 7.
lasheight -i crossfire_p40g.laz ^ -classify_below -0.2 7 ^ -do_not_store_in_user_data ^ -odix h -olaz
Now that the low noise points were removed (or rather classified as noise) we start the actual ground classification process. In this example we want to create a 50 cm DTM, hence it is more than sufficient to find one ground point per 25 cm cell. Therefore we first move all lowest non-noise last return per 25 cm cell to the temporary classification code 8.
Side note: One might also consider to modify the following workflow to run the ground classification on more than just the last returns by omitting ‘-ignore_first_of_many’ and ‘-ignore_intermediate’ from the lasthin call and by adding ‘-all_returns’ to the lasground call. Why? Because for all laser shots that resulted in a low noise point, this noise point will usually be the last return, so that the true ground hit could be the second to last return.
lasthin -i crossfire_p40gh.laz ^ -ignore_first_of_many -ignore_intermediate ^ -ignore_class 7 ^ -step 0.25 ^ -lowest ^ -classify_as 8 ^ -odix _low25 -olaz
The final ground classification is obtained by running lasground only on the points with temporary classification code 8 by ignoring all others, namely the noise points (7) and the unclassified points (0 and 1).
lasground -i crossfire_p40gh_low25.laz ^ -ignore_class 0 1 7 ^ -wilderness ^ -odix g -olaz
We then use las2dem to create the 50 cm DTM from the points classified as ground. We store this DTM raster to the LAZ format which has shown to be the most efficient format for storing elevation or height rasters. We have started calling this format RasterLAZ. It is supported by all LAStools and the new DEMzip tool. One advantage is that we can feed RasterLAZ directly back into LAStools, for example as done below, for a second call to las2dem that computes a hill-shaded DTM.
las2dem -i crossfire_p40gh_low25g.laz ^ -keep_class 2 ^ -step 0.5 ^ -ocut 9 -odix _dtm50 -olaz las2dem -i crossfire_p40_dtm50.laz ^ -step 0.5 ^ -hillshade ^ -odix _hill -opng
Below the resulting hill-shaded DTMs computed for the 40th and the 50th elevation percentile – as well as for the 45th elevation percentile that we’ve added for comparison.
Below we finally take a closer look at an example 1 meter profile line through the LiDAR classified by the 45th percentile workflow. There is a small stretch of ground points that was incorrectly classified as noise points (find the mouse cursor) so it might be worthwhile to change parameters slightly to make the noise classification less aggressive.
Side note follow-up: The return coloring shows there are indeed some ‘intermediate’ as well some ‘first of many returns’ just where we expect the bare terrain to be. However, there are not so many that the results can be expected to drastically change by including them into the ground finding process.
i am afraid but the posted latest version of lasthin does not include the possibility of “first of many” and “intermediate”
I just downloaded this version and named is lasthin_drop.exe. Then I ran successfully:
lasthin_drop -i crossfire.laz ^
-step 1 ^
-percentile 20 15 ^
-classify_as 8 ^
-odix _p20 -olaz
Still dos not work for me. Downloaded the file – renamed it to lasthin_drop.exe -placed it to bin files of Lastools. In GUI I did not see any change -so I wrote syntax in command line with ignore_first_of_many ^
and I got the message “lasthin is not recognized as internal or external command”
You cannot rename the executable and then use the GUI because it will try to call lasthin.exe and not lasthin_drop.exe as evidenced by the error message.