Google Earth Engine – Creating Image Lists and Saving in a Loop After Adding Band

google-earth-enginegoogle-earth-engine-javascript-api

I have an image collection with many images (>800) and I want to calculate monthly NDVI and NBR median indexes and export the resulting images in a loop.
I
had no problem grouping the images in the same month (in a same year) and calculating NDVI and NBR, but I'm having a really hard time using a loop to export the resulting images with names matching the time period of each one. The "description" and "fileNamePrefix" give some variant of: ee.String({ "type": "Invocation", "arguments": { "date": {.

As I could see, I guess I have to first transform the images in a list and only then pass it through a loop. But I couldn't figure how to populate an empty list with new images (the rationale behind being: for each group of images, I'd calculate the median and add the resulting image to a list).

Here is a "clean" script (the one I'm working in is a mess of chunks of code trying to do what I want…): https://code.earthengine.google.com/?scriptPath=users%2Fthiagorbm%2FCerrado%3AProjetoEEJBB.sentinelV2

I'd like the image names to contain the year and month used to obtain the median values.

I'm new to Earth Engine and don't work very often with it. I'm not even sure I'm taking the best "path" to do what I want.

var vegSHP = ee.Geometry.Polygon(
        [[[-47.93318633174054, -15.923525740817693],
          [-47.84117583369367, -15.948285390673487],
          [-47.79070738886945, -15.876308885443688],
          [-47.83565782221213, -15.84506420705287],
          [-47.90844224604025, -15.867191599980972]]]);

var addNDVI = function(image) {
  var ndvi = ee.Image(0).expression(
    '2.5 * ((NIR - RED) / (NIR + RED))*100', {
      'NIR': image.select('B8'),
      'RED': image.select('B4'),
      
    });//.toUint16();
  return image.addBands(ndvi.rename('ndvi'));
};

var image  = ee.ImageCollection('COPERNICUS/S2')
.filterBounds(vegSHP);

var bandasFiltro= image.select('B.*')
.map(addNDVI);
print(bandasFiltro, "bandasFiltro");

var dates = bandasFiltro
    .map(function(bandasFiltro) {
      return ee.Feature(null, {'date': bandasFiltro
      .date()
      .format('YYYY-MM')});
    })
    .distinct('date')
    .aggregate_array('date');

var bandasFiltroData= bandasFiltro
.filterDate(dates.get(1),dates.get(2)) // pegando o primeiro valor da data e o segundo
.median()
.clip(vegSHP)
.set("periodo", ee.String(dates.get(0)).cat("_").cat(dates.get(2)))

for (var i = 0; i < 4-1; i++){ 
  var inicio= dates.get(i);
  var fim= dates.get(i+1);

  var imgMediana= ee.Image(bandasFiltro
  .filterDate(inicio,fim)
  .median()
  .clip(vegSHP))
  .set("periodo", ee.String(inicio).cat("_").cat(fim));
  //print(imgMediana);

  var id= ee.String("sentinel_2_")
  .cat(inicio).replace("\\-", "")
  .cat("_")
  .cat(fim).replace("\\-", "");
  //print(id)

  Export.image.toDrive({
  image:imgMediana,
  description: id,
  folder: 'ProjetoJBB',
  fileNamePrefix: id,
  region: vegSHP,
  crs: 'EPSG:4326',
  scale: 10,
  maxPixels: 10000000000});

}

Best Answer

Just like @aldo_tapia commented, you're mixing up server- and client-side objects, read through that link. It's not always obvious which arguments needs to be server side and which should be client side. For instance, the description in toDrive() must be client side. Your server-side string does not work there.

I would approach this by iterating over each month, creating a collection of monthly composites. Then create a client-side list of composite dates, using evaluate(), do client side iteration over these dates, pick up the corresponding composite by filtering the collection, and export it. You almost certainly want to mask clouds too, so I included that step too.

var aoi = ee.Geometry.Polygon([[
  [-47.93318633174054, -15.923525740817693],
  [-47.84117583369367, -15.948285390673487],
  [-47.79070738886945, -15.876308885443688],
  [-47.83565782221213, -15.84506420705287],
  [-47.90844224604025, -15.867191599980972]
]])
Map.centerObject(aoi)

var startDate = '2020-05-01'
var endDate = '2021-02-01' // Exclusive
var cloudThreshold = 30

var filter = ee.Filter.and(
  ee.Filter.bounds(aoi),
  ee.Filter.date(startDate, endDate)
)

var collection = ee.ImageCollection(
    ee.Join.saveFirst('cloudProbability').apply({
        primary: ee.ImageCollection('COPERNICUS/S2_SR_HARMONIZED').filter(filter),
        secondary: ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY').filter(filter),
        condition: ee.Filter.equals({leftField: 'system:index', rightField: 'system:index'})
    })
).map(function (image) {
  var cloudFree = ee.Image(image.get('cloudProbability')).lt(cloudThreshold)
  var renamed = image.select(
    ['B2', 'B3', 'B4', 'B8', 'B11', 'B12'],
    ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']
  ) 
  return renamed
    .addBands(renamed.normalizedDifference(['nir', 'red']).multiply(10000).rename('ndvi'))
    .addBands(renamed.normalizedDifference(['nir', 'swir2']).multiply(10000).rename('nbr'))
    .updateMask(cloudFree)
    .int16()
})
var numberOfMonths = ee.Date(endDate)
  .difference(startDate, 'months')
  .subtract(1)
  .round()
var monthOffsets = ee.List.sequence(0, numberOfMonths)
var monthlyComposites = ee.ImageCollection(
  monthOffsets.map(function (monthOffset) {
    var date = ee.Date(startDate).advance(monthOffset, 'months')
    return collection
      .filterDate(date, date.advance(1, 'month'))
      .median()
      .set('date', date.format('YYYY-MM'))
  })
)
monthlyComposites
  .aggregate_array('date')
  .evaluate(function (dates) {
    dates.map(function (date) {
      var composite = monthlyComposites
        .filter(ee.Filter.eq('date', date))
        .first()
        .int16()
      var name = 'composite-' + date
      Map.addLayer(composite, {bands: 'ndvi', min: -10000, max: 10000, palette: '#112040, #1C67A0, #6DB6B3, #FFFCCC, #ABAC21, #177228, #172313'}, 'NDVI ' + date)
      Export.image.toDrive({
        image: composite,
        description: name,
        folder: 'ProjetoJBB',
        fileNamePrefix: name,
        region: aoi,
        scale: 10,
        maxPixels: 1e13
      })
    })
  })

https://code.earthengine.google.com/db79598c6a796322fe3a2077211678b2

Related Question