Here is an example of cloud masking for Sentinel-2:
var s2 = ee.ImageCollection("COPERNICUS/S2");
var pt = ee.Geometry.Point([-122.41653442382812, 37.77180027337861]);
var cloudyImage = ee.Image('COPERNICUS/S2/20151207T190417_20151207T221905_T10SEG');
Map.centerObject(cloudyImage, 10);
Map.addLayer(cloudyImage, {bands: ['B4', 'B3', 'B2'], max: 2000}, 'cloudy image');
// Bits 10 and 11 are clouds and cirrus, respectively.
var cloudBitMask = ee.Number(2).pow(10).int();
var cirrusBitMask = ee.Number(2).pow(11).int();
var qa = cloudyImage.select('QA60');
Map.addLayer(qa.bitwiseAnd(cloudBitMask).neq(0), {}, 'clouds');
Map.addLayer(qa.bitwiseAnd(cirrusBitMask).neq(0), {}, 'cirrus');
function maskS2clouds(image) {
var qa = image.select('QA60');
// Both flags should be set to zero, indicating clear conditions.
var mask = qa.bitwiseAnd(cloudBitMask).eq(0).and(
qa.bitwiseAnd(cirrusBitMask).eq(0));
return image.updateMask(mask);
}
var cloudMasked = s2.filterBounds(pt).map(maskS2clouds);
var median = cloudMasked.median();
Map.addLayer(median, {bands: ['B4', 'B3', 'B2'], max: 2000}, 'median');
As far as I know, Sentinel 2 has no computed cloud-shadow mask, so I ommit that part. But for the rest, I think you should at least mask out clouds, and filter a little.
I've made public a repo I have to perform this: users/fitoprincipe/geetools
First the core:
var computeQAbits = function(image, start, end, newName) {
var pattern = 0;
for (var i=start; i<=end; i++) {
pattern += Math.pow(2, i);
}
return image.select([0], [newName]).bitwiseAnd(pattern).rightShift(start);
};
var sentinel2 = function(image) {
var cloud_mask = image.select("QA60");
var opaque = computeQAbits(cloud_mask, 10, 10, "opaque");
var cirrus = computeQAbits(cloud_mask, 11, 11, "cirrus");
var mask = opaque.or(cirrus);
return image.updateMask(mask.not());
}
You can use the function sentinel2
in a map
function.
to your question:
Using min()
, which may not be the best approach to generate a composite, (but that's another story so I am not diggin on it), this would be a complete 'solution':
var s2mask = require('users/fitoprincipe/geetools:cloud_masks').sentinel2;
var AOI = ee.Geometry.Rectangle(-85.14404296875, 46.9502622421856,
-71.87255859375, 41.60722821271717);
var collection = ee.ImageCollection("COPERNICUS/S2")
.filterBounds(AOI)
.filterMetadata('CLOUDY_PIXEL_PERCENTAGE', 'less_than', 70)
.map(s2mask());
var image = ee.Image(collection.min());
Map.addLayer(image, {bands:['B8', 'B12', 'B4'], min:0, max:3000});
Map.centerObject(AOI);
Best Answer
Many image manipulation operations in Earth Engine remove all properties. The principle is that it is impractical for Earth Engine to determine whether the operation makes the metadata incorrect (such as if it is a scale/offset parameter) or to decide what to do when two images with different metadata are being combined with some binary operator.
In order to restore the properties when you know it makes sense, you can use
copyProperties
: