[GIS] Creating water and vegetation mask via image collection

google-earth-apigoogle-earth-enginejavascriptmasking

I am a Java script and EE novice but I'm already a great fan of Google Earth Engine. I am simply trying to create a single NDVI and NDWI masked layer to work on. Below you'll find my Frankenstein of a script where I've pieced code together, and it has worked well to create and NDVI and NDWI layer,I can do it with a single image but I just can't figure out how to apply it to the image collection, as it returns the error- 'S2 masked: Layer error: ImageCollection.mosaic: Error in map(ID=20160801T095532_20160801T133428_T32SQD):
Image.select: Pattern 'NDVI' did not match any bands'
.

I know why it returns this error, the code is wrong, but I just can't figure it out for find an example to help me out.

FYI: I am using Sentinel-2 MSI: Multispectral Instrument, Level-1C for the image collection.

var S2collection =  imageCollection.filterDate('2016-08-01','2019-04-10')
            .filterBounds(aoi)
            .filterMetadata('CLOUD_COVERAGE_ASSESSMENT', 'equals', 0);
                Map.addLayer(S2collection, {bands:['B4', 'B3', 'B2'], max:3000});

  // Function to calculate and add an NDVI band
  var addNDVI = function(image) {
   return image.addBands(image.normalizedDifference(['B8', 'B4']));
  };
  // Add NDVI band to image collection
  var S2 = S2collection.map(addNDVI);
  // Extract NDVI band and create NDVI median composite image
  var NDVI = S2.select(['nd']);
   var NDVImed = NDVI.median(); //I just changed the name of this variable ;)
    var ndvi_vis = ['#d73027', '#f46d43', '#fdae61', '#fee08b', '#d9ef8b',
       '#a6d96a'];
       Map.addLayer(NDVI, {min:0, max:0.7, palette: ndvi_vis},'NDVI');

  // Add NDWI band to image collection
  var addNDWI = function(image) {
    return image.addBands(image.normalizedDifference(['B3', 'B5']));
  };
  // Add NDWI band to image collection
  var S2S = S2collection.map(addNDWI);
  // Extract NDWI band and create NDWI median composite image
  var NDWI = S2S.select(['nd']);
   var NDWImed = NDVI.median();
    var NDWIViz = {min: 0, max: 0.5, palette: ['00FFFF', '0000FF']};
      Map.addLayer(NDWI, NDWIViz, 'NDWI', false);


  // Function to mask out NDVI
  var S2maskedVeg = function(image) {
   var NDVI = image.select(['NDVI']);
     return image.updateMask(NDVI.lte(0.15));
  };
  // Apply water and veg masking functions to image collection
  var S2MASKNDVI = S2collection.map(S2maskedVeg);

  // Function to mask out NDWI
  var S2maskedWater = function(image) {
   var NDWI = image.select(['NDWI']);
    return image.updateMask(NDWI.lte(0.15));
  };
  // Apply water and veg masking functions to image collection
  var S2maskedW = S2MASKNDVI.map(S2maskedWater);
    Map.addLayer(S2maskedW,{max:1},'S2 masked');

Best Answer

The error occurs cause you did not rename the band to 'NDVI' and you did not use the actual variable containing the NDVI band (you are now using the original collection using 'S2collection.map(S2maskedVeg)'.

You would (i think) best first define all you functions. Then apply them in the required order to your image collection, so the one where NDVI is needed in the NDVI mask, NDVI is already present. That would look something like this:

var S2collection =  imageCollection.filterDate('2016-08-01','2019-04-10')
            .filterBounds(aoi)
            .filterMetadata('CLOUD_COVERAGE_ASSESSMENT', 'equals', 0);
                Map.addLayer(S2collection, {bands:['B4', 'B3', 'B2'], max:3000});

// ####### DEFINE ALL FUNCTIONS #####
  // Function to calculate and add an NDVI band
  var addNDVI = function(image) {
   return image.addBands(image.normalizedDifference(['B8', 'B4']).rename('NDVI'));
  };
  // Add NDWI band to image collection
  var addNDWI = function(image) {
    return image.addBands(image.normalizedDifference(['B3', 'B5']).rename('NDWI'));
  }; 
  // Function to mask out NDVI
  var S2maskedVeg = function(image) {
   var NDVI = image.select(['NDVI']);
     return image.addBands(ee.Image(1).updateMask(NDVI.lte(0.15)).rename('NDVI_mask'));
  };
  // Function to mask out NDWI
  var S2maskedWater = function(image) {
   var NDWI = image.select(['NDWI']);
    return image.addBands(ee.Image(1).updateMask(NDWI.lte(0.15)).rename('NDWI_mask'));
  };

// ####### APPLY ALL FUNCTION TO THE IMAGE COLLECTION ####
// Apply water and veg masking functions to image collection
S2collection = S2collection.map(addNDWI).map(addNDVI).map(S2maskedVeg).map(S2maskedWater);
print(S2collection)

I was not sure which band of the image you would like to mask using the NDVI and NDWI, so I added a constant image (ee.Image(1)) and masked that image in the functions where masking is applied.

Here is an example how to use the mask NDVI and NDWI bands:

// define function
var maskBands = function(image) {
  return image.select(['B3', 'B4', 'B5', 'B8']).updateMask(image.select('NDVI_mask'))
                                .updateMask(image.select('NDWI_mask'));
};

// map over the collection and use the function
var maskedCollection = S2collection.map(maskBands);

Link code

Related Question