I would like to derive the occurrence of surface water bodies from Sentinel-1 image collection in the Google Earth Engine.In my example I could already compute the water mask using Otsu’s method for image segmentation: https://code.earthengine.google.com/499580510635aa5f421886d4e409af03.
This procedure has now to be applied to the entire image collection, so that the variable threshold is recalculated for each image and then the water mask is determined.The occurrence of water bodies should be presented relatively (0%-no occurrence, 100%-always water present) as shown in Global Surface Water Explorer.
Does anyone have a solution or a hint for this?
Create the S1 image collection:
var s1 = ee.ImageCollection('COPERNICUS/S1_GRD')
.filterBounds(Map.getBounds(true))
.filterDate('2019-01-01','2019-12-31')
.filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV'))
.map(function(image){return image.clip(Map.getBounds(true))});
print(s1);
Otsu's method for image segmentation:
var histogram = image.select(s1_band).reduceRegion({
reducer: ee.Reducer.histogram()
.combine('mean', null, true)
.combine('variance', null, true),
geometry: polygon,
scale: 10,
bestEffort: true
});
print(histogram);
// Chart the histogram
print(Chart.image.histogram(image.select(s1_band), polygon, 10));
// Return the DN that maximizes interclass variance in S1-band (in the region).
var otsu = function(histogram) {
var counts = ee.Array(ee.Dictionary(histogram).get('histogram'));
var means = ee.Array(ee.Dictionary(histogram).get('bucketMeans'));
var size = means.length().get([0]);
var total = counts.reduce(ee.Reducer.sum(), [0]).get([0]);
var sum = means.multiply(counts).reduce(ee.Reducer.sum(), [0]).get([0]);
var mean = sum.divide(total);
var indices = ee.List.sequence(1, size);
// Compute between sum of squares, where each mean partitions the data.
var bss = indices.map(function(i) {
var aCounts = counts.slice(0, 0, i);
var aCount = aCounts.reduce(ee.Reducer.sum(), [0]).get([0]);
var aMeans = means.slice(0, 0, i);
var aMean = aMeans.multiply(aCounts)
.reduce(ee.Reducer.sum(), [0]).get([0])
.divide(aCount);
var bCount = total.subtract(aCount);
var bMean = sum.subtract(aCount.multiply(aMean)).divide(bCount);
return aCount.multiply(aMean.subtract(mean).pow(2)).add(
bCount.multiply(bMean.subtract(mean).pow(2)));
});
print(ui.Chart.array.values(ee.Array(bss), 0, means));
// Return the mean value corresponding to the maximum BSS.
return means.sort(bss).get([-1]);
};
var threshold = otsu(histogram.get(s1_band+'_histogram'));
print('threshold', threshold);
Note on a tripping hazard for calculating the occurence:
The .filterBounds method based of an area of interest also selects truncated satellite images. Unfortunately I have no solution to prevent this.