[GIS] Filter Sentinel-2 images base on cloud cover over a region of interest

google-earth-enginejavascriptsentinel-2

I know that there are a lot of examples of how to mask clouds for sentiel-2 images, but what I want is sort the images over an area of interest without change anything of the image.

Applying a cloud mask in zones where there are to much clouds, changes dramatically the image (in this case in over Bogota-Colombia). And, in some cases it generates holes in the image. thats why i dont want to change anything about the image.

I am taking this code Filter Landsat images base on cloud cover over a region of interest
as reference.

and here is how it will be with Sentinel-2 image.

//the parameter for sentiel-2 images for clouds is
//CLOUDY_PIXEL_PERCENTAGE
var ic =ee.ImageCollection('COPERNICUS/S2');

// A polygon representing the roi.
// my_polygon es a random polygon over Bogota Colombia (very cloudy zone)
var geometry = my_poligon;

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));
print(filteredCollection);                

//my image with less clouds over my zone of interest                   
var my_image = ee.Image(filteredCollection.filterBounds(centroid)
    .filterDate('2019-01-01', '2019-06-30')
    .sort('CLOUDY_PIXEL_PERCENTAGE')
    .first());                  

Best Answer

Cloud score algorithm is for Landsat scenes. You must use another algorithm to identify clouds. Since QA60 contains dense clouds information, you can use this band.

I posted before how to convert QA band by bits in Cloud mask for Landsat8 on Google Earth Engine, the approach is the same, so you code will mutate to:

//the parameter for sentiel-2 images for clouds is
//CLOUDY_PIXEL_PERCENTAGE
var ic =ee.ImageCollection('COPERNICUS/S2');

// A polygon representing the roi.
// my_polygon es a random polygon over Bogota Colombia (very cloudy zone)
var geometry = my_poligon;

var c = ic.filterBounds(geometry);

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 clouds = function(image) {
  // Select the QA band.
  var QA = image.select(['QA60']);
  // Get the internal_cloud_algorithm_flag bit.
  return getQABits(QA, 10,10, 'cloud');
  // Return an image masking out cloudy areas.
};

var withCloudiness = c.map(function(image) {
  var cloud = clouds(image);
  var cloudiness = cloud.reduceRegion({
    reducer: 'mean', 
    geometry: geometry, 
    scale: 10,
    crs:'EPSG:32719'
  });
  return image.set(cloudiness);
});

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

//my image with less clouds over my zone of interest                   
var my_image = ee.Image(filteredCollection.filterBounds(centroid)
    .filterDate('2019-01-01', '2019-06-30')
    .sort('CLOUDY_PIXEL_PERCENTAGE')
    .first());

NOTE: Now the filter isn't less than 10(%) of clouds, since the cloud image is 0 (no cloud) and 1 (cloud) use the fractional notation (0.1) to filter.

Finally, is right to use 'CLOUDY_PIXEL_PERCENTAGE' instead of 'cloud' for filter the less cloudy image over your study area? If you use it, you're filtering using the whole image, not your study area. You must consider changing the last sort operation