Skip to content

r.dem.bias

Remove terrain-correlated systematic bias from a DoD

r.dem.bias dod=name output=name method=string [predictors=name [,name,...]] [stable_mask=name] [mask=name] [bias_field=name] [output_se=name] [output_leverage=name] [fit_json=name] [spline_tension=float] [spline_smooth=float] [spline_npoints=integer] [spline_res=float] [log_predictors=string [,string,...]] [window=integer] [trim_low=float] [trim_high=float] [--overwrite] [--verbose] [--quiet] [--qq] [--ui]

Example:

r.dem.bias dod=name output=name method=regression

grass.tools.Tools.r_dem_bias(dod, output, method, predictors=None, stable_mask=None, mask=None, bias_field=None, output_se=None, output_leverage=None, fit_json=None, spline_tension=40.0, spline_smooth=5.0, spline_npoints=50000, spline_res=10.0, log_predictors=None, window=21, trim_low=2.5, trim_high=97.5, overwrite=None, verbose=None, quiet=None, superquiet=None)

Example:

tools = Tools()
tools.r_dem_bias(dod="name", output="name", method="regression")

This grass.tools API is experimental in version 8.5 and expected to be stable in version 8.6.

grass.script.run_command("r.dem.bias", dod, output, method, predictors=None, stable_mask=None, mask=None, bias_field=None, output_se=None, output_leverage=None, fit_json=None, spline_tension=40.0, spline_smooth=5.0, spline_npoints=50000, spline_res=10.0, log_predictors=None, window=21, trim_low=2.5, trim_high=97.5, overwrite=None, verbose=None, quiet=None, superquiet=None)

Example:

gs.run_command("r.dem.bias", dod="name", output="name", method="regression")

Parameters

dod=name [required]
    Input DEM of Difference raster to correct
output=name [required]
    Output bias-corrected DoD raster
method=string [required]
    Bias-correction method
    Allowed values: regression, forest, spline
predictors=name [,name,...]
    Terrain predictor rasters (method=regression)
stable_mask=name
    Stable-terrain mask defining the regression fit region (method=regression)
mask=name
    Mask of cells used for the local bias field, e.g. forest (method=forest)
bias_field=name
    Optional output of the estimated bias field that was subtracted
output_se=name
    Output coefficient-uncertainty SE raster of the bias model, sqrt(x' Cov x) (method=regression, 1 sigma, excludes residual variance)
output_leverage=name
    Output extrapolation-distance raster d = sqrt(n*h - 1) in fit-sd units (method=regression)
fit_json=name
    JSON file persisting the fit (n, s2, coefficients, covariance, transforms; method=regression)
spline_tension=float
    v.surf.rst tension for the spline bias field (method=spline)
    Default: 40.0
spline_smooth=float
    v.surf.rst smoothing for the spline bias field (method=spline; oversmoothing is the safe direction for a long-wavelength field)
    Default: 5.0
spline_npoints=integer
    Stable cells sampled as spline fit points (method=spline; deterministic seed)
    Default: 50000
spline_res=float
    Interpolation resolution (m) for the spline bias field, resampled bilinearly to the analysis grid (method=spline)
    Default: 10.0
log_predictors=string [,string,...]
    Predictors to log-transform before z-scoring (must be listed in predictors; explicit, never data-triggered)
window=integer
    Window size in cells for the local bias field (method=forest)
    Default: 21
trim_low=float
    Lower trimming percentile for the local bias core (method=forest)
    Default: 2.5
trim_high=float
    Upper trimming percentile for the local bias core (method=forest)
    Default: 97.5
--overwrite
    Allow output files to overwrite existing files
--help
    Print usage summary
--verbose
    Verbose module output
--quiet
    Quiet module output
--qq
    Very quiet module output
--ui
    Force launching GUI dialog

dod : str | np.ndarray, required
    Input DEM of Difference raster to correct
    Used as: input, raster, name
output : str | type(np.ndarray) | type(np.array) | type(gs.array.array), required
    Output bias-corrected DoD raster
    Used as: output, raster, name
method : str, required
    Bias-correction method
    Allowed values: regression, forest, spline
predictors : str | list[str], optional
    Terrain predictor rasters (method=regression)
    Used as: input, raster, name
stable_mask : str | np.ndarray, optional
    Stable-terrain mask defining the regression fit region (method=regression)
    Used as: input, raster, name
mask : str | np.ndarray, optional
    Mask of cells used for the local bias field, e.g. forest (method=forest)
    Used as: input, raster, name
bias_field : str | type(np.ndarray) | type(np.array) | type(gs.array.array), optional
    Optional output of the estimated bias field that was subtracted
    Used as: output, raster, name
output_se : str | type(np.ndarray) | type(np.array) | type(gs.array.array), optional
    Output coefficient-uncertainty SE raster of the bias model, sqrt(x' Cov x) (method=regression, 1 sigma, excludes residual variance)
    Used as: output, raster, name
output_leverage : str | type(np.ndarray) | type(np.array) | type(gs.array.array), optional
    Output extrapolation-distance raster d = sqrt(n*h - 1) in fit-sd units (method=regression)
    Used as: output, raster, name
fit_json : str, optional
    JSON file persisting the fit (n, s2, coefficients, covariance, transforms; method=regression)
    Used as: output, file, name
spline_tension : float, optional
    v.surf.rst tension for the spline bias field (method=spline)
    Default: 40.0
spline_smooth : float, optional
    v.surf.rst smoothing for the spline bias field (method=spline; oversmoothing is the safe direction for a long-wavelength field)
    Default: 5.0
spline_npoints : int, optional
    Stable cells sampled as spline fit points (method=spline; deterministic seed)
    Default: 50000
spline_res : float, optional
    Interpolation resolution (m) for the spline bias field, resampled bilinearly to the analysis grid (method=spline)
    Default: 10.0
log_predictors : str | list[str], optional
    Predictors to log-transform before z-scoring (must be listed in predictors; explicit, never data-triggered)
window : int, optional
    Window size in cells for the local bias field (method=forest)
    Default: 21
trim_low : float, optional
    Lower trimming percentile for the local bias core (method=forest)
    Default: 2.5
trim_high : float, optional
    Upper trimming percentile for the local bias core (method=forest)
    Default: 97.5
overwrite : bool, optional
    Allow output files to overwrite existing files
    Default: None
verbose : bool, optional
    Verbose module output
    Default: None
quiet : bool, optional
    Quiet module output
    Default: None
superquiet : bool, optional
    Very quiet module output
    Default: None

Returns:

result : grass.tools.support.ToolResult | np.ndarray | tuple[np.ndarray] | None
If the tool produces text as standard output, a ToolResult object will be returned. Otherwise, None will be returned. If an array type (e.g., np.ndarray) is used for one of the raster outputs, the result will be an array and will have the shape corresponding to the computational region. If an array type is used for more than one raster output, the result will be a tuple of arrays.

Raises:

grass.tools.ToolError: When the tool ended with an error.

dod : str, required
    Input DEM of Difference raster to correct
    Used as: input, raster, name
output : str, required
    Output bias-corrected DoD raster
    Used as: output, raster, name
method : str, required
    Bias-correction method
    Allowed values: regression, forest, spline
predictors : str | list[str], optional
    Terrain predictor rasters (method=regression)
    Used as: input, raster, name
stable_mask : str, optional
    Stable-terrain mask defining the regression fit region (method=regression)
    Used as: input, raster, name
mask : str, optional
    Mask of cells used for the local bias field, e.g. forest (method=forest)
    Used as: input, raster, name
bias_field : str, optional
    Optional output of the estimated bias field that was subtracted
    Used as: output, raster, name
output_se : str, optional
    Output coefficient-uncertainty SE raster of the bias model, sqrt(x' Cov x) (method=regression, 1 sigma, excludes residual variance)
    Used as: output, raster, name
output_leverage : str, optional
    Output extrapolation-distance raster d = sqrt(n*h - 1) in fit-sd units (method=regression)
    Used as: output, raster, name
fit_json : str, optional
    JSON file persisting the fit (n, s2, coefficients, covariance, transforms; method=regression)
    Used as: output, file, name
spline_tension : float, optional
    v.surf.rst tension for the spline bias field (method=spline)
    Default: 40.0
spline_smooth : float, optional
    v.surf.rst smoothing for the spline bias field (method=spline; oversmoothing is the safe direction for a long-wavelength field)
    Default: 5.0
spline_npoints : int, optional
    Stable cells sampled as spline fit points (method=spline; deterministic seed)
    Default: 50000
spline_res : float, optional
    Interpolation resolution (m) for the spline bias field, resampled bilinearly to the analysis grid (method=spline)
    Default: 10.0
log_predictors : str | list[str], optional
    Predictors to log-transform before z-scoring (must be listed in predictors; explicit, never data-triggered)
window : int, optional
    Window size in cells for the local bias field (method=forest)
    Default: 21
trim_low : float, optional
    Lower trimming percentile for the local bias core (method=forest)
    Default: 2.5
trim_high : float, optional
    Upper trimming percentile for the local bias core (method=forest)
    Default: 97.5
overwrite : bool, optional
    Allow output files to overwrite existing files
    Default: None
verbose : bool, optional
    Verbose module output
    Default: None
quiet : bool, optional
    Quiet module output
    Default: None
superquiet : bool, optional
    Very quiet module output
    Default: None

DESCRIPTION

r.dem.bias removes terrain-correlated systematic bias that remains in a DEM of Difference (DoD) after rigid co-registration. Alignment tools such as r.dem.coregister, r.dem.nk, and r.dem.icp remove translation and rotation, but a residual elevation difference often still varies with terrain (for example a positive canopy bump in forest, or error that scales with slope, roughness, or point density). This tool models that residual and subtracts it.

Three methods are provided through the method option.

method=regression

Fits a multivariable linear model of the DoD on z-scored terrain predictors over stable terrain, then subtracts the fitted surface from the full DoD.

  • The dependent variable is the DoD restricted to the stable_mask region.
  • Each predictors raster is standardized to zero mean and unit variance, on a log scale for the predictors named in log_predictors (positive values only; a predictor with non-positive values falls back to the linear scale with a warning).
  • An ordinary-least-squares fit (numpy, on sampled stable cells; above 2 million cells a deterministic subsample is drawn) estimates the intercept, per-predictor coefficients, and the coefficient covariance, and the fitted bias field b0 + sum(b_i * z_i) is subtracted from the DoD.
  • The optional output_se raster is the 1-sigma coefficient-uncertainty term of the bias model, sqrt(x' Cov x) evaluated on the transformed predictors. It deliberately excludes the residual variance s2 (reported in the raster metadata and the message stream) so that downstream quadratures (r.dem.lod sigma_extra, r.dem.errprop sigma) can combine it with local dispersion and registration terms without double counting. The covariance is iid OLS: under spatially correlated residuals it understates coefficient uncertainty, so treat the magnitude as a lower bound pending an autocorrelation-aware covariance.
  • The optional output_leverage raster is the extrapolation distance d = sqrt(n*h - 1) in fit-sd units (Mahalanobis distance of each cell from the fit-cell predictor mean). It is independent of n and of the covariance assumptions, and is the honest "distance from control" map: coefficient uncertainty cannot express model-form error under extrapolation, which must be checked out-of-sample.
  • The optional fit_json file persists the whole fit (n_fit, residual variance s2_m2, intercept, per-predictor coefficients, the coefficient covariance matrix, the applied transforms, and max_fit_cells) so a reported correction can be reproduced or re-applied without refitting.
  • Log transforms are explicit via log_predictors; the earlier data-triggered skew rule was removed because a region-scoped statistic crossing a threshold must not silently change the model form (and a log of datum-referenced elevation would make the model datum-dependent).

Predictor rasters are typically produced by r.dem.stats (slope, roughness, landform diversity, local sigma) together with a reference-DEM uncertainty surface.

method=spline

Interpolates the stable-cell residuals into a smooth spatial bias field with v.surf.rst and subtracts it. This models the systematic error as what it physically is, a smooth surface over the map (photogrammetric doming), rather than a function of terrain predictors, and therefore has no collinearity pathologies. The field is fit from spline_npoints randomly sampled stable cells (deterministic seed) at the coarse spline_res resolution (the error is long-wavelength) with spline_tension and spline_smooth, then resampled bilinearly to the analysis grid. Splines interpolate well and extrapolate poorly, so the correction is most trustworthy near the stable cells; validate against independent data (holdout) before trusting it far from control.

method=forest

Estimates a local trimmed-median bias field over a masked subset of cells (classically a forest canopy bump) and subtracts it.

  • Within the mask region the DoD is trimmed to its [trim_low, trim_high] percentile core to exclude outliers.
  • A moving-window median of that core over a window-cell window gives the local bias field.
  • Outside the mask the bias field is zero, so unmasked cells are unchanged.

However, a local trimmed median cannot separate a canopy bump from real elevation change, so any deposition or scour inside mask is removed along with the bias. Keep known and suspected change areas out of the mask, using the footprint from a coarse r.dem.screen pass where one is available.

NOTES

The optional bias_field output stores the estimated correction surface that was subtracted, which is useful for inspection and reporting.

For method=regression the corrected DoD is NULL wherever any predictor is NULL (the fitted surface is undefined there); output_se follows the same predictor-driven NULL pattern, and is defined even where the input DoD is NULL.

The mask used by method=forest is applied through a temporary mask context and is removed automatically; the user's existing mask and computational region are left untouched. Intermediate rasters are removed on exit.

EXAMPLES

The commands below use the example scene built in the r.dem toolset manual, which is derived from the North Carolina sample dataset. Build it there first.

The scene carries three bias components, and each method removes a different one. Chain them: no single method removes all three.

Start with the long-wavelength dome, fitted from the stable cells and interpolated across the map:

g.region raster=elev_lid792_1m

r.dem.bias dod=dod_raw output=dod_spline method=spline \
    stable_mask=stable_terrain bias_field=bias_spline

Then the canopy bump, estimated as a local trimmed median under the forest mask:

r.dem.bias dod=dod_spline output=dod_debiased method=forest \
    mask=forest window=21

The residual on stable terrain falls from 0.17 m to under 0.01 m, and the residual over forest falls from 1.68 m to under 0.01 m.

The regression path models the bias against terrain predictors instead, keeping the coefficient uncertainty for the uncertainty budget downstream:

r.dem.bias dod=dod_raw output=dod_regression method=regression \
    predictors=roughness stable_mask=stable_terrain \
    output_se=bias_se output_leverage=bias_leverage \
    fit_json=bias_fit.json

r.dem.bias example
Figure: Raw DoD carrying the survey bias, the fitted spline bias field, and the difference after the spline and forest stages.

SEE ALSO

r.dem, r.dem.coregister, r.dem.errprop, r.dem.stats, r.neighbors, v.surf.rst

AUTHORS

Corey T. White, Center for Geospatial Analytics, NC State University

SOURCE CODE

Available at: r.dem.bias source code (history)
Latest change: Thursday Aug 20 19:32:37 2026 in commit d08d385