2

How can I apply a cloud mask to each individual image in a collection THEN mosaic them together based on (for example) mean pixel value across images? The code does not work because the maskClouds function requires the input to be a single image but I do NOT want to mosaic all images before all cloud pixels have been removed.

//CDI AOI
var region = ee.FeatureCollection('ft:1tdSwUL7MVpOauSgRzqVTOwdfy17KDbw-1d9omPw')
.filterMetadata('Country', 'equals', 'Ghana');

var landsat8 = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR')
.filterDate('2013-01-01', '2013-12-31')
//.filterMetadata('CLOUD_COVER', 'less_than', 25)
.filterBounds(region); 

////////////////////////////////////////////////////////////
/////////////////Start Function/////////////////////////////
////////////////////////////////////////////////////////////

// Fmask classification values var FMASK_CLEAR_GROUND = 0; var FMASK_WATER = 2; 
//var FMASK_CLOUD_SHADOW = 3; var FMASK_SNOW = 4; var FMASK_CLOUD = 5;

var getQABits = function(image, start, end, newName) {
    // Compute the bits we need to extract.
    var pattern = 0;
    for (var i = start; i <= end; i++) {
       pattern += Math.pow(2, i);
    }
    // Return a single band image of the extracted QA bits, giving the band
    // a new name.
    return image.select([0], [newName])
                  .bitwiseAnd(pattern)
                  .rightShift(start);
};

// A function to mask out cloudy pixels.
var cloud_shadows = function(image) {
  // Select the QA band.
  var QA = image.select(['pixel_qa']);
  // Get the internal_cloud_algorithm_flag bit.
  return getQABits(QA, 3,3, 'Cloud_shadows').eq(0);
  // Return an image masking out cloudy areas.
};

// Second function to mask out cloudy pixels.
var cloud_shadows_mean = function(image) {
  // Select the QA band.
  var QA_mean = image.select(['pixel_qa_mean']);
  // Get the internal_cloud_algorithm_flag bit.
  return getQABits(QA_mean, 3,3, 'Cloud_shadows_mean').eq(0);
  // Return an image masking out cloudy areas.
};

// A function to mask out cloudy pixels.
var clouds = function(image) {
  // Select the QA band.
  var QA = image.select(['pixel_qa']);
  // Get the internal_cloud_algorithm_flag bit.
  return getQABits(QA, 5,5, 'Cloud').eq(0);
  // Return an image masking out cloudy areas.
};

// Second function to mask out cloudy pixels.
var clouds_mean = function(image) {
  // Select the QA band.
  var QA_mean = image.select(['pixel_qa_mean']);
  // Get the internal_cloud_algorithm_flag bit.
  return getQABits(QA_mean, 5,5, 'Cloud_mean').eq(0);
  // Return an image masking out cloudy areas.
};

var maskClouds = function(image) {
  var cs = cloud_shadows(image);
  var c = clouds(image);
  image = image.updateMask(cs);
  return image.updateMask(c);
};

var maskClouds_mean = function(image) {
  var cs_mean = cloud_shadows_mean(image);
  var c_mean = clouds_mean(image);
  image = image.updateMask(cs_mean);
  return image.updateMask(c_mean);
};

////////////////////////////////////////////////////////////
/////////////////End Function///////////////////////////////
////////////////////////////////////////////////////////////

var visParams = {
  bands: ['B4', 'B3', 'B2'],
  min: 0,
  max: 3000,
  gamma: 1.4,
};

var landsat8_mask = maskClouds(landsat8)

var cloud_free_mean = landsat8
.reduce(ee.Reducer.mean());

Map.addLayer(cloud_free_mean, visParams2, 'Cloud Free Mean');

1 Answer 1

3

You can map a function that operates on an image over an entire imageCollection before reducing. For example, I use snippets from your code above to generate a cloud-free composite of Ghana by defining the masking functions first, then applying them to the imageCollection. Note that I expanded the date range because it looks like 2013 may have some additional artifacts (perhaps from cirrus clouds? play around other QA bands for more) that can fall out in the wash when you add a few more years of data. Also consider using a median rather than mean reducer to generate a final image that's more resilient to outliers.

// Same QA function you had above
var getQABits = function(image, start, end, newName) {
    // Compute the bits we need to extract.
    var pattern = 0;
    for (var i = start; i <= end; i++) {
       pattern += Math.pow(2, i);
    }
    // Return a single band image of the extracted QA bits, giving the band
    // a new name.
    return image.select([0], [newName])
                  .bitwiseAnd(pattern)
                  .rightShift(start);
};
// A function to mask out cloudy pixels. Modified from your code to do a lot more all at once.
var cloudmasker = function(image) {
  // Select the QA band.
  var QA = image.select(['pixel_qa']);
  // Get the internal_cloud_algorithm_flag bit.
  var Shadows =  getQABits(QA, 3,3, 'Cloud_shadows').eq(0);
  var Cloud =  getQABits(QA, 5,5, 'Cloud').eq(0);
  // Update image mask using clouds and cloud shadows
  return image.updateMask(Shadows).updateMask(Cloud);
};

//CDI AOI
var region = ee.FeatureCollection('ft:1tdSwUL7MVpOauSgRzqVTOwdfy17KDbw-1d9omPw')
.filterMetadata('Country', 'equals', 'Ghana');
// Center your map
Map.centerObject(region, 7);

// Access data and map the cloudmask function. Added the cloudmasker here
var landsat8 = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR')
  .filterDate('2013-01-01', '2018-12-31')
  .filterBounds(region)
  .map(cloudmasker); 

// Make visParams rely on the reduced image (i.e. add '_mean' to the Band labels)
var visParams = {
  bands: ['B4_mean', 'B3_mean', 'B2_mean'],
  min: 0,
  max: 3000,
  gamma: 1.4,
};

// Reduce the ls8 image
var cloud_free_mean = landsat8.reduce(ee.Reducer.mean());

// Add the reduced image
Map.addLayer(cloud_free_mean, visParams, 'Cloud Free Mean');

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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