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
Best Answer
It's going to be something like this:
I took the liberty of removing some redundant code from your function. Watch out for a reduction inside a map() for the reasons described here. Also, note that you may get no pixels in the result (
waterArea
=0) if the region overlaps the image footprint, but no valid pixels.