Remote Sensing · Sentinel-2 · Precision Agriculture

From Raw Satellite Pixels to a Working NDVI Alert Pipeline

A production walkthrough of Sentinel-2 L2A acquisition, cloud masking, median composites, crop-stress detection, spatial cross-validation, and alert delivery.

Tahira SiddiqueFounder & Head of Spatial Science, AI & ML22 min read
NDVI satellite alert pipeline workflow architecture diagram
← Back to Blog

A cooperative managing 12,000 acres across 47 commercial farms came to us with a direct operational bottleneck: field scouts spent three days a week driving between distant parcels, and visible crop stress often meant yield damage was already irreversible. They needed a way to prioritize scouting before symptoms became visible to the naked eye.

Within 48 hours of kickoff, we deployed an end-to-end automated pipeline delivering parcel-level NDVI anomaly alerts. This is the technical walkthrough: the physical choices, processing patterns, validation design, and lessons learned.

Core Principle

Raw satellite pixels become actionable only when sensor physics, atmospheric corrections, crop phenology, and decision workflows are engineered as one cohesive system.


1. Acquire Sentinel-2 Level-2A Imagery

Sentinel-2 provides multispectral observations with Band 4 (red) and Band 8 (near-infrared) at 10 m spatial resolution. We strictly use Level-2A products because bottom-of-atmosphere (BOA) surface reflectance eliminates atmospheric path radiance variations when comparing vegetation through time.

Modern data access uses the Copernicus Data Space Ecosystem openEO client:

import openeo

connection = openeo.connect("openeo.dataspace.copernicus.eu").authenticate_oidc()

cube = connection.load_collection(
    "SENTINEL2_L2A",
    spatial_extent={"west": 73.70, "south": 31.00, "east": 74.55, "north": 31.70},
    temporal_extent=["2025-04-01", "2025-07-15"],
    bands=["B04", "B08", "SCL"],
    max_cloud_cover=20,
)

2. Mask Cloud, Cirrus, Snow, and Shadow with SCL

Cloud contamination is the fastest way to destroy trust in an automated NDVI system. The Sentinel-2 Level-2A Scene Classification Layer (SCL) identifies clouds, cirrus, and cloud shadows.

import numpy as np
import rasterio
from rasterio.enums import Resampling

def load_masked_bands(scl_path, red_path, nir_path):
    with rasterio.open(scl_path) as src:
        scl = src.read(1, out_shape=(src.height * 2, src.width * 2), resampling=Resampling.nearest)

    valid = np.isin(scl, [4, 5])  # Vegetation and bare soil only

    with rasterio.open(red_path) as red_src, rasterio.open(nir_path) as nir_src:
        red = red_src.read(1).astype("float32")
        nir = nir_src.read(1).astype("float32")

    red[~valid] = np.nan
    nir[~valid] = np.nan
    return red, nir, valid
⚠ Cloud Shadow Is Not a Minor Edge Case

When an initial pass excluded clouds but forgot cloud shadow (SCL Class 3), affected canopy pixels dropped by ~0.15 NDVI units, generating spurious alerts. Masking shadows is mandatory for production reliability.

3. Use Robust Temporal Composites

A composite compresses multiple acquisitions into one clean value per pixel. We use a 30-day median composite requiring at least 4 valid cloud-free observations.

Interactive Comparison · Compositing Method

Cloud RobustnessHigh
Shadow RobustnessHigh
Phenology BiasNone
Output NoiseLow
0.30.50.70.9Apr 5Apr 22May 9May 28Jun 14Jul 1Jul 16
Current Observation Historical Baseline

Median tracks the seasonal curve while resisting residual values at both tails.

def median_composite(ndvi_stack, min_observations=4):
    valid_count = np.sum(~np.isnan(ndvi_stack), axis=0)
    composite = np.nanmedian(ndvi_stack, axis=0)
    composite[valid_count < min_observations] = np.nan
    return composite, valid_count

4. Compute NDVI & Compare with Crop-Stage Baselines

NDVI is calculated as (NIR − Red) / (NIR + Red). Rather than using brittle static cutoffs, we calculate standardized z-scores against historical phenological medians for each crop variety.

z_score = (current_ndvi - historical_median) / historical_std
alert_mask = z_score < -1.5  # Flag anomalies 1.5 standard deviations below normal

Interactive Teaching Model · Alert Sensitivity

0.30.50.70.9Apr 5Apr 22May 9May 28Jun 14Jul 1Jul 16
Current Observation Historical Baseline Alert Threshold
No alert: observations remain within the 1.5σ normal phenological envelope.

5. Add a Lightweight CNN for Change Detection

We pair NDVI thresholding with a compact PyTorch CNN trained on multispectral 64×64 patches. Farm-level spatial cross-validation guarantees the model generalizes across unvisited parcels.

import torch.nn as nn

class CropStressCNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.encoder = nn.Sequential(
            nn.Conv2d(6, 32, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
            nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
            nn.Conv2d(64, 64, 3, padding=1), nn.ReLU(),
            nn.AdaptiveAvgPool2d(1),
        )
        self.head = nn.Sequential(
            nn.Flatten(), nn.Linear(64, 32), nn.ReLU(),
            nn.Linear(32, 1), nn.Sigmoid(),
        )

    def forward(self, inputs):
        return self.head(self.encoder(inputs))

6. Deliver Alerts Inside the Field Workflow

Detection has no operational value if it stays trapped in a desktop GIS layer. The pipeline posts alerts to mobile push notifications and field management systems within 8 minutes of satellite scene ingest.

from firebase_admin import messaging

def send_alert(field_id, z_score, stress_probability, device_token):
    severity = "SEVERE" if z_score < -2.0 else "MODERATE"
    message = messaging.Message(
        notification=messaging.Notification(
            title=f"{severity}: Inspect Field {field_id}",
            body=f"NDVI is {abs(z_score):.1f}σ below baseline (confidence {stress_probability:.0%}).",
        ),
        data={"field_id": field_id, "event": "crop_stress_review"},
        token=device_token,
    )
    return messaging.send(message)

Field Results & Operational Impact

47 Farms
12,000 acres monitored
91.8%
Agronomist-validated recall
5.9%
False positive alert rate
14 Days
Mean lead time before symptoms
18%
Documented crop loss reduction
< 8 min
Ingest to push notification

Deploy Remote Sensing in Production

Build Automated Satellite Alert Pipelines

Infryne TechWorks develops end-to-end satellite computer vision, change detection, and precision agriculture pipelines from raw pixels to operational APIs.

Primary Sources

Related Infryne Articles