Dictionary.get: Dictionary does not contain key: bucketMeans Error when trying to apply Otsu threshold
I am trying to apply Otsu's threshold to remove water from my NDVI image. But when running the code I get the error:
ImageCollection (Error)
Error in map(ID=1_2_LE07_020039_20220510):
Dictionary.get: Dictionary does not contain key: bucketMeans.
The image shows nothing when I try to display the image with Map.addLayer, so they probably have null. I am wondering if there's anyway to filter them out so that I don't get the error. Or any other idea would be helpful.
var PEI =
ee.Geometry.Polygon(
[[[-88.64042172041307, 30.446701603950796],
[-88.64042172041307, 30.32290398952697],
[-88.49004635420214, 30.32290398952697],
[-88.49004635420214, 30.446701603950796]]], null, false);
Map.centerObject(PEI, 15)
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_func = function(image) {
image = ee.Image(image).select('NDVI')
var histogram = image.reduceRegion({
reducer: ee.Reducer.histogram()
.combine('mean', null, true)
.combine('variance', null, true),
geometry: PEI,
scale: 10,
bestEffort: true
});
var threshold = otsu(histogram.get('NDVI_histogram'));
var water_removed = image.gt(threshold).selfMask();
return water_removed;
};
var addNDVI = function(img) {
var ndvi = img.normalizedDifference(['B5','B4']).rename('NDVI')
return img.addBands(ndvi)
}
var addNDVIpre8 = function(img) {
var ndvi = img.normalizedDifference(['B4','B3']).rename('NDVI')
return img.addBands(ndvi)
}
var landsat5 = ee.ImageCollection("LANDSAT/LT05/C02/T1_TOA").filterBounds(PEI)
.filterMetadata('CLOUD_COVER', 'less_than', 20)
.select(['B5', 'B4', 'B3', 'QA_PIXEL'])
.map(addNDVIpre8)
print('l5', landsat5)
var landsat7 = ee.ImageCollection("LANDSAT/LE07/C02/T1_TOA").filterBounds(PEI)
.filterMetadata('CLOUD_COVER', 'less_than', 20)
.select(['B5', 'B4', 'B3', 'QA_PIXEL'])
.map(addNDVIpre8)
print('l7', landsat7)
var landsat8 = ee.ImageCollection("LANDSAT/LC08/C02/T1_TOA").filterBounds(PEI)
.filterMetadata('CLOUD_COVER', 'less_than',20)
.select(['B5', 'B4', 'B3', 'QA_PIXEL'])
.map(addNDVI)
print('l8', landsat8)
var landsat = landsat5.merge(landsat7).merge(landsat8)
print('total', landsat)
//var landsatlist = landsat.toList(landsat.size());
var landsat_otsu = landsat.map(threshold_func)
print(landsat_otsu)
Link: https://code.earthengine.google.com/46a1c8ed3b8ae773fea005a65ac87576