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 variances2(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 ofnand 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 variances2_m2, intercept, per-predictor coefficients, the coefficient covariance matrix, the applied transforms, andmax_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

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