GRASS logo

NAME

t.crop.stage - Estimates per-pixel crop growth stage (A-E) from an NDVI space time raster dataset.

KEYWORDS

temporal, raster, NDVI, crop, phenology, time

SYNOPSIS

t.crop.stage
t.crop.stage --help
t.crop.stage [-e] input=name output=name [where=sql_query] [upper_percentile=float] [min_peak_ndvi=float] [lower_threshold=float] [min_peak_width=integer] [min_observations=integer] [measurement_noise=float] [process_noise_level=float] [process_noise_velocity=float] [nprocs=integer] [--overwrite] [--help] [--verbose] [--quiet] [--ui]

Flags:

-e
Also write extended output maps (velocity, value, days since peak, upper threshold)
--overwrite
Allow output files to overwrite existing files
--help
Print usage summary
--verbose
Verbose module output
--quiet
Quiet module output
--ui
Force launching GUI dialog

Parameters:

input=name [required]
Name of the input NDVI space time raster dataset
output=name [required]
Name for output crop stage raster map (categories: 1=A 2=B 3=C 4=D 5=E)
where=sql_query
WHERE conditions of SQL statement without 'where' keyword used in the temporal GIS framework
Example: start_time > '2001-01-01 12:30:00'
upper_percentile=float
Percentile of each pixel's NDVI series used as the adaptive peak threshold
Options: 0-100
Default: 90.0
min_peak_ndvi=float
Hard floor for the adaptive peak (upper) threshold
Default: 0.50
lower_threshold=float
Fixed lower NDVI threshold separating bare soil/residue from vegetated stages
Default: 0.35
min_peak_width=integer
Minimum consecutive days above the upper threshold to confirm a genuine seasonal peak
Default: 5
min_observations=integer
Minimum length (days) of the smoothed daily series for a reliable estimate
Default: 30
measurement_noise=float
Kalman filter observation noise variance
Default: 0.005
process_noise_level=float
Kalman filter process noise for the NDVI level state
Default: 0.001
process_noise_velocity=float
Kalman filter process noise for the NDVI velocity state
Default: 0.0001
nprocs=integer
Number of parallel processes for per-pixel estimation
Default: 1

Table of contents

DESCRIPTION

t.crop.stage estimates the current crop growth stage, per pixel, from an NDVI space time raster dataset (STRDS) using a crop-agnostic, curve-relative model. Most row crops and vegetables follow a similar NDVI trajectory over a growing season — a rise to peak vegetative vigor followed by senescence — so a single curve-relative model can locate "where on the curve" a given pixel currently sits, without crop-specific calibration.

The output is a single classified raster map with five generic stages:

CategoryStageDescription
1ABare soil / planting / emergence
2BGreenup / rapid growth
3CPeak maturity
4DSenescence
5EPost-harvest / residue / bare soil

Pixels whose NDVI series is too short or too sparse (fewer than min_observations days once resampled to a daily grid) are left NULL in the output.

For each pixel, the maps registered in the input STRDS (optionally filtered with where) are read in the current computational region, resampled to a daily grid, gap-filled with PCHIP interpolation, and smoothed with a Whittaker filter. The stage of the last observation is then decided from three signals:

SignalDescription
NDVI levelPosition relative to the adaptive lower_threshold / upper (peak) threshold
TrendRising or falling, estimated with a Kalman filter
Peak historyWhether a genuine seasonal peak has already been confirmed
StageNDVI levelTrendPeak confirmed
Abelow lower thresholdanyno
Bbetween thresholdsrisingno
Cat/above upper thresholdany
Dbetween thresholdsfallingyes
Ebelow lower thresholdanyyes

The upper (peak) threshold is derived per pixel as max(percentile(NDVI, upper_percentile), min_peak_ndvi); a peak only counts as "confirmed" once the pixel stays above it for at least min_peak_width consecutive days (guards against noise spikes).

With the -e flag, four additional DCELL maps are written alongside output:

NOTES

EXAMPLES

Set the region to the input STRDS and classify crop stage:

t.crop.stage input=ndvi_strds output=crop_stage
r.category map=crop_stage

Restrict to a temporal subset and also write the extended diagnostic maps:

t.crop.stage input=ndvi_strds output=crop_stage_2026 \
  where="start_time >= '2026-01-01'" -e nprocs=4

Use custom thresholds for a low-vigor crop:

t.crop.stage input=ndvi_strds output=crop_stage \
  lower_threshold=0.25 min_peak_ndvi=0.40 upper_percentile=85

SEE ALSO

r.category, t.rast.list, t.rast.series, t.info

AUTHORS

Yann Chemin

Crop stage model adapted from crop-stage-detection by Ran Pelta (Agmatix / GrowersTech, NASA Harvest).

SOURCE CODE

Available at: t.crop.stage source code (history)

Accessed: Sunday Sep 13 08:29:33 2026


Main index | Temporal index | Topics index | Keywords index | Graphical index | Full index

© 2003-2026 GRASS Development Team, GRASS 8.5.1dev Reference Manual