1

This is a follow-up question to Seeking Function to calculate red-edgeNDVI in Google Earth Engine?

I’ve added the redEdgeNDVI band to the image collection by mapping the function over the collection as suggested in the previous post. I’ve then created a composite image based on the maximum redEdgeNDVI for each pixel across all the images in the collection (S2_max_reNDVI). I’ve then split this image in two based on the value of the redEdgeNDVI creating two images, one with max redEdgeNDVI < 0.6 (S2_reNDVI_0_59) and one with max redEdgeNDVI >=0.6 S2_reNDVI_6). My code works fine up to this point.

What I then want to do is take the image S2_reNDVI_6 and calculate a new chlorophyll index called CIredEdge ((NIR/redEdge)-1) and add this as a band to S2_reNDVI_6, just like I did with redEdgeNDVI. However this time the object S2_reNDVI_6 is an Image and not a Collection.

I’ve tried writing this as a function:

//Function to calculate CIredEdge
var add_CIredEdge = function(image){
  //Create band variables
  var redEdge = image.select('B5');
  var NIR = image.select('B8');
  var CIredEdge = NIR.divide(redEdge).subtract(1);
    return image.addBands(CIredEdge);
};

//Map image to CIre
var S2_CIredEdge = S2_reNDVI_6.map(add_CIredEdge);

As an expression:

var CIre = S2_reNDVI_6.expression(
    '(NIR / redEdge) -1', {
      'redEdge': S2_reNDVI_6.select('B5'),
      'NIR': S2_reNDVI_6.select('B8')
});

And by computing it the hard way:

var CIre = S2_reNDVI_6.select('B8').divide(S2_reNDVI_6.select('B5')).subtract(1);

var S2_CIredEdge = S2_reNDVI_6.addBands(CIre);

Map.addLayer(S2_CIredEdge, {palette: ['ffeda0', 'feb24c', 'f03b20']}, 'CIrededge pixel composite');
//Map.addLayer(S2_CIredEdge, {bands:['CIre'], palette: ['ffeda0', 'feb24c', 'f03b20']}, 'CIrededge pixel composite');

But none of these methods work. Using the function I get the error message “S2_reNDVI_6.map is not a function” when trying to map the image.

With the expression and by doing it the hard way the result returns a 1 band (float) image but the band is ‘B8’ and the layer does not display even though the layers dialogue does. When I stretch to 100% the ranges given are 0 to 0. If I add the band to S2_reNDVI_6 there are 11 bands with the new band being named ‘B8_1’.

I suspect that there is something wrong with way I input the formula for the calculation.

I am new to GEE.

The object 'aoi' is a polygon shapefile.

Here is my code that works:

/**
 * Function to mask clouds using the Sentinel-2 QA band
 * @param {ee.Image} image Sentinel-2 image
 * @return {ee.Image} cloud masked Sentinel-2 image
 */
function maskS2clouds(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));

  return image.updateMask(mask)
  .divide(10000);
}
//-----------------------------------------------------------------------------------
//Section 2
  // Load Sentinel-2 TOA reflectance data.
  var S2 = ee.ImageCollection('COPERNICUS/S2')
                  .filterDate('2017-06-01', '2017-09-30')
                  // Pre-filter to get less cloudy granules.
                  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 20))
                  //Select required bands only
                  .select('B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B8A', 'QA60')
                  //Apply cloud mask
                  .map(maskS2clouds);

// Create clipping function
var clipper = function(image){
  return image.clip(aoi); // Add the table or shapefile to clip to here
};

//Clip images
var S2Clip = S2.map(clipper);

//Function to calculate redEdgeNDVI
var add_reNDVI = function(image){
  //Create band variables
  var redEdge = image.select('B5');
  var NIR = image.select('B8');
  var redEdgeNDVI = NIR.subtract(redEdge).divide(NIR.add(redEdge)).rename('reNDVI');
    return image.addBands(redEdgeNDVI);
};

//Map collection to reNDVI
var S2_reNDVI = S2Clip.map(add_reNDVI);

// Make a "max redEdgeNDVI" pixel composite taking max reNDVI from all images
var S2_max_reNDVI = S2_reNDVI.qualityMosaic('reNDVI');

// Display the result.
//Map.addLayer(S2_max_reNDVI, {bands:['reNDVI'], palette: ['ffeda0', 'feb24c', 'f03b20']}, 'Max reNDVI pixel composite');

//Split image in 2
//Set threshold for using redEdgeNDVI
var reNDVI_threshold = S2_max_reNDVI.lt(0.6);

//Set threshold for using CIredEdge
var CIre_threshold = S2_max_reNDVI.gte(0.6);

//Extract pixels with max reNDVI < 0.6 for redEdgeNDVI - LAI conversion
var S2_reNDVI_0_59 = S2_max_reNDVI.updateMask(reNDVI_threshold);

//Extract pixels with max reNDVI >= 0.6 for CIredEdge - LAI conversion
var S2_reNDVI_6 = S2_max_reNDVI.updateMask(CIre_threshold);

// Display the results < 0.6.
//Map.addLayer(S2_reNDVI_0_59, {bands:['reNDVI'], palette: ['ffeda0', 'feb24c', 'f03b20']}, 'Pixels Max reNDVI pixel composite');

// Display the results >= 0.6.
//Map.addLayer(S2_reNDVI_6, {bands:['reNDVI'], palette: ['ffeda0', 'feb24c', 'f03b20']}, 'Pixels Max reNDVI CIredEdge pixel composite');
0

The problem was I was setting the threshold on all bands, not just on reNDVI.

I changed:

var reNDVI_threshold = S2_max_reNDVI.lt(0.6);

to

var reNDVI_threshold = S2_max_reNDVI.select('reNDVI').lt(0.6);

and

var CIre_threshold = S2_max_reNDVI.gte(0.6);

to

var CIre_threshold = S2_max_reNDVI.select('reNDVI').gte(0.6);

This solved it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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