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');
Answer
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.