My goal is to create an image collection that has 100% free cloud over a small region of interest, for example a lake.

This script filters landsat 8 images based on location and cloud cover:

var nocloudimages =  landsat8.filterBounds(ROI)
                     .filter(ee.Filter.lt('CLOUD_COVER', value))
                     .sort('system:time_start', true)

However, as we know, the 'CLOUD_COVER' accounted for the whole landsat 8 image percentage of cloud, not a particular Region of Interest (ROI) cloud cover.

Is there a method to achieve that?


It's going to be something like this, but you'll need to play with the threshold (10 in this example) to meet your needs. Watch out for ROIs that overlap a scene's footprint, but do not contain any valid pixels. Also watch out for ROIs that are very large or span multiple WRS cells.

var ic = ee.ImageCollection("LANDSAT/LC08/C01/T1_RT_TOA");

// A polygon representing the roi.
var geometry = ee.Geometry.Polygon(
        [[[-121.85897778617999, 37.70881514186375],
          [-121.83975284337708, 37.76202899390253],
          [-121.94137041100134, 37.759857750255144]]]);

var c = ic.filterBounds(geometry);

var withCloudiness = c.map(function(image) {
  var cloud = ee.Algorithms.Landsat.simpleCloudScore(image).select('cloud');
  var cloudiness = cloud.reduceRegion({
    reducer: 'mean', 
    geometry: geometry, 
    scale: 30,
  return image.set(cloudiness);

var filteredCollection = withCloudiness.filter(ee.Filter.lt('cloud', 10));

There is standard example in the code editor that is pretty close to what you want. https://code.earthengine.google.com/1be28850c6c7880d8fcd5f1e0a808986

// SimpleCloudScore, an example of computing a cloud-free composite with L8
// by selecting the least-cloudy pixel from the collection.

// A mapping from a common name to the sensor-specific bands.
var LC8_BANDS = ['B2',   'B3',    'B4',  'B5',  'B6',    'B7',    'B10'];
var STD_NAMES = ['blue', 'green', 'red', 'nir', 'swir1', 'swir2', 'temp'];

// Compute a cloud score.  This expects the input image to have the common
// band names: ["red", "blue", etc], so it can work across sensors.
var cloudScore = function(img) {
  // A helper to apply an expression and linearly rescale the output.
  var rescale = function(img, exp, thresholds) {
    return img.expression(exp, {img: img})
        .subtract(thresholds[0]).divide(thresholds[1] - thresholds[0]);

  // Compute several indicators of cloudyness and take the minimum of them.
  var score = ee.Image(1.0);
  // Clouds are reasonably bright in the blue band.
  score = score.min(rescale(img, 'img.blue', [0.1, 0.3]));

  // Clouds are reasonably bright in all visible bands.
  score = score.min(rescale(img, 'img.red + img.green + img.blue', [0.2, 0.8]));

  // Clouds are reasonably bright in all infrared bands.
  score = score.min(
      rescale(img, 'img.nir + img.swir1 + img.swir2', [0.3, 0.8]));

  // Clouds are reasonably cool in temperature.
  score = score.min(rescale(img, 'img.temp', [300, 290]));

  // However, clouds are not snow.
  var ndsi = img.normalizedDifference(['green', 'swir1']);
  return score.min(rescale(ndsi, 'img', [0.8, 0.6]));

// Filter the TOA collection to a time-range and add the cloudscore band.
var collection = ee.ImageCollection('LC8_L1T_TOA')
    .filterDate('2013-05-01', '2013-07-01')
    .map(function(img) {
      // Invert the cloudscore so 1 is least cloudy, and rename the band.
      var score = cloudScore(img.select(LC8_BANDS, STD_NAMES));
      score = ee.Image(1).subtract(score).select([0], ['cloudscore']);
      return img.addBands(score);

// Define visualization parameters for a true color image.
var vizParams = {'bands': ['B4', 'B3', 'B2'], 'max': 0.4, 'gamma': 1.6};
Map.setCenter(-120.24487, 37.52280, 8);
Map.addLayer(collection.qualityMosaic('cloudscore'), vizParams);
  • Thank you for your answer. But i wanted a collection of images not one. I just wanted all images that has 100% free cloud cover over a small region of interest (ROI). – Minh Shines Aug 21 '17 at 8:28
  • The example builds a single mosaic image of cloud free pixels from a collection of images. But are you are asking for a set of images with no clouds over that area? In that case, you can clip the image collection to your region and then apply the cloud score and keep just the images that have a low cloud score. – intotecho Aug 21 '17 at 12:44
  • 1
    It's worth noting that the cloudscore function can be replaced by ee.Algorithms.Landsat.simpleCloudScore(). – Nicholas Clinton Aug 21 '17 at 19:26
  • 1
    Can't thank you guys enough! I did it. 'intotecho' approach is right. I clipped all the landsat images to the ROI only and then finally apply Nicholas Clinton script to do the job! – Minh Shines Aug 22 '17 at 7:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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