How to filter LiDAR data by scan angle?

I just finished writing a script to accomplish this task using the free and open-source GIS Whitebox Geospatial Analysis Tools (download here), for which I am the lead developer. The source code of the script can be found here. Although the script is not yet part of the current official Whitebox release (v. 3.2.1) you can get an early version of it by selecting Update Scripts From Repository from the Tools menu. You will need to relaunch Whitebox after doing this. You should then find a new script in the LiDAR toolbox called Filter LAS Scan Angles. Unfortunately you won't have an associated Help file until the public release of the tool with the next version of Whitebox.

enter image description here

The tool takes any number of LAS file inputs and will filter them in parallel. Thus, the performance should scale with the number of cores you have on your system. If you want to integrate the tool within a workflow involving multiple steps or run it in batch mode, you can also call the tool from a Python script in the Whitebox Scripter using the following as an example:

wd = pluginHost.getWorkingDirectory() 
# You may have multiple input files but they must # be separated by semicolons in the string. 
inputs = wd + "input1.las" + ";" + wd + "input2.las" + ";" + wd + "input3.las" 
threshold = "15.0"
args = [inputs, threshold]
pluginHost.runPlugin("FilterLasScanAngles", args, False)

The tool will output a ShapeFile of MULTIPOINTZ shapetype for each LAS input. The elevation and intensity values are stored in the Z and M properties of the points respectively. I hope that suffices, if not, I can work on it to output LAS files, but it'll take more time.

Here's an example, where I've filtered a LAS file to remove all points with a scan angle greater than 4 degrees. The resulting ShapeFile (in green palette) has been overlayed overtop the original LAS file (in blue palette) and you can see the flight line pattern associated with varying point scan angle.

enter image description here


In terms of commercial software, FME can do this using PointCloudFilter transformer:

example

The syntax required in the 'expression' input is unique to FME, but easy to learn. Here is a video demonstrating how to use PointCloudFilter expressions.

In general, FME would probably not process point clouds as fast as a dedicated LiDAR software, but it could certainly handle any bulk .las tasks.