Tuning PMF for Flat Agricultural Terrain

TL;DR: On flat farmland, set slope low (0.1–0.3), initial_distance small (0.1–0.15 m) and max_distance modest (1–1.5 m) so standing crops and hedges are rejected, choose max_window_size just larger than the biggest farm building (20–30 m at 1 m cells), and keep exponential: true. Check the DTM for crop-height bumps and for field drains that were filled in.

# Context and Motivation

This guide is part of PMF Ground Classification. Flat agricultural land looks like the easiest possible ground classification job, and for the morphological filter it mostly is: there are few steep slopes for the opening to cut off. The difficulty is subtler. Crops half a metre to two metres tall form dense, flat-topped canopies that return few ground points in summer; hedgerows and field margins sit a metre or two above fields; field drains and ditches are narrow and shallow. Default PMF settings, which allow a gentle slope and a generous height tolerance, accept crop tops as ground and flatten away drains — both of which matter for the drainage and flood studies that farmland DTMs are typically used for.

Small features that matter on flat land A nearly flat profile across two fields separated by a hedge and a drainage ditch. A standing crop about one metre tall covers the left field. Default PMF settings produce a ground surface that rides on the crop top in places and fills the ditch. Tuned settings keep the ground at the soil surface and preserve the ditch. default: rides on the crop ditch hedge tuned: soil surface kept grey: true ground · dashed: default PMF · solid: tuned PMF (illustrative)

# Prerequisites and Assumptions

  • PDAL 2.x with filters.pmf.
  • Flat or gently undulating terrain (median slope under about 3°).
  • Noise removed, and ideally a leaf-off or post-harvest collection; summer data over tall crops limits any filter.
  • A few reference profiles or checkpoints across drains and field boundaries.

# Step-by-Step Implementation

# Step 1 — Lower the slope parameter

PMF’s slope scales how much the elevation threshold grows with window size. On flat land 0.1–0.3 prevents the threshold from growing large enough to accept crops.

# Step 2 — Tighten the distances

initial_distance is the threshold at the smallest window; max_distance caps it. 0.1–0.15 m and 1–1.5 m reject crops and hedges while tolerating ploughed soil roughness.

# Step 3 — Size the maximum window

max_window_size must exceed the largest object to remove. Farm buildings and machinery sheds are typically 15–30 m across; at 1 m cells, a 31-cell window is usually enough. Larger windows add time and flatten broad but real features.

# Step 4 — Keep exponential growth

exponential: true grows windows geometrically (1, 3, 7, 15, 31…), reaching the maximum quickly with few iterations. Linear growth offers finer control but is slower.

# Step 5 — Check drains and crops

Profile across ditches and field boundaries, and compare the DTM over cropped fields with a post-harvest collection if one exists.

# Complete Working Example

json
{
  "pipeline": [
    "tiles/fens_2206.laz",
    { "type": "filters.range", "limits": "Classification![7:7],Classification![18:18]" },
    { "type": "filters.assign", "value": ["Classification = 1 WHERE Classification == 2"] },
    { "type": "filters.pmf", "cell_size": 1.0, "slope": 0.2, "initial_distance": 0.12,
      "max_distance": 1.2, "max_window_size": 31, "exponential": true },
    { "type": "writers.las", "filename": "out/fens_2206_pmf.laz", "minor_version": 4,
      "dataformat_id": 6, "forward": "all", "tag": "classified" },
    { "type": "filters.range", "inputs": ["classified"], "limits": "Classification[2:2]" },
    { "type": "writers.gdal", "filename": "out/fens_2206_dtm.tif", "resolution": 1.0,
      "output_type": "idw", "window_size": 4, "data_type": "float32" }
  ]
}

A quick comparison of default and tuned settings on the same tile, measuring how high “ground” sits above the lowest returns in each cell — a crop-residue indicator:

python
"""Crop-residue indicator: ground points well above the cell minimum."""
import json

import numpy as np
import pdal

SETTINGS = {
    "default": {"slope": 1.0, "initial_distance": 0.15, "max_distance": 2.5, "max_window_size": 33},
    "tuned":   {"slope": 0.2, "initial_distance": 0.12, "max_distance": 1.2, "max_window_size": 31},
}
for name, s in SETTINGS.items():
    p = pdal.Pipeline(json.dumps({"pipeline": [
        "tiles/fens_2206.laz",
        {"type": "filters.range", "limits": "Classification![7:7],Classification![18:18]"},
        {"type": "filters.assign", "value": ["Classification = 1"]},
        {"type": "filters.pmf", "cell_size": 1.0, "exponential": True, **s},
    ]}))
    p.execute()
    a = p.arrays[0]
    cell = (a["X"] // 2).astype(np.int64) * 1_000_000 + (a["Y"] // 2).astype(np.int64)
    order = np.argsort(cell)
    c, z = cell[order], a["Z"][order]
    starts = np.r_[0, np.nonzero(np.diff(c))[0] + 1]
    cell_min = np.repeat(np.minimum.reduceat(z, starts), np.diff(np.r_[starts, len(z)]))
    g = a["Classification"][order] == 2
    high = (z - cell_min)[g]
    print(f"{name:>8}: ground {g.mean():.1%}, ground >0.4 m above cell min: {(high > 0.4).mean():.2%}")
Crop residue in the ground class Two bars for the share of ground points more than 0.4 metres above the lowest return in their 2 metre cell. Default PMF settings: 6.8 percent, mostly crop tops. Tuned settings: 0.9 percent, close to the level expected from genuine micro-relief such as ridges and furrows. default PMF 6.8 % tuned PMF 0.9 % ground points more than 0.4 m above their 2 m cell minimum (illustrative) summer collection over cereal crops

# Key Parameter Table

Option Default Flat farmland Effect
slope 1.0 0.1–0.3 How fast the threshold grows with window size
initial_distance 0.15 m 0.1–0.15 m Tolerance at the smallest window
max_distance 2.5 m 1.0–1.5 m Cap on the tolerance; below crop and hedge heights
max_window_size 33 25–31 Just above the largest building, in cells
cell_size 1.0 m 1.0 m Grid for the morphological surface
exponential true true Window growth pattern

# Verification

  • Crop-residue indicator as in the script: a low share of ground points far above the local minimum.
  • Ditch profiles. Depths across field drains should match the reference within a decimetre.
  • Seasonal comparison. If a leaf-off or post-harvest flight exists, difference the two DTMs over fields; residual crop shows as positive differences confined to field boundaries.

# Gotchas and Edge Cases

Tall summer crops. Maize or oilseed rape at two metres or more with dense canopy may leave almost no ground returns. No setting recovers ground that was never measured; flag those fields and interpolate from margins.

Levees and embankments. Flood banks are narrow, raised and real. A small max_distance can reject their crests as non-ground. Check known embankments explicitly, and relax settings locally or use breaklines.

Glasshouses and polytunnels. Large, flat structures just above ground look like terrain to morphology. Their footprint needs the maximum window to exceed it; add a building mask if they are common.

Window sizes with exponential growth A sequence of square windows growing 1, 3, 7, 15 and 31 cells wide, reaching a maximum window of 31 cells in five iterations. A farm building 24 metres across fits inside the final window, so it is removed; a larger maximum would add iterations without benefit. 24 m shed 1371531 cells = max_window_size five iterations

Default slope of 1.0. PMF’s default slope was chosen for varied terrain; on flat land it lets the threshold reach max_distance quickly, which is why crops pass. Lowering slope is the most effective single change.

# Frequently Asked Questions

What PMF settings suit flat agricultural land?

A low slope around 0.1 to 0.3, a small initial distance around 0.12 metres, a maximum distance around 1 to 1.5 metres and a maximum window just larger than the largest farm building, with exponential window growth.

Why does PMF classify crops as ground?

With the default slope and maximum distance, the elevation threshold grows large enough to accept flat-topped crop canopies a metre or more above the soil. Lowering slope and max_distance keeps the threshold below crop height.

How do I preserve drainage ditches?

Keep max_window_size no larger than needed and max_distance small, and verify with profiles across known ditches. Narrow ditches can still be interpolated over if few ground returns fall inside them; breaklines help where they are critical.

Is PMF or SMRF better for farmland?

Both work well on flat land when tuned. PMF’s parameters are simple and map directly onto crop and building heights; SMRF offers more control on mixed terrain. Compare them on a reference tile if the project matters.