0

I know that it is possible to filter an image according to the amount of clouds in the whole picture.

Is there a way to choose the image according to the amount of cloud for a given polygon instead of the whole image?

// function to create mosaic of AOI
// Mosaic the visualization layers and display (or export).
// This function clips images to the ROI feature collection
var clipToCol = function(image){
  return image.clip(geometry);
};

// Map the function over one year of data
// Load Sentinel-2 
var s2 = ee.ImageCollection('COPERNICUS/S2')
                  .filterDate('2017-06-01', '2017-12-30')
                  .filterBounds(geometry)
                  .map(clipToCol)
                  .sort('CLOUD_COVER')
                  .first();

//Parametros de visualización
  var rgbVis = {
  min: 0.0,
  max: 3000,
  bands: ['B4', 'B3', 'B2'],
  };

  Map.addLayer(s2 , rgbVis, 'RGB')
1
  • 1
    The idea is doable. You just need to write a map function to calculate the number of cloud pixels and non-cloud pixels within a given polygon, get the cloud cover from these two numbers, then add a new property to each image to store this information.
    – Kevin
    Commented Jul 6, 2019 at 12:22

1 Answer 1

2

First of all, the property name that holds the cloud coverage in Sentinel 2 is CLOUD_COVERAGE_ASSESSMENT, not CLOUD_COVER. In you code you are just sorting, which does nothing because that property is not present, but if you try to filter, it will throw an error.

// function to create mosaic of AOI
// Mosaic the visualization layers and display (or export).

// Map the function over one year of data
// Load Sentinel-2 
var s2 = ee.ImageCollection('COPERNICUS/S2')
                  .filterDate('2017-06-01', '2017-12-30')
                  .filterBounds(geometry)

var filtered = s2.filterMetadata('CLOUD_COVERAGE_ASSESSMENT', 'less_than', 50)
// var filtered = s2.filterMetadata('CLOUD_COVER', 'less_than', 50) // doesn't work

print('S2', s2.toList(s2.size()).map(function(img){return [ee.Image(img).date().format('yyyyMMdd'), ee.Image(img).get('CLOUD_COVERAGE_ASSESSMENT')]}))
print('filtered', filtered.toList(filtered.size()).map(function(img){return [ee.Image(img).date().format('yyyyMMdd'), ee.Image(img).get('CLOUD_COVERAGE_ASSESSMENT')]}))

https://code.earthengine.google.com/e2709c19846884520c2369faffc50b64

To compute a "mask percentage" property first you have to mask out clouds:

var cldmask = require('users/fitoprincipe/geetools:cloud_masks')
var masked = filtered.map(cldmask.sentinel2())
// Inspect first masked
var rgbVis = {
  min: 0.0,
  max: 3000,
  bands: ['B4', 'B3', 'B2'],
  };
Map.addLayer(masked.first(), rgbVis, 'Masked')
Map.addLayer(geometry)

An then, I have a function in geetools to compute the percentage of masked pixels.

var tools = require('users/fitoprincipe/geetools:tools')

// Test the first image of the collection
var maskCover = tools.image.maskCover(masked.first(), geometry)
print('first image mask coverage (%):', maskCover)
print('first image cloud coverage (%):', masked.first().get('CLOUD_COVERAGE_ASSESSMENT'))

// Add MASK_COVER property for all images in the collection
var addMaskCover = function(img) {
  var maskCover = tools.image.maskCover(img, geometry)
  return img.set('MASK_COVER', maskCover)
}
var colWithMaskCover = masked.map(addMaskCover)

// filter the collection by MASK_COVER
var newFiltered = colWithMaskCover.filterMetadata('MASK_COVER', 'less_than', 10)

// Inspect results
print('newFiltered', newFiltered)
print(newFiltered.toList(newFiltered.size()).map(function(img){
  return {
  'CLOUD_COVERAGE_ASSESSMENT':ee.Image(img).get('CLOUD_COVERAGE_ASSESSMENT'),
  'MASK_COVER': ee.Image(img).get('MASK_COVER')
  }
}))

https://code.earthengine.google.com/cd36f8a7336e396aab0c1ec99b78043e

4
  • I get the idea about what you did. I have few questions..: 1. I see that the mask is cutting the places with clouds, but what happens next with those hole that are in the image ? 2. When implementing a classification with the filtered collection, how those holes and how the mask is affecting it ? here is a link to my code to see those holes i´m talking about. code.earthengine.google.com/d3ec48baa6b807188b79520ceb550e81 (the big function where most of all is, is to call asynchronous shapes ) thank you so much for your help with this issue Commented Jul 8, 2019 at 15:49
  • Hola @CamiloLozano, I don't have access to shapes_arroz and Colombia.. you need to share them or make some test shapes Commented Jul 8, 2019 at 15:56
  • Hi Rodrigo, i just did it public. let me know if there are problems. Commented Jul 8, 2019 at 16:31
  • I see you want to attempt a classification, well obviously cloudy pixels won't help you, so I think you should keep them masked. The usual approach is to create a composite, so those masked pixels can be filled with pixels from other image that contains valuable information. There are many approaches for that.. a median composite, medoid, BAP Commented Jul 8, 2019 at 21:10

Your Answer

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

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