Does anyone know how to do a composite of greenest pixel for Sentinel 2?

That is calculate the maximum NDVI for a Image collection, and then do a pixel-wise image stacking of the original bands (that correspond to the image of the maximum NDVI). There is already an algorithm for Landsat 8 named .qualityMosaic() , but it needs the quality band that is only available for Landsat.

2 Answers 2


You can use qualityMosiac exactly similar for Sentinel-2 as for Landsat. The method you are looking for is described here. What you need is adding a NDVI band to the image collection of Sentinel-2 and use qualityMosaic('NDVI') to obtain the per pixel values of the corresponding pixel with the highest NDVI value.

var s2 = ee.ImageCollection("COPERNICUS/S2")
.filterBounds(ee.Geometry.Point([121.331, 39.1426]))
.filterDate('2018', '2019');

// compute ndvi and add to the image collection
var withNDVI = s2.map(function(img){
  var red = ee.Image(img.select('B4'));
  var nir = ee.Image(img.select('B8'));
  var ndvi = (nir.subtract(red)).divide(nir.add(red)).rename('ndvi');
  return img.addBands(ndvi);

// use quality mosaic to get the per pixel maximum NDVI values and corresponding bands
var ndviQual = withNDVI.qualityMosaic('ndvi');
Map.addLayer(ndviQual, {min:0, max: 10000, bands: ['B4', 'B3', 'B2']})

Link script

  • 1
    this should be the accepted answer as it answers exactly what the question asked Mar 15, 2019 at 15:34

We often create composites of various vegetation indexes from Sentinel-2 using Google Earth Engine. We take all the images from a given time period, find the value in the 95th percentile in that stack, and create one image that contains the 95th percentile value over the time period of interest. We use the 95th percentile value rather than the max to avoid any outliers due to errors. However, I think you are trying to do something similar, so I hope this can help you. The portion of code I think you are looking for is the last line, but I've included some code with comments above that for context:

// define start and end date vars.
var year = 2018;
var start = ee.Date(year+'-01-01');
var end = ee.Date(year+'-12-31');

// s2_filter: filters all avail sentinel 2 (s2) images: limit spatial extent 
// to the boundary and filter date range by start and end vars defined above
var s2_filter = s2
.filterDate(start, end);

// print number of images in collection, given spatial/temporal filters
// already defined
var count = s2_filter.size();
print('size of image collection', count);

// *********** start ndvi processing

// compute ndvi using red band 4 and NIR band 8a; calculated as
// : (b8-b4)/(b8+b4)

var ndvi = s2_filter.map(function(img){
  var red = ee.Image(img.select('B4'));
  var nir = ee.Image(img.select('B8'));
  return (nir.subtract(red)).divide(nir.add(red)).rename('ndvi');

// print metadata and attributes 

// limit values returned to ONE value in the 95th percentile; not using max to avoid 
var ndvi_95 = ndvi.reduce(ee.Reducer.percentile([95]));
  • Using the 95th percentile is an excellent idea! Even though that´s not exactly what I asked for, I will definitely give it a try Mar 15, 2019 at 12:40

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.