14.4 Spectral Indices — NDVI, NDWI, and Friends
Band arithmetic that turns imagery into information — vegetation, water, burns, buildings.
Key takeaways
- Spectral indices combine bands with simple arithmetic to emphasise a specific land-cover property.
- NDVI, NDWI, NBR, NDBI, NDSI are the essential vocabulary.
- Indices are qualitative proxies, not absolute measurements — interpret with context.
Introduction
Much of remote sensing's practical value comes from spectral indices — algebraic combinations of bands that emphasise a specific property. NDVI is the most famous, but dozens exist for vegetation, water, burns, built-up areas, snow, and more. This lesson covers the essential dozen.
NDVI — Normalised Difference Vegetation Index
$$\text{NDVI} = \frac{NIR - Red}{NIR + Red}$$
- Range: −1 to +1.
- Bare soil: ~0.0–0.2.
- Sparse vegetation: 0.2–0.4.
- Dense vegetation: 0.4–0.9.
- Water: negative (NIR absorbed more than red).
Used for:
- Crop health monitoring.
- Drought detection.
- Deforestation tracking.
- Biomass estimation (indirect).
Calculation in Python:
1ndvi = (nir - red) / (nir + red + 1e-6) # epsilon avoids div-by-zero
2ndvi = np.clip(ndvi, -1, 1)NDWI — Normalised Difference Water Index
Two popular versions:
McFeeters (water bodies): $$\text{NDWI} = \frac{Green - NIR}{Green + NIR}$$
Water has high reflectance in green, low in NIR — so NDWI > 0 for water. Used for open water detection.
Gao (vegetation water content): $$\text{NDWI} = \frac{NIR - SWIR}{NIR + SWIR}$$
Higher NDWI_Gao = more water in leaves. Used for drought and vegetation water-stress monitoring.
NBR — Normalised Burn Ratio
$$\text{NBR} = \frac{NIR - SWIR2}{NIR + SWIR2}$$
High NBR = healthy vegetation. Low NBR = burn scar or bare soil.
dNBR (difference NBR) between pre- and post-fire images classifies burn severity:
- Unburned: dNBR < 0.1.
- Low severity: 0.1–0.27.
- Moderate: 0.27–0.66.
- High severity: > 0.66.
NDBI — Normalised Difference Built-up Index
$$\text{NDBI} = \frac{SWIR - NIR}{SWIR + NIR}$$
Built-up areas typically have higher SWIR reflectance than NIR. Useful as part of urban extraction but often combined with NDVI exclusion (built areas have low NDVI too).
NDSI — Normalised Difference Snow Index
$$\text{NDSI} = \frac{Green - SWIR}{Green + SWIR}$$
Snow is bright in visible (green) and dark in SWIR. NDSI > 0.4 typically indicates snow cover.
EVI — Enhanced Vegetation Index
Improves NDVI by reducing atmospheric and soil-background effects:
$$\text{EVI} = G \cdot \frac{NIR - Red}{NIR + C_1 \cdot Red - C_2 \cdot Blue + L}$$
Constants: G = 2.5, C₁ = 6, C₂ = 7.5, L = 1. Used in MODIS vegetation products as a more robust alternative to NDVI, especially in dense vegetation.
SAVI — Soil-Adjusted Vegetation Index
$$\text{SAVI} = \frac{NIR - Red}{NIR + Red + L} (1 + L)$$
With L typically 0.5. Reduces soil-brightness bias in areas with incomplete canopy cover.
BAI — Burned Area Index
$$\text{BAI} = \frac{1}{(0.1 - Red)^2 + (0.06 - NIR)^2}$$
Specifically tuned to highlight charcoal signatures.
When indices fail
All indices have assumptions that break down:
- Shadow can look like water or dense vegetation.
- Cloud edges produce nonsense NDVI values.
- Cloud shadows cause low NDVI that looks like stressed vegetation.
- Soil variability — NDVI means different things over dark soil vs bright soil.
- Nodata — masked-out cells should be excluded from histograms.
Always mask clouds and scene edges before computing indices, and validate against reference data when possible.
Time series
Most indices are best used as time series — a single NDVI value for a field is almost uninformative, while a year of NDVI values reveals planting, growth, harvest, and fallow phases clearly.
1# Monthly NDVI composite
2import xarray as xr
3s2 = xr.open_dataset('s2_cube.nc')
4ndvi_monthly = (s2.nir - s2.red) / (s2.nir + s2.red)
5ndvi_monthly = ndvi_monthly.resample(time='M').median()Google Earth Engine
GEE has one-liner indices:
var ndvi = image.normalizedDifference(['B8', 'B4']).rename('NDVI');Works the same for ['B3','B8'] (NDWI), etc.
Self-check exercises
1. Why are cloud shadows a problem for NDVI time series?
Cloud shadows have low reflectance across all bands, producing low NDVI values that mimic stressed or senescent vegetation. Without masking them, a time series shows spurious dips that drive false detections of drought or disease. Proper cloud masks (Sentinel-2's SCL band, Landsat QA bands, or ML-based masks) are essential before computing indices.
2. You see NDVI values above 1 in your output. What's wrong?
NDVI is mathematically bounded to [−1, +1]. Values outside that range indicate: integer arithmetic truncation (cast to float first), nodata included in the calculation (huge negative sentinels minus normal red values produce unbounded results), or the bands were swapped. Check dtypes, mask nodata, verify band order.
3. Why use dNBR instead of single-date NBR for fire severity mapping?
Pre-fire NBR varies by land cover — a forest has different baseline than a pasture. Single-date post-fire NBR confounds burn intensity with baseline land cover. The difference (dNBR = NBR_before − NBR_after) isolates the change caused by the fire, making severity thresholds meaningful across different landscapes.
Summary
- Spectral indices extract specific information from multispectral imagery.
- NDVI / NDWI / NBR / NDBI / NDSI cover most common uses.
- Indices are proxies — validate with reference data.
- Time series reveal phenology and change better than single dates.
Further reading
- Huete, A. — A Soil-Adjusted Vegetation Index (SAVI).
- Key, C. H. & Benson, N. C. — Landscape Assessment: Fire Severity with Normalized Burn Ratio.
- McFeeters, S. K. — The use of NDWI in the delineation of open water features.
- Index DataBase (IDB) — encyclopedic list of spectral indices.