Extract periods in collections in GEE

compositegoogle-earth-enginelandsat

I have the following code where I calculate the greenest pixel composite for the months 5-9 from Landsat 7.

var geometry = 
    /* color: #d63000 */
    /* shown: false */
    ee.Geometry.Polygon(
        [[[20.81272957288212, 39.87257138492846],
          [20.79075691663212, 39.8098319474331],
          [20.935639118780557, 39.798226782067786],
          [20.95555183850712, 39.860976816642435]]]);
var mask7 = function(image) {
  var qa = image.select('BQA');
  var cloud = qa.bitwiseAnd(1 << 4)
                  .and(qa.bitwiseAnd(1 << 6))
                  .or(qa.bitwiseAnd(1 << 8));
  var mask2 = image.mask().reduce(ee.Reducer.min());
  return image
       .select(['B3', 'B4','B5'], ['Red', 'NIR','SWIR'])
       .updateMask(cloud.not()).updateMask(mask2)
       .set('system:time_start', image.get('system:time_start'));
};


var dataset = ee.ImageCollection("LANDSAT/LE07/C01/T1_TOA")
                            .filterBounds(geometry)
                            .filter(ee.Filter.calendarRange(5,9,'month'))
                            .map(mask7)

var NDVI_l = function(image) {
  var ndvi = image.normalizedDifference(['NIR', 'Red']).rename('NDVI');
  return image.addBands(ndvi);
};

var NDVI_col = dataset
                     .map(NDVI_l)
                     .select("NDVI");


var greenest = NDVI_col.qualityMosaic('NDVI');

print(greenest)

Map.addLayer(greenest.clip(geometry),{min:-1, max:1,  'palette': ['red','yellow', 'green']}, 'Greenest pixel composite');

However, I want the following:

  1. to calculate the period between the earliest greenup (from the greenest composite) per year and the latest browning (lowest NDVI pixel composite that I do no know how to calculate) per year (and for the period 1999-2018).
  2. to create an image collection with these periods (so an image per year with the maximum values)

Questions:

  1. how can I calculate a composite of the latest lowest pixel NDVI values per year?
  2. how can I extract the period between the highest and lowest NDVIs per year?
  3. how can I extract the NDVI images between the earliest greenup and latest browning events per year?

Perhaps I need something like the following for the annual intervals?

var years = ee.List.sequence(1999, 2018);

var byyear = ee.ImageCollection.fromImages(
      years.map(function (y) {
        return greenest.filter(ee.Filter.calendarRange(y, y, 'year'))
                    .max()
                   .set('year', y);
}))

Best Answer

You can get the min/max values and day of year of each by using the numInputs option on the min and max reducers to bring along the corresponding day of year (from a date band). Example using Sentinel-2:

// Mask clouds, compute NDVI and add a DOY band.
function prepare(image) {
  var qa = image.select('QA60')

  // Bits 10 and 11 are clouds and cirrus, respectively.
  var cloudBitMask = 1 << 10;
  var cirrusBitMask = 1 << 11;

  // Both flags should be set to zero, indicating clear conditions.
  var mask = qa.bitwiseAnd(cloudBitMask).eq(0).and(
             qa.bitwiseAnd(cirrusBitMask).eq(0))

  var doy = ee.Image.constant(image.date().getRelative('day', 'year')).int().rename('doy')

  // Return the masked and scaled data, without the QA bands.
  return image.updateMask(mask).normalizedDifference(["B5", "B4"]).rename("ndvi")
      .addBands(doy)
      .copyProperties(image, ["system:time_start"])
}

// Find the max NDVI and the corresponding DOY and then the min NDVI/DOY after the max date.
function minMax(year) {
  var date = ee.Date.fromYMD(year, 1, 1)
  var collection = ee.ImageCollection('COPERNICUS/S2')
    .filterDate(date, date.advance(1, 'year'))
    .filterBounds(geometry)
    .map(prepare)
  
  // Find the max NDVI and get the DOY that goes along with it.
  var max = collection.reduce(ee.Reducer.max(2)).rename('maxNDVI', 'maxDOY')
  
  // Find the min NDVI value AFTER the max DOY.
  var min = collection.map(function(image) {
    return image.updateMask(image.select('doy').gt(max.select('maxDOY')))
  })
  .reduce(ee.Reducer.min(2))
  .rename('minNDVI', 'minDOY')
  
  return max.addBands(min)
}

var results = ee.List.sequence(2016, 2020).map(minMax)
var resultsCollection = ee.ImageCollection.fromImages(results)
Map.addLayer(resultsCollection)

You can do any math you want the min/max NDVI/DOY by mapping a function to do simple band math after that.

Full code here: https://code.earthengine.google.com/9efbf16cda7c9a7c1c9730d3f877dc0c

Related Question