Tracking Radar Vegetation Index (Agriculture Development) Script

//VERSION=3 (auto-converted from 1)

function setup() {
    return {
        input: [
            {
                bands: ["VV", "VH", "dataMask"],
            },
        ],
        output: { bands: 3 },
        mosaicking: "ORBIT",
    };
}

function calcRVI(sample) {
    var denom = sample.VH * 2 + sample.VV * 2;
    return denom != 0 ? (sample.VH * 8) / denom : 0.0;
}
function stretch(val, min, max) {
    return (val - min) / (max - min);
}

function evaluatePixel(samples, scenes) {
    var avg1 = 0.2;
    var count1 = 0;
    var avg2 = 0.2;
    var count2 = 0;
    var avg3 = 0.2;
    var count3 = 0;
    var endMonth = scenes[0].date.getMonth();

    for (var i = 0; i < samples.length; i++) {
        if (samples[i].dataMask == 0) continue;
        var rvi = calcRVI(samples[i]);
        if (scenes[i].date.getMonth() == endMonth) {
            avg3 = avg3 + rvi;
            count3++;
        } else if (scenes[i].date.getMonth() == endMonth - 1) {
            avg2 = avg2 + rvi;
            count2++;
        } else {
            avg1 = avg1 + rvi;
            count1++;
        }
    }
    avg1 = avg1 / count1;
    avg2 = avg2 / count2;
    avg3 = avg3 / count3;
    avg1 = stretch(avg1, 0.25, 0.75);
    avg2 = stretch(avg2, 0.25, 0.75);
    avg3 = stretch(avg3, 0.25, 0.75);

    return [avg1, avg2, avg3];
}

function preProcessScenes(collections) {
    collections.scenes.orbits = collections.scenes.orbits.filter(function (
        orbit
    ) {
        var orbitDateFrom = new Date(orbit.dateFrom);
        return (
            orbitDateFrom.getTime() >=
            collections.to.getTime() - 3 * 31 * 24 * 3600 * 1000
        );
    });
    return collections;
}

Evaluate and Visualize

General description of the script

The script analyses and compares the RVI values using all available radar images. The script calculates the average RVI for the current and previous 2 months and takes the current image as the reference.

Details of the script

The script works best in lowland areas during active vegetation periods. In addition to terrain mismatches in highlands, other image distortions are possible, that are probably related to satellite orbit and image acquisition mode changes (also regarding Linear to Db problems?).

Images can be over-saturated during prolonged periods of drought/floods and no vegetation change (mostly winter). Usually best idea is to select the reference date in the end of the month and sometimes the date should be changed to better fit the available images (due to change of orbits and acquisition schemes).

Crop properties and VV/VH radar signal limitations have impact on RVI sensitivity (author’s understanding is that soybeans are best targets).

It is definitely beneficial to tinker with the pixel evaluation, and value stretch settings, as well as the time-frame of analysis.

Some output images.

Author of the script

Valters Zeizis

Description of representative images

In the image you can see agriculture fields around Yeya river, Krasnodar region, Russia.

Under the current settings the images would be colored based on the Change of RV (increase, stable, decrease), so:

  • black/dark and white/grey areas are where the index is stable, like water (low RVI) or forests (high RVI)
  • blue/light blue areas indicate increasing crop growth
  • green/yellow areas indicate ripening or ripe crops
  • orange/red areas indicate areas of harvested areas

The script example

Credits and references

[1] The script is made using Sentinel-2 Agricultural growth stage script by Harel Dan and posted on Twitter.

[2] Some ideas were also gathered in SNAP/STEP forums.

[3] ResearchGate, Radar Vegetation Index as an Alternative to NDVI for Monitoring of Soyabean and Cotton.

[4] MDPI, Sensitivity of Sentinel-1 Backscatter to Vegetation Dynamics: An Austrian Case Study.