Skip to main content

Generate DTM (Digital Terrain Model) from DSM (Digital Surface Model)

Project description

dsm2dtm

dsm2dtm logo

Generate DTM (Digital Terrain Model) from DSM (Digital Surface Model)

CI PyPI PyPI Downloads Conda Forge Conda Downloads License

dsm2dtm is a robust, python library for extracting bare earth Digital Terrain Models (DTM) from Digital Surface Models (DSM). It effectively removes non-ground features like buildings, vegetation, and cars, leaving only the underlying terrain.

Key features:

  • Pure Python: No external binary dependencies (no SAGA, no GDAL CLI). Just numpy, scipy, and rasterio.
  • Robust: Handles noise, cliffs, and varied resolutions automatically.
  • Adaptive: Automatically tunes parameters based on input resolution and terrain slope.
  • Easy to Use: Simple CLI and a clean Python API for developers.

Installation

Via Pip

pip install dsm2dtm

Via Conda

conda install -c conda-forge dsm2dtm

From Source

git clone https://github.com/seedlit/dsm2dtm.git
cd dsm2dtm
pip install .

Usage

1. Python Library

You can integrate dsm2dtm into your own Python pipelines. We provide high-level and low-level APIs.

High-Level API (File-based)

from dsm2dtm import generate_dtm, save_dtm

input_path = "data/input_dsm.tif"
output_path = "results/output_dtm.tif"

# 1. Generate DTM (returns numpy array and profile metadata)
dtm_array, profile = generate_dtm(input_path)

# 2. Save to disk
save_dtm(dtm_array, profile, output_path)

Low-Level API (Numpy-based)

Ideal for in-memory processing or integration with other libraries like xarray.

import rasterio
from dsm2dtm.algorithm import dsm_to_dtm

# Load data yourself
with rasterio.open("input_dsm.tif") as src:
    dsm = src.read(1)
    res = src.res  # (x_res, y_res)
    nodata = src.nodata

# Run algorithm on raw numpy array
dtm = dsm_to_dtm(dsm, resolution=res, nodata=nodata)

# dtm is a float32 numpy array

2. Command Line Interface (CLI)

The simplest way to use dsm2dtm is via the command line.

dsm2dtm --dsm input_dsm.tif --out_dir output/

Arguments:

  • --dsm: Path to the input DSM (GeoTIFF).
  • --out_dir: Directory where the output DTM will be saved (default: generated_dtm).
  • --radius: (Optional) Kernel radius in meters for object removal. Objects larger than 2x this radius will typically NOT be removed. Set this to slightly larger than half the width of the largest building in your scene. Default: 40.0.
  • --slope: (Optional) Terrain slope (0-1). Calculated automatically if not provided.

How It Works

The library implements an optimized version of the Progressive Morphological Filter (PMF) combined with surface refinement.

graph LR
    subgraph Preprocessing [Preprocessing]
        A["Input DSM"] -->|Load & Reproject| B["Internal Grid (UTM)"];
        B -->|Resample if >0.5m| C["Working Resolution"];
        C --> D["Slope Estimation"];
    end

    subgraph Core [Core Filtering]
        D --> E{"Progressive Morphological Filter"};
        E -->|Iterative Opening| F["Rough Ground Estimate"];
        F --> G["Surface Refinement"];
        G -->|Remove Spikes| H["Refined Ground"];
    end

    subgraph Post [Post-Processing]
        H --> I["Gaussian Smoothing"];
        I --> J["Gap Filling"];
        J -->|Reproject| K["Final DTM"];
    end
  1. Resolution Adaptation: Parameters are scaled automatically based on the input pixel size. High-resolution inputs (>0.5m) are optionally downsampled for stability and speed, then upsampled back.
  2. Slope Estimation: Local terrain slopes are calculated to adapt the filtering thresholds.
  3. Progressive Morphological Filter (PMF): Iteratively applies morphological opening (erosion followed by dilation) with increasing window sizes. This effectively "shaves off" objects that stick out above the ground surface.
  4. Refinement: A smoothing step compares the rough ground estimate with the original surface to recover over-smoothed details while rejecting spikes.
  5. Gap Filling: Any remaining holes (nodata) are filled using inverse distance weighting or nearest neighbor interpolation.

Examples

Example 1: Urban Area

Removal of buildings from a Digital Surface Model to reveal the underlying terrain. Urban Example

Example 2: Hillside Terrain

Comparison of Input DSM, Generated DTM, and Lidar-derived Ground Truth. Hillside Example


Contributing

We welcome contributions! Please feel free to submit a Pull Request.

Roadmap / Todo

We are actively looking for help with:

  • Performance:
    • GPU acceleration (e.g., using cupy).
    • Parallel processing (Multi-core/Multi-threading or dask).
  • Algorithm Improvements:
    • Reducing holes/artifacts on building borders
    • Better removal of square-shaped buildings (currently works best on rectangular footprints).

Setup

We use uv for dependency management and pre-commit for code quality.

# 1. Clone
git clone https://github.com/seedlit/dsm2dtm.git

# 2. Install dependencies
uv sync --all-extras

# 3. Install hooks
pre-commit install

Running Tests

We use pytest for testing. The suite includes unit tests, stress tests, and integration tests with real-world data (downloaded automatically).

# Run all tests
uv run pytest

# Run only stress tests
uv run pytest tests/test_stress.py

License

MIT License. See LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dsm2dtm-0.3.0.tar.gz (22.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dsm2dtm-0.3.0-py3-none-any.whl (15.3 kB view details)

Uploaded Python 3

File details

Details for the file dsm2dtm-0.3.0.tar.gz.

File metadata

  • Download URL: dsm2dtm-0.3.0.tar.gz
  • Upload date:
  • Size: 22.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dsm2dtm-0.3.0.tar.gz
Algorithm Hash digest
SHA256 be2368e13abbb3a6397e4040369c64e6e3ed88f3694e3d9b431dc7be082ecf71
MD5 ce56cfa5152e8448c0911b94cc27d70d
BLAKE2b-256 ce6e099db848c09027e5e2565fbd140ac7ace70214c6da40e9e2c95401c82dcf

See more details on using hashes here.

Provenance

The following attestation bundles were made for dsm2dtm-0.3.0.tar.gz:

Publisher: pypi-publish.yml on seedlit/dsm2dtm

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dsm2dtm-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: dsm2dtm-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 15.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dsm2dtm-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a3e1c1fd9513d05fff1c7050304bfd544f981c38e59f955773dbd3dfc210918e
MD5 9de79ddcdbfa1ecff615858bc69ef98f
BLAKE2b-256 918748d4dfb5fd6f5036325f16304cee9151672384df876a5a5e5ae400b55567

See more details on using hashes here.

Provenance

The following attestation bundles were made for dsm2dtm-0.3.0-py3-none-any.whl:

Publisher: pypi-publish.yml on seedlit/dsm2dtm

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page