#2: create a cloud free composite

A modular land cover system part 2: shadow masking

Step 1: create a new script and call it shadowMask_module

Step 2: copy the code below and store it in the script


// zScoreThresh: Threshold for cloud shadow masking- lower number masks out
var zScoreThresh = -1.80;

// shadowSumThresh: Sum of IR bands to include as shadows within TDOM and the
//    shadow shift method (lower number masks out less)
var shadowSumThresh = 0.20;

// contractPixels: The radius of the number of pixels to contract (negative
//    buffer) clouds and cloud shadows by. Intended to eliminate smaller cloud
//    patches that are likely errors
// (1.5 results in a -1 pixel buffer)(0.5 results in a -0 pixel buffer)
// (1.5 or 2.5 generally is sufficient)
var contractPixels = 1.5; 

// dilatePixels: The radius of the number of pixels to dilate (buffer) clouds
//    and cloud shadows by. Intended to include edges of clouds/cloud shadows
//    that are often missed
// (1.5 results in a 1 pixel buffer)(0.5 results in a 0 pixel buffer)
// (2.5 or 3.5 generally is sufficient)
var dilatePixels = 2.5;

////////////////////////////////////////////////////////////////////////////////
// Function for finding dark outliers in time series.
// Original concept written by Carson Stam and adapted by Ian Housman.
// Adds a band that is a mask of pixels that are dark, and dark outliers.
exports.shadowMask = function(collection,studyArea) {

  var inBands = ["B8",'B11'];
  var shadowSumBands = ['nir','swir1'];

  var allCollection = ee.ImageCollection('COPERNICUS/S2').filterBounds(studyArea)
                                                        .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',70))
                                                         .map(maskClouds).select(inBands,shadowSumBands);

//  allCollection = allCollection.map(function(img){return img.divide(10000)});

  // Get some pixel-wise stats for the time series
  var irStdDev = allCollection.select(shadowSumBands).reduce(ee.Reducer.stdDev());
  var irMean = allCollection.select(shadowSumBands).mean();

  var maskDarkOutliers = function(img){
      var zScore = ee.Image(img.select(shadowSumBands)).subtract(irMean).divide(irStdDev);
      var irSum = img.select(shadowSumBands).reduce(ee.Reducer.sum());
      var TDOMMask = zScore.lt(zScoreThresh).reduce(ee.Reducer.sum()).eq(2).and(irSum.lt(shadowSumThresh));

      TDOMMask = TDOMMask.focal_min(contractPixels).focal_max(dilatePixels).rename('TDOMMask');
      return img.updateMask(TDOMMask.not()).addBands(TDOMMask).addBands(irSum).addBands(zScore);
  };  

  // Mask out dark dark outliers
  collection = collection.map(maskDarkOutliers);

  return collection;
};

function maskClouds(image){
  var qa = image.select('QA60').int16();

  // Bits 10 and 11 are clouds and cirrus, respectively.
  var cloudBitMask = Math.pow(2, 10);
  var cirrusBitMask = Math.pow(2, 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 the masked and scaled data.
  return image.updateMask(mask);
}

Step 4: Open the main script and add the lines below

print("applying cloud shadow mask");
s2 = shadowS2.shadowMask(??,??);
Map.addLayer(ee.Image(s2.first()),{min:0,max:0.6,bands:"??,??,??","ShadowMask");
print(ee.Image(s2.first()));

Step 5: Run the script

link

Leave a Reply