Forest Health Indices

Calculate vegetation indices (NDVI, NDMI, NBR, EVI) from Sentinel-2 satellite imagery to monitor forest health, detect drought stress, and identify burn areas.

Published
docker pull public.ecr.aws/m33/forest-indices:latest
Compatible with: sentinel-2 landsat-8 landsat-9

Overview

The Forest Health Indices pattern calculates four key spectral vegetation indices from Sentinel-2 multispectral satellite imagery. These indices are essential for monitoring forest health, detecting drought stress, identifying wildfire damage, and tracking vegetation changes over time.

Indices Calculated

NDVI (Normalized Difference Vegetation Index)

The most widely used vegetation index. Measures photosynthetic activity and vegetation density.

NDVI = (NIR - Red) / (NIR + Red)
     = (B08 - B04) / (B08 + B04)
NDVI Value Interpretation
-1.0 to 0 Water, snow, clouds, bare soil
0 to 0.2 Barren rock, sand, or dead vegetation
0.2 to 0.4 Sparse vegetation, shrubs, grassland
0.4 to 0.6 Moderate vegetation
0.6 to 1.0 Dense, healthy vegetation

NDMI (Normalized Difference Moisture Index)

Detects vegetation water content and drought stress. Useful for early detection of water stress before visible symptoms appear.

NDMI = (NIR - SWIR1) / (NIR + SWIR1)
     = (B08 - B11) / (B08 + B11)
NDMI Value Interpretation
-1.0 to 0 Bare soil, very dry vegetation
0 to 0.2 Water-stressed vegetation
0.2 to 0.4 Moderate moisture levels
0.4 to 1.0 High vegetation water content

NBR (Normalized Burn Ratio)

Identifies burned areas and assesses burn severity. Essential for wildfire monitoring and post-fire recovery tracking.

NBR = (NIR - SWIR2) / (NIR + SWIR2)
    = (B08 - B12) / (B08 + B12)
NBR Value Interpretation
-0.5 to -0.1 High burn severity
-0.1 to 0.1 Moderate burn severity
0.1 to 0.27 Low burn severity
0.27 to 0.66 Unburned vegetation

For change detection, calculate dNBR = pre-fire NBR - post-fire NBR

EVI (Enhanced Vegetation Index)

Improved version of NDVI that reduces atmospheric interference and soil background effects. More accurate in high-biomass regions.

EVI = 2.5 × ((NIR - Red) / (NIR + 6×Red - 7.5×Blue + 1))
    = 2.5 × ((B08 - B04) / (B08 + 6×B04 - 7.5×B02 + 1))

EVI ranges from -1 to 1, with similar interpretation to NDVI but less saturation in dense vegetation.

Usage

Pull the Task Image

fabric image pull forest-indices

Basic Usage

Calculate all four indices from Sentinel-2 data:

fabric task run forest-indices \
  --input-dir ./sentinel2_bands/ \
  --output-dir ./results/

Calculate Specific Indices

Only calculate NDVI and NDMI:

fabric task run forest-indices \
  --input-dir ./sentinel2_bands/ \
  --output-dir ./results/ \
  --indices "NDVI,NDMI"

In a Pipeline

tasks:
    calculate-indices:
        image: public.ecr.aws/m33/forest-indices:latest
        depends_on:
            - download-imagery
        inputs:
            input_dir: "{{ tasks.download-imagery.outputs.data_dir }}"
            output_dir: /data/indices
            indices: ["NDVI", "NDMI", "NBR", "EVI"]

Input Requirements

Band Files

The task automatically detects band files with flexible naming:

# Supported naming patterns:
B04.tif
B04_10m.tif
T32TQM_20240715T103031_B04_10m.tif

Directory Structure

input_dir/
├── B02.tif      # Blue (10m) - required for EVI
├── B04.tif      # Red (10m)
├── B08.tif      # NIR (10m)
├── B11.tif      # SWIR1 (20m) - auto-resampled to 10m
└── B12.tif      # SWIR2 (20m) - auto-resampled to 10m

Output

Output Files

Each index is saved as a GeoTIFF with preserved spatial metadata:

output_dir/
├── ndvi.tif     # Values: -1 to 1
├── ndmi.tif     # Values: -1 to 1
├── nbr.tif      # Values: -1 to 1
└── evi.tif      # Values: -1 to 1

Output Properties

  • Format: GeoTIFF with LZW compression
  • Resolution: 10m (20m bands automatically resampled)
  • CRS: Preserved from input
  • NoData: -9999

Visualization

In QGIS

  1. Open the output .tif file
  2. Right-click layer → Properties → Symbology
  3. Set render type to "Singleband pseudocolor"
  4. Set min/max to -1 and 1
  5. Choose color ramp: RdYlGn (Red-Yellow-Green)

Recommended Color Scales

Index Color Ramp Min Max
NDVI RdYlGn -0.2 0.8
NDMI BrBG -0.3 0.5
NBR RdYlBu -0.5 0.7
EVI RdYlGn -0.2 0.8

Performance

  • Processing time: ~30 seconds per 100 km² at 10m resolution
  • Memory usage: ~2 GB peak for typical scenes
  • Docker image size: 450 MB

Use Cases

Drought Monitoring

Track NDMI over time to detect early signs of water stress:

# Process multiple dates
for date in 2026-01 2026-02 2026-03; do
  fabric task run forest-indices \
    --input-dir ./sentinel2_${date}/ \
    --output-dir ./timeseries/${date}/
done

Wildfire Assessment

Calculate pre- and post-fire NBR to assess burn severity:

# Pre-fire baseline
fabric task run forest-indices \
  --input-dir ./pre_fire/ \
  --output-dir ./pre_fire_indices/ \
  --indices "NBR"

# Post-fire assessment
fabric task run forest-indices \
  --input-dir ./post_fire/ \
  --output-dir ./post_fire_indices/ \
  --indices "NBR"

# dNBR = pre_NBR - post_NBR (calculate in QGIS or Python)

Forest Health Baseline

Create a comprehensive baseline of forest conditions:

fabric run forest-monitoring \
  --input-study_area "Black Forest, Germany" \
  --input-date_range "2026-06-01/2026-06-30" \
  --input-indices "NDVI,NDMI,NBR,EVI"

Related

Required Bands

Band ID Name Resolution Purpose
B02 Blue 10m Visible blue band for EVI calculation
B04 Red 10m Visible red band for vegetation indices
B08 NIR 10m Near-infrared for vegetation health
B11 SWIR1 20m Short-wave infrared for moisture content
B12 SWIR2 20m Short-wave infrared for burn detection