Evalscript with filterScenes function (specific one image per month)

Hello all, I am currently working with this script. With the help of this script I want to obtain one image per month let’s say for the last 1 or may be 10 years. I am using the code mentioned below but unable to achieve the desired result. Can anyone please help me?

curl -X POST https://services.sentinel-hub.com/api/v1/process 
 -H 'Content-Type : application/json'
 -H 'Authorization: Bearer <your access token>' 
 -d '{
  "input": {
    "bounds": {
      "bbox": [
        -17.628331,
        14.554343,
        -17.171647,
        14.922227
      ]
    },
    "data": [
      {
        "dataFilter": {
          "timeRange": {
            "from": "2021-01-01T00:00:00Z",
            "to": "2021-12-30T23:59:59Z"
          }
        },
        "type": "sentinel-1-grd",
        "id": "S1GRD"
      },
      {
        "dataFilter": {
          "timeRange": {
            "from": "2021-01-01T00:00:00Z",
            "to": "2021-12-30T23:59:59Z"
          },
          "maxCloudCoverage": 10
        },
        "type": "sentinel-2-l2a",
        "id": "S2L2A"
      }
    ]
  },
  "output": {
    "width": 512,
    "height": 426.118,
    "responses": [
      {
        "identifier": "default",
        "format": {
          "type": "image/jpeg"
        }
      }
    ]
  },
  "evalscript": "//VERSION=3\n//Author: Regione del Veneto\n\nfunction setup() {\n    return {\n        input: [\n            {datasource: \"S1GRD\", bands:[\"VV\", \"VH\"], orthorectify:\"TRUE\"},\n            {datasource: \"S2L2A\", bands:[\"B02\", \"B03\", \"B04\", \"B08\",\"B11\",\"B12\"]}\n        ],\n        output: [\n            { id: \"default\", bands: 3}\n        ]\n    };\n}\n

function filterScenes(availableScenes, inputMetadata){\n    availableScenes.sort((s1, s2) => s1.date - s2.date); // sort the scenes by dates in ascending order\n    previousSceneMonth = availableScenes[0].date.getMonth()-1\n    return availableScenes.filter(function (scene) {\n        if (scene.date.getMonth() != previousSceneMonth ){\n            previousSceneMonth=scene.date.getMonth();\n            return true;\n        } else return false;\n    });\n}\n

function evaluatePixel(samples) {\n\n    // Setting the samples for Sentinel-1 and Sentinel-2 products\n\n    let S1 = samples.S1GRD[0]\n    let S2 = samples.S2L2A[0]\n    \n    //Computing the indices for image classification\n\n    // Normalized Difference Vegetation Index\n\n    let ndvi = index(S2.B08,S2.B04)\n    // Modified Normalized Difference Water Index\n\n    let mndwi = index(S2.B03,S2.B12)\n    // Bare Soil Index\n\n    let bsi = ((S2.B11 + S2.B04) - (S2.B08 + S2.B02)) / ((S2.B11 + S2.B04) + (S2.B08 + S2.B02))\n    // (NEW) Modified Normalized Difference Sand Index\n\n    let mndsi = index(S2.B04,S2.B02)\n\n    //Setting threshold values for image classification\n\n    // Extracts built-up areas in white\n\n    if (S1.VH > 0.2 || S1.VV > 0.2) {\n        return {\n            default: [1,1,1]\n        }}\n    // Extracts shrub and grassland in ~yellow\n\n    if (ndvi > 0.2 && ndvi < 0.4) {\n        return {\n            default: [0.9,0.9,0]\n        }}\n    // Extracts flourishing vegetation in ~green\n\n    if (ndvi >= 0.4) {\n        return {\n            default: [0.2,0.75,0]\n        }}\n    // Extracts water bodies in ~blue\n\n    if (mndwi > 0 && S1.VH < 0.015) {\n        return {\n            default: [0,0,0.75]\n        }}\n    // Extracts bare soils in ~red\n\n    if (bsi > 0.2) {\n        return {\n            default: [0.75,0,0]\n        }}\n    // Extracts sand surface in ~orange\n\n    if (mndsi > 0.1) {\n        return {\n            default: [1,0.65,0]\n        }}\n    // Leave in black unclassified pixels\n\n    else{\n    return {\n      default: [0,0,0]\n    }}\n}"
}'

Hi @sentinelhubnew ,

We have an example in the documentation. I hope it would help.

Best Regards

I am following the same example but still unable to achieve the desired result

Hi @sentinelhubnew ,

In order to better help you, could you please explain a bit more on what problem you encountered also the error message. Thank you.

Best Regards

Hello, thanks for the reply. I am not getting an error exactly. I am using this custom script https://custom-scripts.sentinel-hub.com/data-fusion/sand-oriented_land_cover_classification_s1_s2/# which has a data fusion request and I am also using the function filterScenes so that I can get 1 image per month for a specific period of time i-e let’s say 10 years (1 image per month). I am unable to get the result I want. Could you please guide me properly where I have made mistake.
Thanks

Hi @sentinelhubnew ,

To get one image per month we recommend preProcessScenes as filterScenes is deprecated.

I quickly prepared an example to show how you could have the first scene per month of your selected time range in the evaluatePixel function.

//VERSION=3

function setup() {
    return {
        input: [
            {datasource: "S1GRD", bands:["VV", "VH"], orthorectify:"TRUE"},
            {datasource: "S2L2A", bands:["B02", "B03", "B04", "B08","B11","B12"]}
        ],
        output: [
            { id: "default", bands: 3}
        ],
        mosaicking: "TILE"
    };
}

function preProcessScenes (collections) {
    collection_s1 = collections.S1GRD
    collection_s2 = collections.S2L2A
    // select the first scene of each month for s1grd
    collection_s1.scenes.tiles.sort(function (s1, s2) {
            var date1 = new Date(s1.date);
            var date2 = new Date(s2.date);
            return date1 - date2}) // sort the scenes by dateFrom in ascending order

    firstTileDate_s1 = new Date(collection_s1.scenes.tiles[0].date)
    var previousTileMonth_s1 = firstTileDate_s1.getMonth() - 1
    collection_s1.scenes.tiles = collection_s1.scenes.tiles.filter(function (scene) {
        var currentTileDate_s1 = new Date(scene.date)
        if (currentTileDate_s1.getMonth() != previousTileMonth_s1){
            previousTileMonth_s1 = currentTileDate_s1.getMonth();
            return true;
        } else return false;
    })
    // select the first scene of each month for s2l2a
    collection_s2.scenes.tiles.sort(function (s1, s2) {
            var date1 = new Date(s1.date);
            var date2 = new Date(s2.date);
            return date1 - date2}) // sort the scenes by dateFrom in ascending order

    firstTileDate_s2 = new Date(collection_s2.scenes.tiles[0].date)
    var previousTileMonth_s2 = firstTileDate_s2.getMonth() - 1
    collection_s2.scenes.tiles = collection_s2.scenes.tiles.filter(function (scene) {
        var currentTileDate_s2 = new Date(scene.date)
        if (currentTileDate_s2.getMonth() != previousTileMonth_s2){
            previousTileMonth_s2 = currentTileDate_s2.getMonth();
            return true;
        } else return false;
    })
    // update collections
    collections.S1GRD = collection_s1
    collections.S2L2A = collection_s2
    return collections
}

function evaluatePixel(samples) {

    //samples.S1GRD and samples.S2L2A contain one scene per month in the selected time range, 
    //select the one you're interested in
    let S1 = samples.S1GRD[0]
    let S2 = samples.S2L2A[0]
    
    //Computing the indices for image classification

    // Normalized Difference Vegetation Index

    let ndvi = index(S2.B08,S2.B04)
    // Modified Normalized Difference Water Index

    let mndwi = index(S2.B03,S2.B12)
    // Bare Soil Index

    let bsi = ((S2.B11 + S2.B04) - (S2.B08 + S2.B02)) / ((S2.B11 + S2.B04) + (S2.B08 + S2.B02))
    // (NEW) Modified Normalized Difference Sand Index

    let mndsi = index(S2.B04,S2.B02)

    //Setting threshold values for image classification

    // Extracts built-up areas in white

    if (S1.VH > 0.2 || S1.VV > 0.2) {
        return {
            default: [1,1,1]
        }}
    // Extracts shrub and grassland in ~yellow

    if (ndvi > 0.2 && ndvi < 0.4) {
        return {
            default: [0.9,0.9,0]
        }}
    // Extracts flourishing vegetation in ~green

    if (ndvi >= 0.4) {
        return {
            default: [0.2,0.75,0]
        }}
    // Extracts water bodies in ~blue

    if (mndwi > 0 && S1.VH < 0.015) {
        return {
            default: [0,0,0.75]
        }}
    // Extracts bare soils in ~red

    if (bsi > 0.2) {
        return {
            default: [0.75,0,0]
        }}
    // Extracts sand surface in ~orange

    if (mndsi > 0.1) {
        return {
            default: [1,0.65,0]
        }}
    // Leave in black unclassified pixels

    else{
    return {
      default: [0,0,0]
    }}
}

NOTE that the evaluatePixel function in the example only takes the first scene of the first month in the time range. You may want to adjust the evaluatePixel function to get all results at once.

An example would be the following:

function evaluatePixel(samples) {
  // Precompute an array to contain NDVI observations
  var n_observations = samples.length;
  let ndvi = new Array(n_observations).fill(0);
  
  // Fill the array with NDVI values
  samples.forEach((sample, index) => {
    ndvi[index] = (sample.B08 - sample.B04) / (sample.B08 + sample.B04) ;
  });
                     
  return ndvi;

Let me know if you have further questions.

Best Regards

Hey chung.horng, thanks for the reply. I really appreciate your help.