Multi Temporal script in EO Browser

Hello,

I would like to know if it is possible to run multi temporal script in EO browser ?

I know it is possible in Playground adding “-temporal”. Just would like to know for EO broswer.

Thanks a lot.
Camille

Hey @camille.bay,

since a while this is indeed also possible in EO Browser.

Chapter 3. Multitemporal Scripting in this blog post describs the steps you have to follow to get it working :wink:

Best,
dthiex

1 Like

Hey,

thanks a lot ! So I modified what is needed in the function setup.

I would like to use the script: Forest_cut_temporal_detection

https://github.com/sentinel-hub/custom-scripts/blob/master/sentinel-2/forest_cut_temporal_detection/script.js

I am not sure to understand how to set Timespan…

DESCIRPTION of the script

In order to map forest cutting from one year to another, this script compares:

  • the mean ndvi of the three previous months from the selected image
  • to the mean ndvi of the three same months but from the previous year

I should set Timespan just with the three months of the year or all the period (1 year and three months) ?

With Playground, the script just catchs the date of the displayed image and run.

Thanks a lot for the help.

Camille

Hey,

the timespan should be the whole period, but it can also be even longer than needed.
If I understand the script correctly, the important date is the later date (the end of the timespan) as it then goes back from that date to the previous year. This means that the beginning of the timespan can be even earlier than 1 year and three months before the end of the timespan, if you want to be extra sure. Although this can then use up more processing units.

Hope this helps.
Ziga

1 Like

Thanks a lot ! :slight_smile:

I tried but the results are differents… I have to investigate

Hi all,

I don’t have the same results between Playground ans EO browser. I think it is how I set Timespan…

Someone konw how to properly set it ?

thanks

I believe Playground takes by default a period of 6 months, unless you shorten it. Playground also sets the MAXCC parameter, based on your “cloud filter slider” setting.
Can you post a link to Playground and EO Browser examples, so that we look what is happening in back-end.
Alternatively you can do this yourself by opening Debugger and check the requests going to Sentinel Hub in one and another example.

here for Playground (18 October 2018)

here EO broswer with Timespan (18 October 2017 - 18 October 2018)

Here the script:

//VERSION=3 (auto-converted from 1)
// Minimum difference between the two mean NDVIs
var thresold = 0.25;
// Thresold to dismiss clouds to calculate the mean
var blueThresold = 0.18;
// Minimum mean NDVI to consider for month(s) of last year
var minimunNDVI = 0.7;
// to normalize colormap
var stretchMin = 0;
var stretchMax = 0.8;

function setup() {
  return {
    input: [{
      bands: [
          "B02",
          "B03",
          "B04",
          "B05",
          "B08",
          "B12"
      ]
    }],
    
    mosaicking: Mosaicking.ORBIT,
    output: { bands: 3 },
    
  }
}


function stretch(val, min, max) {
    return (val - min) / (max - min);
}


function NDVI(sample) {
    let denom = sample.B08 + sample.B04;
    return ((denom != 0) ? (sample.B08 - sample.B04) / denom : 0.0);
}

function NDWI(sample) {
    let denom = sample.B03 + sample.B08;
    return ((denom != 0) ? (sample.B03 - sample.B08) / denom : -1);
}

function mean(array) {
    if (array.length == 0) {
        return 1
    } else {
        var sum = 0;
        for (var i = 0; i < array.length; i++) {
            sum += parseFloat(array[i]); //don't forget to add the base
        }

        var avg = sum / array.length;
        return avg
    }
}

// Manage overlapping years.
// If january is selected and user need 2 months to take
// script needs to take december from last year as second month.
function getNeededDates(sceneMonth, sceneYear, monthsToTake) {
    let monthToGet = [];
    let yearToGet = [];

    for (i = 0; i < monthsToTake; i++) {
        if (sceneMonth - i <= 0) {
            month = 12 - (sceneMonth - i);
            year = sceneYear - 1;
        } else {
            month = sceneMonth - i;
            year = sceneYear;
        }
        monthToGet.push(month);
        yearToGet.push(year);
    }

    return [monthToGet, yearToGet];
}

function evaluatePixel(samples, scenes) {
    let initMonth = scenes[0].date.getMonth();
    let initYear = scenes[0].date.getFullYear();

    let monthsAndYears = getNeededDates(initMonth, initYear, 3);

    let currentYearNDVI = 0;
    let currentYearCount = 0;

    let previousYearNDVI = 0;
    let previousYearCount = 0;
    let lastYearMonth0 = [];
    let lastYearMonth1 = [];
    let lastYearMonth2 = [];

    for (i = 0; i < samples.length; i++) {
        if (!(samples[i].B04 == 0) & !(samples[i].B03 == 0)) {
            sceneMonth = scenes[i].date.getMonth();
            sceneYear = scenes[i].date.getFullYear();
            if (monthsAndYears[0].includes(sceneMonth)) {
                if (samples[i].B02 < blueThresold) {
                    ndvi = NDVI(samples[i]);
                    if (monthsAndYears[1].includes(sceneYear))
                    // if current year (last 12 months max)
                    {
                        currentYearNDVI = currentYearNDVI + ndvi;
                        currentYearCount++;

                    }
                    // if year before
                    else if (monthsAndYears[1].includes(sceneYear + 1)) {
                        previousYearNDVI = previousYearNDVI + ndvi;

                        if (monthsAndYears[0][0] == sceneMonth) {
                            lastYearMonth0.push(ndvi);
                        } else if (monthsAndYears[0][1] == sceneMonth) {
                            lastYearMonth1.push(ndvi);
                        } else if (monthsAndYears[0][2] == sceneMonth) {
                            lastYearMonth2.push(ndvi);
                        }
                        previousYearCount++;
                    }
                }
            }
        }
    }

    // compute the mean
    let avgCurrentYearNDVI = currentYearNDVI / currentYearCount;
    let avgPreviousYearNDVI = previousYearNDVI / previousYearCount;

    // if ndvi decreases from defined thresold in the same months from previous year
    // highlights in red the pixel
    // check also if is not water
    let difference = avgPreviousYearNDVI - avgCurrentYearNDVI;

    if ((NDWI(samples[0]) < 0.5) & (difference >= thresold) & (avgPreviousYearNDVI > minimunNDVI) & (mean(lastYearMonth0) > minimunNDVI) & (mean(lastYearMonth1) > minimunNDVI) & (mean(lastYearMonth2) > minimunNDVI)) {
        // the more the difference is high, the more it is red
        colorMap = [stretch((2.8 * (2 / 3) * 10 * difference * samples[0].B04 + 0.1 * samples[0].B05), stretchMin, stretchMax), stretch((2.8 * samples[0].B03 + 0.15 * samples[0].B08), stretchMin, stretchMax), stretch((2.8 * samples[0].B02), stretchMin, stretchMax)];
    }
    // else show current image
    else {
        colorMap = [stretch((2.8 * samples[0].B04 + 0.1 * samples[0].B05), stretchMin, stretchMax), stretch((2.8 * samples[0].B03 + 0.15 * samples[0].B08), stretchMin, stretchMax), stretch((2.8 * samples[0].B02), stretchMin, stretchMax)];
    }
    return colorMap;
}

function filterScenes(scenes, inputMetadata) {
    return scenes.filter(function(scene) {
        return scene.date.getTime() >= (inputMetadata.to.getTime() - (14 * 31 * 24 * 3600 * 1000)); // 14 = 11 months + 3 months
    });
}

What is the procedure to open Debugger ?

Thanks a lot!
Camille

Hi @camille.bay,

there are two differences between processing in Playground and EO Browser in your case:

  • Your script is (filterScenes function, at the end) limited to 14 months of processing. However, the time span set in EO Browser only limits it to 12 months. If you change the time span from August 2017 to October 2018, you will cover the same period as what is executed in Playground.
  • Playground adds (on top of the mentioned filter) also “maximum cloud coverage’” filter, that is set in user interface (slider above the map). So you are essentially only processing scenes with less than 20% cloud coverage in Playground and all of them in EO Browser. If you set the slider to 100% in Sentinel Playground, you will get same results as in EO Browser.

It is currently not possible to set cloud coverage filter in EVALSCRIPT, but we are working to add this as well. That being said, cloud coverage filter works on scene basis, which is usually not good enough. If you want to use cloud cover filtering, we would recommend you use CLM “band” and filter out only the relevant pixels, not the whole scene.

In case you need Debugger the next time, find instructions here.

PS: I have masked out part of the instance ID in the Playground link so that other Forum users cannot use your instance.

Hi @gmilcinski,

thanks a lot for your time and explanations!

Camille