Google Earth Engine – Reducing ImageCollection to a Single Band

google-earth-engine

I have an image collection that is a binary layer that indicates whether there is a burn or not in each pixel, for the specified time period by which I filtered the satellite images. This is calculated from the differences in the Normalized Burn ratio (dNBR), calculated for each image. A pixel has value 1 (which means it is burned) if the dNBR value is above the threshold value for a pixel, both when looking at the difference between NBR of day1 and day2, and looking at the difference between NBR of day1 and day3. Now I want to reduce the image collection to an image such that each pixel that burnt at any point of time (within the given time period) has a positive value and attach a timestamp as a band to the image, such that each burnt value pixel has a time of burn. The way I am implementing it is by adding a date band to the original filtered image collection, then finding the dNBR and then reducing the image collection by max() reducer. But the problem is the reducer is maximising even the time band and I am getting only one value as the time stamp. Is there a way to apply reduce to only one value and retain the value of the other band which the maximum value was part of? I have been breaking my head over it for quite some time. Please help

var vis = {"opacity":1,"bands":["B4","B3","B2"],"gamma":3.464},
sent = ee.ImageCollection("COPERNICUS/S2")

var land = sent2.filterBounds(geometry).filterDate("2019-01-01","2019-06-01")
.filterMetadata("MGRS_TILE","equals",'44RLT')
.filter(ee.Filter.lt("CLOUDY_PIXEL_PERCENTAGE",5));
var landsort = land.sort("system:time_start");
print(landsort);

var addDate = function(image){
  var doy = image.date().getRelative('day', 'year');
  var doyBand = ee.Image.constant(doy).uint16().rename('doy')
  doyBand = doyBand.updateMask(image.select('B8').mask())

  return image.addBands(doyBand);
};

var a = ee.ImageCollection(landsort.toList(landsort.size()));
var a = a.map(addDate)
var a = a.toList(a.size())
var b = function(image){
 var nbr3 = ee.Image(image).normalizedDifference(["B8","B12"]);
 var nbr2 = ee.Image(a.get(a.indexOf(image).subtract(1))).normalizedDifference(["B8","B12"]);
 var nbr1 = ee.Image(a.get(a.indexOf(image).subtract(2))).normalizedDifference(["B8","B12"]);

 var e = nbr1.subtract(nbr2).gt(0.3);
 var f = nbr1.subtract(nbr3).gt(0.3);
 var g = e.multiply(f);
 var h = g.addBands(ee.Image(a.get(a.indexOf(image).subtract(2)))
.metadata('system:time_start'));
 return h;
};
var dnrcollect = ee.ImageCollection(a.map(b)).max();
Map.addLayer(dnrcollect)

Best Answer

Use: col.reduce(ee.Reducer.max(nBands)) instead of col.max().

The ee.Reducer.max() reducer allows you to specify additional bands to be included in the resulting image whose pixel values correspond to whatever image had the max value (of first band) among constituents.

From your example:

ee.ImageCollection(a.map(b)).reduce(ee.Reducer.max(NEED TO SPECIFY NUMBER OF EXTRA BANDS))

A toy example - use the inspector and expand all of the layer info to verify (see image below):

/**
 * @license
 * Copyright 2019 Google LLC.
 * SPDX-License-Identifier: Apache-2.0
 */

// Make some images with a data band and a date band.
var img1 = ee.Image.random(10).addBands(ee.Image.constant(10)).float().rename('data', 'date');
var img2 = ee.Image.random(20).addBands(ee.Image.constant(20)).float().rename('data', 'date');

// Make an image collection from the images.
var col = ee.ImageCollection([img1, img2]);

// Reduce the collection by the max of the first band and retain corresponding bands.
var maxImg = col.reduce(ee.Reducer.max(col.first().bandNames().size()))
  .rename(['maxData', 'maxDate']);

// Show both datasets on the Map so that inspector can be used to verify.
Map.addLayer(col, null, 'col');
Map.addLayer(maxImg, null, 'max');

enter image description here

Code Editor script: https://code.earthengine.google.com/b62c98246369e784ecd93852a7a2476e

Related Question