šŸƒQGISIntermediateā±ļø 3 mins read

NDVI Calculation & Vegetation Health Mapping

Published by GISTECHNEWS Editorial Team • Peer-Reviewed & Verified on QGIS 3.34+ LTR & Python 3.10+

The Normalized Difference Vegetation Index (NDVI) is the global benchmark remote sensing index for quantifying photosynthetic vegetation canopy density, agricultural crop vigor, and forestry biomass. Healthy vegetation exhibits a distinct spectral signature: leaf chlorophyll absorbs incoming solar radiation strongly in the visible Red band (~660 nm) for photosynthesis, while the spongy mesophyll cell structure strongly scatters and reflects radiation in the Near-Infrared (NIR) band (~860 nm). By comparing the ratio of absorption to scattering, NDVI isolates live green vegetation from soil, water, and built-up surfaces.

šŸ“‹ Prerequisites

  • QGIS 3.34+ LTR installed.
  • Multispectral satellite scene: Sentinel-2 (B4 Red & B8 NIR) or Landsat 8-9 (B4 Red & B5 NIR).
  • Surface Reflectance (Bottom of Atmosphere - BOA) calibrated imagery.

šŸ› ļø Technical Environment

Required Software: QGIS Raster Calculator / Python (Recommended: QGIS 3.34 LTR)

Practice Dataset: Sentinel-2 L2A Band 4 (Red) & Band 8 (NIR)

Source Portal: ESA Copernicus Data Space

CRS / Format: WGS 84 / UTM (GeoTIFF (10m Resolution))

šŸ“Š Conceptual Technical Diagram: Spectral Reflectance Signatures & NDVI Formulation

The biological mechanism behind the Normalized Difference Vegetation Index (NDVI) comparing healthy vs stressed plant canopy.

Wavelength (Micrometers µm) Reflectance (%) Blue Green Red (B4) Near-Infrared / NIR (B8) Healthy Leaf (High NIR, Low Red) Stressed Canopy NDVI Formula NDVI = (NIR - Red) / (NIR + Red) Healthy Canopy Example: (0.50 - 0.08) / (0.50 + 0.08) = +0.72 Water Body Example: (0.02 - 0.10) / (0.02 + 0.10) = -0.66

Step-by-Step Workflow & Methodological Execution

1

Module 1: The NDVI Mathematical Equation and Band Mapping

The NDVI formula normalizes spectral differences onto a standardized scale from -1.0 to +1.0: $$NDVI = \frac{NIR - Red}{NIR + Red}$$ Band assignments vary across satellite sensors: • Sentinel-2 MSI: Band 8 (NIR, 10m) and Band 4 (Red, 10m). • Landsat 8-9 OLI: Band 5 (NIR, 30m) and Band 4 (Red, 30m). Interpreting the NDVI scale: • -1.0 to 0.0: Deep water, reservoirs, snow, and clouds (water absorbs NIR completely). • 0.0 to 0.2: Bare soil, sand dunes, asphalt, and rock formations. • 0.2 to 0.5: Sparse vegetation, scrubland, senescent crops, and urban lawns. • 0.5 to 0.9: Dense, healthy green canopies, agricultural crops at peak vegetative stage, and tropical rainforests.

2

Module 2: Calculating NDVI with the QGIS Raster Calculator

Execute the calculation directly inside QGIS: 1. Open Raster -> Raster Calculator. 2. Construct Expression: Double-click the raster bands to avoid typo errors. For Sentinel-2: `("sentinel2@8" - "sentinel2@4") / ("sentinel2@8" + "sentinel2@4")` 3. Output Layer: Define output path as `ndvi_sentinel2.tif`. 4. Output Format: Choose GeoTIFF. Verify that the output CRS matches your input bands. 5. Click OK. QGIS processes the floating-point calculation across millions of pixels in seconds.

3

Module 3: Styling Symbology and Generating Crop Stress Maps

Raw NDVI outputs appear as dull grayscale images. Apply professional cartographic styling: 1. Open Layer Properties -> Symbology. 2. Render Type: Change from 'Singleband gray' to 'Singleband pseudocolor'. 3. Color Ramp: Select the standard RdYlGn (Red-Yellow-Green) color ramp. 4. Mode: Set mode to 'Equal Interval' or 'Quantile' with 5 classes: • < 0.1: Red (Bare Soil / Water) • 0.1 - 0.25: Orange (Severe Drought Stress) • 0.25 - 0.45: Yellow (Moderate Vigor) • 0.45 - 0.65: Light Green (Healthy Vegetation) • > 0.65: Dark Forest Green (Vigorous Canopy) 5. Crop Masking: Use Raster -> Extraction -> Clip Raster by Mask Layer to isolate NDVI values strictly inside your agricultural farm boundary.

āš ļø Common Errors & Troubleshooting

āŒ NDVI values fall entirely between 0 and 0.001

šŸ’” Resolution: Check raster data types; if using integer division (e.g. in Python), cast input bands to floating point (float32) prior to arithmetic.

āŒ Clouds appearing as high vegetative values

šŸ’” Resolution: Clouds can introduce saturated values; apply a SCL (Scene Classification Layer) mask to exclude cloud and shadow pixels.

šŸ’” Expert Tips & Best Practices

  • Apply the 'RdYlGn' (Red-Yellow-Green) color ramp with Min = -0.2 and Max = 0.8 for intuitive visual crop health interpretation.
  • Values between 0.2 and 0.5 indicate sparse/moderate shrub vegetation; values >0.6 represent dense agricultural or tropical canopy.

šŸ Python Rasterio & NumPy NDVI Vectorized Calculation

import rasterio
import numpy as np

# Open Sentinel-2 Band 4 (Red) and Band 8 (NIR)
with rasterio.open("B04_Red_10m.jp2") as red_ds:
    red = red_ds.read(1).astype('float32')
    profile = red_ds.profile

with rasterio.open("B08_NIR_10m.jp2") as nir_ds:
    nir = nir_ds.read(1).astype('float32')

# Calculate NDVI with division protection
np.seterr(divide='ignore', invalid='ignore')
ndvi = (nir - red) / (nir + red)

# Clean NaN values
ndvi = np.nan_to_num(ndvi, nan=-9999.0)

# Configure output profile for Cloud-Optimized GeoTIFF
profile.update(
    dtype=rasterio.float32,
    count=1,
    nodata=-9999.0,
    compress='lzw'
)

# Export calculated NDVI GeoTIFF
with rasterio.open("calculated_ndvi.tif", "w", **profile) as dst:
    dst.write(ndvi.astype('float32'), 1)

print("NDVI calculation completed. GeoTIFF successfully saved.")

šŸ”— Related Tutorials & Practical Workflows