Generate a Canopy Height Model (CHM) from DSM and DTM in QGIS

QGIStutorialCHMdrone mappingaerial surveyLiDARterrainPython
Generate a Canopy Height Model (CHM) from DSM and DTM in QGIS

A Canopy Height Model (CHM) tells you the height of objects above the bare ground at every pixel. It’s one of the most useful outputs of a drone survey — once you have a CHM, you can classify vegetation by height, extract tree heights for individual features, and generate classified maps for client reports.

What it does

The generate_chm.py script subtracts the DTM (bare earth elevation) from the DSM (surface elevation including trees and structures). The result at each pixel is the height of whatever is there above the ground.

If the DSM and DTM have different spatial resolutions (common when they come from different processing runs), the script automatically resamples the DTM to match the DSM grid before subtraction. Negative values from noise or misalignment are clamped to zero.

Output: {dtm_name}_chm.tif saved in the DTM directory, added to your QGIS project.

What you need

  • QGIS 3.28 or newer
  • numpy, rasterio (bundled with QGIS)
  • A DSM raster with “dsm” in the layer name, checked in the Layers panel
  • A DTM raster with “dtm” in the layer name, checked in the Layers panel
  • The generate_chm.py script from the Terrain Analysis Pack

The two rasters this script reads, as coloured hillshade — DSM (surface, includes canopy):

DSM hillshade of a forested estate, coloured by elevation, canopy visible as texture

DTM (bare ground only):

DTM hillshade of the same estate — bare ground elevation with canopy stripped out

Steps

  1. Load your DSM and DTM rasters into QGIS. The layer names must contain dsm and dtm respectively.
  2. Check (tick) both layers in the Layers panel.
  3. Open Plugins → Python Console → Show Editor.
  4. Paste the script and click Run.

The CHM is saved in the DTM directory and loaded into your QGIS project. Raw, it looks like this — a grey/white gradient, bright where the canopy is tall:

Raw grayscale Canopy Height Model — bright patches are tall canopy, dark patches are ground

What to do with the CHM

Once you have a CHM, you can:

Here’s the same CHM after style_chm.py classifies it into height bands — much easier to read than the raw grey version above:

Classified Canopy Height Model with a five-band legend — tan for bare ground through dark red for tall canopy — plus north arrow and distance axes

Typical CHM values in plantation surveys

In a mature plantation:

  • 0–1 m: ground cover, low shrubs
  • 1–5 m: young trees or understorey
  • 5–15 m: mid-canopy trees
  • 15 m+: tall canopy in well-established estates

Get the script

generate_chm.py is part of the Terrain Analysis Pack — five terrain analysis scripts for QGIS at $35 USD.