I am rewriting a code to apply the edge Otsu method for a collection of image in GEE. My code is divided into 2 part, first I determined an image using the Canny edge detection, after that I used the Otsu to defined the optimized threshold on the image above, then I extracted the water_mask from the images. I got this error: " Layer error: Image.select, argument 'input': Invalid type. Expected type: Image. Actual type: ImageCollection." But when I set up the input, it was already a collection ? Here is my code: https://code.earthengine.google.com/2e95a8d056dbc5df21ddea06d762f923
function otsu(histogram) {
// make sure histogram is an ee.Dictionary object
histogram = ee.Dictionary(histogram);
// extract relevant values into arrays
var counts = ee.Array(histogram.get('histogram'));
var means = ee.Array(histogram.get('bucketMeans'));
// calculate single statistics over arrays
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);
// compute between sum of squares, where each mean partitions the data
var indices = ee.List.sequence(1, size);
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)));
});
// return the mean value corresponding to the maximum BSS
return means.sort(bss).get([-1]);
}
//Edge Otsu Algorithms
function edgeOtsu(image,kwargs) {
var geom = image.geometry()
// get list of band names used later
var bandList = ee.Image(image).bandNames();
var kwargKeys = [];
for(var key in kwargDefaults) kwargKeys.push( key );
var params;
var i,k,v;
// loop through the keywords and construct ee.Dictionary from them,
// if the key is defined in the input then pass else use default
params = ee.Dictionary(kwargs);
for (i=0;i<kwargKeys.length;i++) {
k = kwargKeys[i];
v = kwargDefaults[k];
params = ee.Dictionary(
ee.Algorithms.If(params.contains(k),params,params.set(k,v))
)
// parameters for all methods
var initialThreshold = ee.Number( params.get('initialThreshold') ),
reductionScale = ee.Number( params.get('reductionScale') ),
smoothing = ee.Number( params.get('smoothing') ),
bandName = ee.String( params.get('bandName') ),
connectedPixels = ee.Number( params.get('connectedPixels') ),
edgeLength = ee.Number( params.get('edgeLength') ),
smoothEdges = ee.Number( params.get('smoothEdges') ),
cannyThreshold = ee.Number( params.get('cannyThreshold') ),
cannySigma = ee.Number( params.get('cannySigma') ),
cannyLt = ee.Number( params.get('cannyLt') ),
maxBuckets = ee.Number( params.get('maxBuckets') ),
minBucketWidth = ee.Number( params.get('minBucketWidth') ),
maxRaw = ee.Number( params.get('maxRaw') ),
invert = params.get('invert'),
verbose = params.get('verbose').getInfo();
// get preliminary water
var binary = ee.Image(image).lt(initialThreshold).rename('binary');
// get canny edges
var canny = ee.Algorithms.CannyEdgeDetector(binary, cannyThreshold, cannySigma);
// process canny edges
var connected = canny.updateMask(canny).lt(cannyLt).connectedPixelCount(connectedPixels, true);
var edges = connected.gte(edgeLength);
edges = edges.updateMask(edges);
var edgeBuffer = edges.focal_max(smoothEdges, 'square', 'meters');
// get histogram for Otsu
var histogram_image = ee.Image(image).updateMask(edgeBuffer);
var histogram = ee.Dictionary(histogram_image.reduceRegion({
reducer:ee.Reducer.histogram(maxBuckets, minBucketWidth,maxRaw)
.combine('mean', null, true).combine('variance', null,true),
geometry: roi,
scale: reductionScale,
maxPixels: 1e13,
tileScale:16
}).get(bandName.cat('_histogram')));
var threshold = otsu(histogram_image);
// get watermask
var waterMask = ee.Image(image).select('VV_smoothed').gt(threshold).rename('waterMask');
waterMask = waterMask.updateMask(waterMask); //Remove all pixels equal to 0
return ee.Image(image).addBands(waterMask);
}}
/////////////////////////////////////////////////////////////////////////
var roi = ee.FeatureCollection("FAO/GAUL_SIMPLIFIED_500m/2015/level0").filter(ee.Filter.eq('ADM0_NAME', 'Pakistan'));
// convert feature collection into geometry
var roi = roi.geometry().bounds();
Map.addLayer(roi, {color: 'black'}, 'Study Area',1);
// Zoom to regions of interest
Map.centerObject(roi);
// import sentinel 1 and filter data series
var s1 = ee.ImageCollection('COPERNICUS/S1_GRD')
.filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV'))
.filter(ee.Filter.eq('instrumentMode', 'IW'))
.filter(ee.Filter.eq('orbitProperties_pass', 'ASCENDING'))
.filterBounds(roi)
.filterBounds(Map.getBounds(true))
.filterDate('2022-1-01','2022-12-31')
//.filter(ee.Filter.contains({leftField: ".geo", rightValue: aoi})) // Filter partial S1-Images of AOI
.map(function(image){return image.clip(Map.getBounds(true))})
.map(function(image){return image.addBands(image.select('VV').focal_median(parseFloat('50'),'circle','meters').rename('VV_smoothed'))}); // Smooth S1-Images
print(s1);
var kwargDefaults = {
'initialThreshold':-14,
'reductionScale': 180,
'smoothing': 100,
'bandName': "VV",
'connectedPixels': 100,
'edgeLength': 20,
'smoothEdges': 20,
'cannyThreshold': 1,
'cannySigma': 1,
'cannyLt': 0.05,
'maxBuckets': 255,
'minBucketWidth': 0.001,
'maxRaw': 1e6,
'invert':false,
'verbose': false
};
var s1_edge = edgeOtsu(s1,kwargDefaults);
Map.addLayer(s1_edge)