0

I am a new user on GEE. Currently, I found a code for creating a water occurrence on GEE, I tried to apply this code for my AOI, but it have some error while running this.

Error:

ImageCollection (Error) Filter.contains: Unable to use a collection in an algorithm that requires a feature or image. This may happen when trying to use a collection of collections where a collection of features is expected; use flatten, or map a function to convert inner collections to features. Use clipToCollection (instead of clip) to clip an image to a collection.

Here is the code link: https://code.earthengine.google.com/329d8fec48149147034f685fdfbbc730?hideCode=true

 var aoi = ee.FeatureCollection("FAO/GAUL_SIMPLIFIED_500m/2015/level0").filter(ee.Filter.eq('ADM0_NAME', 'Pakistan'));
Map.addLayer(aoi, {color: 'black'}, 'Study Area',1);
// Zoom to regions of interest
Map.centerObject(aoi);

// 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(aoi)
//.filterBounds(Map.getBounds(true))
.filterDate('2018-11-01','2019-10-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);

// 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)));
  });
  
// Return the mean value corresponding to the maximum BSS.
  return means.sort(bss).get([-1]);
};

// return image with water mask as additional band
var add_waterMask = function(image){
  // Compute histogram
  var histogram = image.select('VV').reduceRegion({
    reducer: ee.Reducer.histogram(255, 2)
      .combine('mean', null, true)
      .combine('variance', null, true), 
    geometry: aoi, 
    scale: 10,
    bestEffort: true
  });
  // Calculate threshold via function otsu (see before)
  var threshold = otsu(histogram.get('VV_histogram'));
  
  // get watermask
  var waterMask = image.select('VV_smoothed').lt(threshold).rename('waterMask');
  waterMask = waterMask.updateMask(waterMask); //Remove all pixels equal to 0
  return image.addBands(waterMask);
};

s1 = s1.map(add_waterMask);

//Calculating water occurrence
var min_occurence = 10;
var water_sum = s1.select('waterMask').reduce(ee.Reducer.sum());
var water_frequency = water_sum.divide(s1.select('waterMask').size()).multiply(100);
var water_frequency_masked = water_frequency.updateMask(water_frequency.gt(min_occurence));

//Add color bar
//base code adapted from: 
//https://gis.stackexchange.com/questions/290713/adding-map-key-to-map-or-console-in-google-earth-engine
//https://code.earthengine.google.com/9f890c110e98fa3391480543009c8028

function ColorBar(palette) {
  return ui.Thumbnail({
    image: ee.Image.pixelLonLat().select(0),
    params: {
      bbox: [0, 0, 1, 0.1],
      dimensions: '300x15',
      format: 'png',
      min: 0,
      max: 1,
      palette: palette,
    },
    style: {stretch: 'horizontal', margin: '0px 22px'},
  });
}
function makeLegend(lowLine, midLine, highLine,lowText, midText, highText, palette) {
  var  labelheader = ui.Label('Water occurrence during investigation period',{margin: '5px 17px', textAlign: 'center', stretch: 'horizontal', fontWeight: 'bold'});
  var labelLines = ui.Panel(
      [
        ui.Label(lowLine, {margin: '-4px 21px'}),
        ui.Label(midLine, {margin: '-4px 0px', textAlign: 'center', stretch: 'horizontal'}),
        ui.Label(highLine, {margin: '-4px 21px'})
      ],
      ui.Panel.Layout.flow('horizontal'));
      var labelPanel = ui.Panel(
      [
        ui.Label(lowText, {margin: '0px 14.5px'}),
        ui.Label(midText, {margin: '0px 0px', textAlign: 'center', stretch: 'horizontal'}),
        ui.Label(highText, {margin: '0px 1px'})
      ],
      ui.Panel.Layout.flow('horizontal'));
    return ui.Panel({
      widgets: [labelheader, ColorBar(palette), labelLines, labelPanel], 
      style: {position:'bottom-left'}});
}
Map.add(makeLegend('|', '|', '|', "0 %", '50 %', '100%', ['orange','yellow','lightblue','darkblue']));

// time-lapse animation
var timelapse = {
  bands: ["VV","VV","VV"],
  region: aoi,
  min: -20,
  max: 0,
  framesPerSecond: 5};
  
var animation = ui.Thumbnail({
  image: s1,
  params: timelapse,
  style: {
    position: 'bottom-left',
    width: '360px',
  }});

//Add layers ans animation to map
Map.addLayer(s1.median(),{bands: ['VV','VV','VV'],min: -20,max: 0,},'S1-image [median]');
Map.addLayer(water_frequency_masked,{min:min_occurence,max:100,palette:['orange','yellow','lightblue','darkblue']},'Percentage of annual water occurence');
Map.add(animation);

// Create and print a histogram chart
//Make time series of water pixels as area in km² within region
var ClassChart = ui.Chart.image.series({
  imageCollection: s1.select('waterMask'),
  region: aoi,
  reducer: ee.Reducer.sum(),
  scale: 100,
})
  .setOptions({
      title: 'Area of the identified water mask',
      vAxis: {'title': 'area'},
      lineWidth: 1.5,
      pointSize: 2
    });
ClassChart.style().set({
    position: 'bottom-right',
    width: '492px',
    height: '300px'
  });

Map.add(ClassChart);

//Create callback function that adds image to the map coresponding with clicked data point on chart
ClassChart.onClick(function(xValue, yValue, seriesName) {
    if (!xValue) return;  // Auswahl zurücksetzen
  
    // Show the image for the clicked date.
    var equalDate = ee.Filter.equals('system:time_start', xValue);
    //Find image coresponding with clicked data and clip water classification to aoi 
    var classification = ee.Image(s1.filter(equalDate).first()).clip(aoi).select('waterMask'); 
    var SARimage = ee.Image(s1.filter(equalDate).first());
        var date_string = new Date(xValue).toLocaleString('de-DE', {dateStyle: 'full', timeStyle: 'short' });
    //Make map layer based on SAR image, reset the map layers, and add this new layer
    var S1Layer = ui.Map.Layer(SARimage, {
      bands: ['VV'],
      max: 0,
      min: -20
    },'S1-Image ['+ new Date(xValue).toLocaleString('de-DE')+']');
    Map.layers().reset([S1Layer]);
    var visParamsS1Layer = {
      min: 0,
      max: 1,
      palette: ['#FFFFFF','#0000FF']
    };
    
    //Add water classification on top of SAR image
    Map.addLayer(classification,visParamsS1Layer,'water mask ['+date_string+']');
});
2
  • You're more likely to get help if you post your code here in a code block, rather than have people leave the site for an external link.
    – lambertj
    Dec 16, 2022 at 2:57
  • GEE already has a water occurrence layer, so you may not need to make one: developers.google.com/earth-engine/tutorials/…
    – GeoMonkey
    Dec 16, 2022 at 10:26

1 Answer 1

0

Your aoi is a feature collection and you need a geometry. So just transform the variable aoi:

// create aoi
var aoi = ee.FeatureCollection("FAO/GAUL_SIMPLIFIED_500m/2015/level0").filter(ee.Filter.eq('ADM0_NAME', 'Pakistan'));
// convert feature collection into geometry
var aoi = aoi.geometry().bounds();

There seems to be another error in the following line. I could not fixed it, so I commented it:

//.filter(ee.Filter.contains({leftField: ".geo", rightValue: aoi}))

After these changes, I got a “Too many pixels” error generating the chart. I set the scale to 1000 (more appropriate for a country-level analysis) and it works fine.

// Create and print a histogram chart
//Make time series of water pixels as area in km² within region
var ClassChart = ui.Chart.image.series({
  imageCollection: s1.select('waterMask'),
  region: aoi,
  reducer: ee.Reducer.sum(),
  scale: 1000, 
})
1
  • 1
    Thanks a lot. It works ! ^^ Dec 17, 2022 at 1:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.