I'm trying to train an algorithm to detect mangrove forests in several regions around Asia for each year using Landsat 8. When I apply the .median reducer on some image collections over a 1-year timespan, the composite is totally clear and cloud free (see 1st image - code link: https://code.earthengine.google.com/486067b4ca23929c45313eadd0e0cacc)

no cloud

However, for some regions or years with high cloud cover throughout the year, the .median reduction gives me a composite that is noisy (see 2nd image - code link: https://code.earthengine.google.com/286e97966b48d2ae426b832f024097ee).


Is there a way I can apply the .median reducer only on images with comparatively low cloud cover? Or can anyone here think of another way of getting an accurate, cloud-free, year-long composite for an image collection to do a supervised classification?


    // filtering the image collection
var image = ee.Image(ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA')
  .filterDate('2015-01-01', '2015-12-31')    
Map.addLayer(image, {bands: ['B4', 'B3', 'B2'], max: 0.3}, 'landsat');

// // merge feature collections
// var newfc = mangrove.merge(other_veg).merge(water).merge(urban);
// print(newfc);

// // create training data
// var bands = ['B2', 'B3', 'B4', 'B5', 'B6', 'B7'];
// var training = image.select(bands).sampleRegions({
//   collection: newfc, 
//   properties: ['landcover'], 
//   scale: 30
//   });

// print(training);

// //Train the classifier
// var classifier = ee.Classifier.cart().train({
//   features: training, 
//   classProperty: 'landcover', 
//   inputProperties: bands
// });

// //Run the classification
// var classified = image.select(bands).classify(classifier);

// //Display classification
// Map.centerObject(newfc, 11);
// Map.addLayer(image,
// {bands: ['B4', 'B3', 'B2'], max: 0.3},
// 'Landsat image');
// Map.addLayer(classified,
// {min: 0, max: 3, palette: ['008b04', 'ffc82d', 'ff0000', '1400c2']},
// 'classification');
// Map.addLayer(newfc, {}, 'data_points');


2 Answers 2


You can also use the 'BQA' band to mask the clouds for each image and just calculate the median for each pixel without clouds. You can check the information of the image collection and the quality assessment band in the following link: https://developers.google.com/earth-engine/datasets/catalog/LANDSAT_LC08_C01_T1_TOA#bands. In that link you can see that the 'BQA' band contains the quality assessment information, while the bit 4 contains the information that classifies the pixel as cloud or not.

var image = ee.Image(ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA')
  .filterDate('2015-01-01', '2015-12-31')  
    // Use bit 4
    var bitCloud = 1<<4;
    // Select BQA band
    var qa = image.select('BQA');
    // Create mask to stay with pixels where its BQA band
    // indicates 0 in its bit 4
    var mask = qa.bitwiseAnd(bitCloud).eq(0);
    // Return the masked image
    return image.updateMask(mask);

You can filter by CLOUD_COVER metadata. May not always work because it's a property that represents the whole scene, and sometimes a single scene has cloud free areas that will be excluded, and sometime you may run out of images. But it is always the first choice, and if you hit any edge case, you'd have to search for better methods. I tried the simple approach and worked in your case:

// filtering the image collection
var image = ee.Image(ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA')
  .filterDate('2018-01-01', '2018-12-31')
  .filterMetadata('CLOUD_COVER', 'less_than', 10) // I tried with 30 and 20 until 10 gave good results
Map.addLayer(image, {bands: ['B4', 'B3', 'B2'], max: 0.3}, 'landsat');

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.