Home

Awesome

chm_prep

What chm_prep does

High resolution airborne lidar Canopy Height Models (CHMs), or Digital Surface Models (DSM) often present small cavities over forest canopies (figure 1a and 2a). These are caused by laser pulses travelling deep below the generalized crown envelope and generating low returns. CHMs and DSMs may also show spikes (figure 1a) caused by high noise (if it was not properly removed from the point cloud before creating raster products). Finally, isolated no-data pixels (figure 2a) or extreme no-data values may also cause problems. chm_prep can remove all of these. This improves the CHMs or DSMs before they are used for, say, individual tree crown (ITC) extraction, or image orthorectification when a lidar DSM constitutes the 3D source. All in all, it was designed to:

The user controls all the processing parameters.

It leaves all non-problematic pixels unchanged, so it is quite more targeted than, say, a simple median filter applied to all pixels. See for example the results in figures 1b and 2b below. Moreover, it is made for production, so it runs very fast (C speed!), and is by default a batch mode processor ready to process 1000s of tiles.

Figure 1a: this CHM contains cavities and spikes (isolated bright pixels)Figure 1b: CHM in figure 1a processed with chm_prep (cavities and spikes have been removed)
Before and after applying chm_prepBefore and after applying chm_prep
Figure 2a: this CHM contains cavities and isolated no-data pixels (in red, can you spot them?)Figure 2b: CHM in figure 2a processed with chm_prep (cavities and no-data pixels have been removed)
Before and after applying chm_prepBefore and after applying chm_prep

Installing chm_prep

Code structure

chm_prep is composed of two Python scripts (chm_prep.py and chm_prep_process.py) which deal with the I/O and the no-data management. chm_prep_process.py launches the core cavity filling and spike removing algorithm, which, for efficiency reasons, is coded in C (chm_prep.c) and compiled to binary shared libraries (chm_prep_linux.so or chm_prep_win32.so). chm_prep.py makes OS calls to chm_prep_process.py, so make sure your virtual environment (if any) is activated before you launch chm_prep.py`.

Installation

To install, place all the files (.py and .so, etc.) in the same directory (clone the repo to a local directory). Among the installed files, you'll see the two C binaries: chm_prep_linux.so and chm_prep_win32.so, respectively for Linux/GNU and Windows operating systems. When running the Python script, the proper version will automatically be chosen based on your OS.

Note that there are currently no MacOS binary, but you can compile one from source if desired and adjust the Python script accordingly.

Python dependencies

The Python script has the following external dependencies:

Please make sure these packages are installed in your Python environment.

Compiling from source

If you prefer to compile for source (chm_prep.c), make sure to compile to a shared library with the appropriate name for your OS. We hereby provide gcc examples compile commands:

Principles of the filtering algorithm

Before we explain how to use chm_prep, let's take a look at the algorithm steps:

The algorithm can be applied in a single pass, or two passes. For high resolution models (e.g. a 25 cm, or 10 cm CHM), two passes are recommended. The first pass typically uses a bigger Laplacian kernel to get rid of larger cavities (or spikes), while the second pass targets the small pits and spikes. The user controls the number of passes and the parameter values of each.

The original values of all non-anomalous pixels values are conserved.

Using chm_prep

To run chm_prep, adjust the parameter values in the chm_prep.ini file, save it, and run the Python script:

python3 chm_prep.py

The chm_prep.ini file

The chm_prep.ini file contains all the user parameters controlling the I/O and those of the algorithm. A template chm_prep.ini with "factory settings" is provided. It also contains inline comments to help the user properly fill in all the values. Make sure to follow the formatting standards of this template (e.g., no quotation marks around paths, etc.). See the appendix for an example of an chm_prep.ini file.

Input/Output parameters

All .tif files in the source_dir will be processed. The results will be written to the dest_dir. The _prep suffix will be added to the original file names. The dest_dir will be created if it does not exist.

Filtering parameters

The filtering parameters are written on a single comma-delimited line, one line per pass (see the Principles of the filtering algorithm section for a description of passes). The order of the filtering parameters on a line is as follow:

Typical values for two passes for a 25 cm CHM could be:

Typical values for a single pass over a 50 cm CHM could be:

The number of passes (one or two) is controlled by the presence or absence of the pass2_params line.

We recommend to run some tests on a small number of CHMs or DSMs before launching a large batch. Start with a single pass and test some parameter values. If some cavities or spikes are left, implement a second pass.

Saturation parameters

The user can decide to saturate the values to a minimum, for example to avoid CHM values to be below 0 m. The user can also choose to set a maximum for a CHM. This may help removing high noise patches that were not filtered out from the point cloud or limit the anomalous values caused by tree crowns hanging over a steep slope, etc. First, the following parameters must be set to True or False:

Then set the values of the min and max if the above parameters were set to True, e.g.:

no-data parameters

No-data pixels can be present in a CHM or DSM for a variety of reasons: part of a tile was not scanned, pulses reaching a water body did not trigger a return, or the interpolation algorithm used to rasterize the lidar returns left a few isolated no-data values. These can create problems in the downstream processing steps (e.g., for ITC, etc.). What is more, some no-data values represent extreme or non-existing mathematical numbers, such as minus infinity or NaN (Not a Number), which sometimes leads to undesired behavior. chm_prep lets the user keep, filter or modify any no-data pixels using three different schemes:

The first option, transfer, simply leaves the no-data pixels intact (but the user can change their values using the output_nodata_val parameter). The set_to_zero option will change the no-data pixels to zero. This can be practical for setting no-data values over a water body in a CHM to 0.0 m instead of having no-data in these areas, but we don't recommend this option for other use cases. Finally, the remove_small_holes option will leave the large no-data areas intact but will get rid of single pixel or small regions of no-data, such as those generated by certain rasterizing algorithms. The user must then provide a value for the hole_size_thr (hole size threshold) parameter, e.g.:

Holes having a pixel area smaller than hole_size_thr will be filled. The value of hole_size_thr must be an integer representing the number of pixels (pixel area) in individual no-data holes to be used as a threshold.

Tile size, memory management, buffering and CRS

chm_prep is designed for the standard case where a large lidar project is divided in rather small tiles (1 km x 1 km, 2 km x 2 km, etc.). Running chm_prep on a very large file could cause the program to exit because it would run out of memory. Moreover, edge effects can occur where cavities are very close to the edge of a raster lidar tile. Cavities or spikes might be left undetected in these border areas. For this reason, it is recommended to buffer the tiles by at least the amount of pixels of the largest Laplacian kernel width before running chm_prep. The filtered output rasters can be afterward be cut back to their cores and then eventually mosaicked. Finally, the coordinate reference system (CRS) must be defined within the input .tif files.

Demo data

Demo data for testing chm_prep can be found here.

Issues and bug reports

If you encounter issues or bugs, please create an issue by clicking here.

Contacting the author

You can email the author, Benoît St-Onge, at bstonge@protonmail.com or bso@geophoton.ca.

You're also invited to visit our web site: http://www.geophoton.ca

Please give us credit

When using chm_prep, please use the following citation:

St-Onge, B. (2023). chm_prep, an application for removing cavities and spikes from lidar CHMs and DSMs [Software]. Available from https://github.com/Geophoton-inc/chm_prep.

You can also cite the original papers:

The core algorithm was first published in: St-Onge, B., 2008. Methods for improving the quality of a true orthomosaic of Vexcel UltraCam images created using alidar digital surface model, Proceedings of the Silvilaser 2008, Edinburg, 555-562.# https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=81365288221f3ac34b51a82e2cfed8d58defb10e

A related version of the algorithm was later published in: Ben-Arie, J. R., G. J. Hay, R. P. Powers, G. Castilla et B. St-Onge, 2009. Development and Evaluation of a Pit Filling Algorithm for LiDAR Canopy Height Models, IEEE Transactions on Computers and Geosciences, 35:1940-1949 https://www.sciencedirect.com/science/article/abs/pii/S0098300409000624

Licence

chm_prep is distributed under the GNU General public licence. Please consult the licence file.

Diclaimer

THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Documentation version

Last update: October 17th, 2023.

Appendix

Example ini file

Note: # indicates comments. Effective lines are not commented.

chm_prep.ini

# Source directory containing the raw canopy height models.
source_dir=/path/to/your/input/directory

# Output directory to store the improved canopy height models.
dest_dir=/path/to/your/output/directory

# Enter the values of the 4 parameters controlling the cavity filling algorithm in the following order:
# - Size of the Laplacian filter in pixels (suggested values: 3 or 5).
# - Threshold value for the cavity Laplacian filter (suggested value: around 0.1). Values > threshold will be
#   considered as cavities. The smaller the value the more cavities will be detected.
# - Threshold value for the spike Laplacian filter (suggested value: around -0.1). Values < threshold will be
#   considered as spikes. The greater the value the more spikes will be detected.
# - Size of the median filter in pixels (suggested values: 3 or 5).
# - Radius of the dilation filter in pixels (suggested values: 0 or 1).
# The values of a given pass must be written on a single line and separated by commas.
# The values can be entered for a single pass [pass1_params], or optionally for two passes [pass2_params] (the first
# targeting the large cavities, the second targeting the small cavities).
# Single pass example (pass2_params is omitted):
#   pass1_params=3,0.1,3,0
# Two passes example:
#   pass1_params=5,0.1,3,1
#   pass2_params=3,0.1,3,0
pass1_params=3,0.1,-0.1,3,0
pass2_params=3,0.1,-0.1,3,0

# Set force_min_val to True to force the minimum value of the output CHM to be equal to the value of the
# min_val parameter (e.g., 0.0). Set to false to keep the values unchanged (except for filtering).
force_min_val=True
min_val=0.0

# Set force_max_val to True to force the minimum value of the output CHM to be equal to the value of the
# max_val parameter (e.g., 0.0). Set to false to keep the values unchanged (except for filtering).
force_max_val=True
max_val=40.0

# No-data processing. If nodata_processing is set to:
# - "transfer", the no-data values of the input CHM will be transferred to the output CHM.
# - "set_to_zero", all no-data pixels of the input CHM will be set to zero in the output CHM, despite the no-data value
# being set to a value different than zero. This can be used for example to fill the no-data pixels over
# water bodies to zero.
# - "remove_small_holes", the small holes in the output CHM will be treated as cavities and filled. The size of the holes
# to be filled is controlled by the hole_size_thr parameter.
# surrounding pixels.
# Uncomment the desired option below.
# nodata_processing=transfer
# nodata_processing=set_to_zero
nodata_processing=remove_small_holes
# If nodata_processing is set to "remove_small_holes", holes having a pixel area smaller than hole_size_thr will be
# filled. The value of hole_size_thr must be an integer representing the number of pixels in a given no-data hole.
# This parameter is ignored if nodata_processing is set to "transfer" or "set_to_zero".
hole_size_thr=9

# Nodata value in the output CHM.
output_nodata_val=-99.0