So, you are asking two question at once. You would like to use the Otsu threshold to calculate a water mask on a per-image basis. Besides, you would like a watermask in a similar way for the median image. In your code, you have mixed them up. For that reason, your code is not working.
You tried to filter by cloud cover, however, as you do it now you will remain the full collection and just rearrange the order of the images. To filter by cloudcover, use:
var sorted = temporalFiltered.filter(ee.Filter.lt('CLOUD_COVER', 10));
First, make a function to calculate NDWI for a random image:
// Create a function to calculate NDWI per image
function calcNDWI(image){
return image.normalizedDifference(['B3', 'B5']).rename('NDWI');
}
Then, define the Otsu thresholding function of Nicolas Clinton inside your code (which I have done, see the link).
To get the Otsu threshold and water mask for the full image collection, map over you imageCollection, which you named 'sorted':
var mappedCollection = sorted.map(function(image){
var NDWI = calcNDWI(image);
var histogram = ee.Dictionary(NDWI.reduceRegion({
reducer: ee.Reducer.histogram(100),
geometry: AOI_subset,
scale: 30,
bestEffort: true
}).get('NDWI'));
var threshold = otsu(histogram);
var waterMask = NDWI.lt(ee.Number(threshold)).rename('waterMask');
return image.addBands([NDWI, waterMask]).set('OtsuThresh', threshold);
});
For the median, you can do that in a similar way. But, the median is a SINGLE image, so you cannot map over it (which gave the error):
var NDWImedian = calcNDWI(median);
var histogram = ee.Dictionary(NDWImedian.reduceRegion({
reducer: ee.Reducer.histogram(100),
geometry: AOI_subset,
scale: 30,
bestEffort: true
}).get('NDWI'));
var threshold = otsu(histogram);
var waterMask = NDWImedian.lt(ee.Number(threshold)).rename('waterMask');
var median = median.addBands([NDWImedian, waterMask]).set('OtsuThresh', threshold);
Then visualize some stuff in the console and map. Note that inside a mapped function, occuring on the server-side, you cannot print something (e.g. the histogram), so I did that only for the median image:
// Print
print('size full collection', sorted.size());
print('The full collection', mappedCollection);
print('Histogram of the median', ui.Chart.image.histogram(median.select('NDWI'), AOI_subset, 30));
print('Otsu thresholds', mappedCollection.aggregate_array('OtsuThresh'));
// Make a variable of visualization parameters.
var visParams = {bands: ['B4', 'B3', 'B2'], min: 0, max: 0.35};
var ndwiViz = {min: 0.01, max: 0.75, palette: ['2ca25f', '0000FF'], bands: 'NDWI'};
Map.addLayer(median.updateMask(median.select('waterMask')), visParams, 'True color median water masked');
Map.addLayer(mappedCollection.first().updateMask(mappedCollection.first().select('waterMask')), visParams, 'True color first image water masked');
Link script
When you select the QA band, the QA image has only one band (you selected one image). Applying a function expression on that image with other band numbers than zero is not possible, because there is only one band in that image, thus:
// Select the QA band.
var QA = image.select('ET_QC');
var cloud = getQABits(QA, 3, 4, 'cloud_state')
.expression("b(0) == 1 || b(0) == 2"); // sélection des deux bits que l'on dégage
AND
// Select the QA band.
var QA = image.select('ET_QC');
// Get the internal_cloud_algorithm_flag bit.
var qscore = getQABits(QA, 5, 7, 'quality score')
.expression("b(0) == 2 || b(0) == 3 || b(0)==4"); // sélection des deux bits que l'on dégage
Link code
Best Answer
You just need to indicate which values from the SCL band you are interested in and the apply that mask to each image. Although you can indicate the values one by one, it is easier to use
and
andor
withlt
(less than) orgt
(greater than) operators to select the desired SCL values.