Saturday 9 February 2019

Calculating CIredEdge from Sentinel 2 composite image and adding as Band in Google Earth Explorer?


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.


No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...