I've filtered an imagecollcetion down to all images in an area between a specified range of dates annually (imagecollection A) and then filtered it further by narrowing it down to the most cloud-free images within that range.

//-------------------- Generate AOI
var pointBuffer = geometry.buffer({'distance': 6000});

//-------------------- Set Parameters
// Range of years
var startyear = 2022;
var endyear = 2023;

// Rage of months
var startMonth = 5;
var endMonth = 7;

// Minimum yellow threshold - for rapseed
var min_y_tresh = 0.035

//-------------------- Load Sentinel-2 TOA reflectance data.
var imagecollection_A = ee.ImageCollection('COPERNICUS/S2')
    .filterDate(startyear+'-01-01', endyear+1+'-01-01')
    .filter(ee.Filter.calendarRange(startMonth, endMonth, 'month'));
print(imagecollection_A,"imagecollection_A Check")

//-------------------- Generate and map NDYI and NDYI Mask to image collection
// Function generates NDYI
var addNDYI = function(image) {
  var NDYI = image.normalizedDifference(['B3','B2']).rename('NDYI');
  return image.addBands(NDYI);

// Function masks NDYI to specified treshold
var addNDYI_Mask = function(image) {
  var masked = image.select('NDYI').updateMask(image.select('NDYI').gte(min_y_tresh)).rename('NDYI_Masked'); 
  return image.addBands(masked);

var imagecollection_B = imagecollection_A.map(addNDYI);
var imagecollection_C = imagecollection_B.map(addNDYI_Mask);
print(imagecollection_C,"Collection Check");

//-------------------- Get Cloud Free Image Per Year
var years = ee.List.sequence(startyear, endyear).getInfo();

var imagecollection_D = years.map(function(year){
  // Get least cloudy annual single scene.
  var annual = imagecollection_C.filterDate(year+'-01-01', (year+1)+'-01-01')
  var annual_img = ee.Image(annual.first());
  return annual_img;
imagecollection_D = ee.ImageCollection(imagecollection_D);

What I would like to do is filter imagecollection A based on the pixel values of the NDYI band that has been added.

I know I can filter band values using .reduce(ee.Reducer.max()), but this results in a single band when I try to apply it.

I'm trying to generate an imagecollection that has been filtered down to a specific date range annually, then filtered by an NDYI thresholded pixel value, and finally to the least cloudy image.

I can get everything else but I just can't figure out the NDYI thresholded filter. Any help would be greatly appreciated!

Below is a link to the complete code: https://code.earthengine.google.com/bb51958baa978cd2fc82130a3975b8fa

  • Can you explain further what you mean by "filter the image collection based on the pixel values of NDYI band"? what is the specific filter that you will apply on each image to either keep or discard it? "Based on pixel values of NDYI band" is ambiguous -- are you going to discard a whole image based on the NDYI value of some pixels? or are you first retrieving the spatial mean/max/something else over the whole image, and then filter the image based on that value? Commented May 8, 2023 at 6:52
  • Hey Oliver, Ideally I would like to retrieve the spatial max over the whole image using the NDYI and then filter. For example, if I have five images between the months of June and August 2023, I would like to filter this down to the image that has the highest NDYI. Then apply it to the annual imagecollection. Does that make more sense?
    – Mícheál
    Commented May 8, 2023 at 8:13

1 Answer 1


Here's how you could get the (spatial) maximum NDYI value for each image in your collection. The caveat is that we are not getting the maximum value for each of the 10980x10980 px pixels at the native scale (10 meters), most likely the user memory would run out and the computation would fail. Instead, we can take advantage of the image pyramid and request the computation at a coarser scale. If this is something acceptable for your analysis, then give it a try. Here I used a 5' resolution -- you can try higher resolutions and see it it works for you:

//-------------------- Get maximum NDYI value for each image:
function getMaxNDYI(image){
// Adds a property to each image specifiying the MAX value of NDYI over the WHOLE image
// (within a specified grid -- see scale, crs, crsTransform)
    var maxValue = image.select("NDYI").reduceRegion({
      geometry:image.get("system:footprint"), // this is a very large geometry,
      // so we better use a coarse grid -- certainly not the native S2 scale (10 or 20m)
      // unless you use a specific smaller region(s) other than the image's footprint.
      crsTransform:[5/60,0,0,0,5/60,0], // 5 arcmin resolution grid
    return image.set({
      maxNDYI: maxValue
var imagecollection_D = imagecollection_C.map(getMaxNDYI).sort("maxNDYI", false)
print(imagecollection_D,"Collection D Check");

The result prints the image collection sorted by highest maxNDYI.

Finally, if you want to keep only the images with the highest maxNDYI for each year, we can do something like this:

//-------------------- For each year, get the maximum value of maxNDYI:
var years=ee.List.sequence(startyear,endyear)
function getYearMaxNDYIImage(year){
  var s = ee.Date.fromYMD(year,1,1)
  var e = ee.Date.fromYMD(year.add(1),1,1)
  return imagecollection_D
  .sort("maxNDYI",false) // ascending=False -- so the highest is first
var imagecollection_E = ee.ImageCollection(
  years.map(getYearMaxNDYIImage) // Get the yearly MaxNDYI image for each year. 
print(imagecollection_E,"Collection E Check");     //Only 2 images
print(imagecollection_E.aggregate_array("maxNDYI"))  // 2 values -- the highest for 2022 and 2023

The complete script is here:


  • Hey Oliver, Thanks for the above, it is exactly what I was trying to do and a cool way of doing it! Really helpful and I really appreciate the help.
    – Mícheál
    Commented May 8, 2023 at 11:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.