0

I am attempting to compute NDWI and extract a water body by using the condition NDWI > 0. Then, I plan to convert the extracted water body from an image to a vector, and use it to clip an ImageCollection in Google Earth Engine. However, I am encountering the following error:

"Image.ReduceToVectors: First band ('NDWI) of image must be integral"

How can I fix this problem?

Below is my written code:

var aoi = 
    /* color: #98ff00 */
    /* shown: false */
    ee.Geometry.Polygon(
        [[[-79.27637646484375, 44.791912158148946],
          [-79.5043427734375, 44.680702676974754],
          [-79.61695263671875, 44.53404856957901],
          [-79.75977490234375, 44.428228350736454],
          [-79.6361787109375, 44.22782207859495],
          [-79.50159619140625, 44.14313192011186],
          [-79.32581494140625, 44.24553252712021],
          [-79.04841015625, 44.36346595637119],
          [-79.22419140625, 44.71779626807499]]]);
/**
 * Function to mask clouds using the Sentinel-2 QA band
 * @param {ee.Image} image Sentinel-2 image
 * @return {ee.Image} cloud masked Sentinel-2 image
 */
function maskS2clouds(image) {
  var qa = image.select('QA60');

  // Bits 10 and 11 are clouds and cirrus, respectively.
  var cloudBitMask = 1 << 10;
  var cirrusBitMask = 1 << 11;

  // Both flags should be set to zero, indicating clear conditions.
  var mask = qa.bitwiseAnd(cloudBitMask).eq(0)
      .and(qa.bitwiseAnd(cirrusBitMask).eq(0));

  return image.updateMask(mask).divide(10000);
}

print('aoi info', aoi.getInfo())

// Funcion to clip the sentinel bands
function clipping(im){
   return im.clip(aoi)
}

// Function to clip the sentinel bands using waterbody
function clipping_w(im){
   return im.clip(water_body_Vector)
}

// Function to get Sentinel 2A images for an aoi and specific date
function getSentinel2WithinDateRange(start,end,aoi){
  var sentinel2 = ee.ImageCollection('COPERNICUS/S2_SR_HARMONIZED')
                    .filterBounds(aoi)
                    .filterDate(start, end)
                    .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 20))
                    .map(maskS2clouds);
                    
  return sentinel2.map(clipping)
}

var date_start = '2025-08-04'
var date_end = '2025-08-04'

var collections_1 = getSentinel2WithinDateRange(date_start, date_end,aoi)
print('Collection info', collections_1.getInfo())

var visualization = {
  min: 0.0,
  max: 0.5,
  bands: ['B4', 'B3', 'B2'],
};

Map.centerObject(aoi)

var collections_med = ee.ImageCollection(collections_1.median());
var collections_mosaic = collections_med.mosaic();

// Compute NDWI
var green = collections_mosaic.select(['B3']);
print('green info', green.getInfo())
var nir = collections_mosaic.select(['B8'])
print('nir info', nir.getInfo())

var NDWI = green.subtract(nir).divide(green.add(nir)).rename('NDWI');
print('NDWI info', NDWI.getInfo())

var ndwiViz = {min: -1, max: 1, palette: ['black', 'white','blue']};
// Map.addLayer(NDWI, ndwiViz, 'NDWI');

var water_body = NDWI.updateMask(NDWI.gte(0))
print('water_body info', water_body.getInfo())

Map.addLayer(water_body, ndwiViz, 'water body');

var projection = water_body.projection()

var water_body_Vector=water_body.reduceToVectors({
   geometry: water_body.geometry().getInfo(),
   crs: projection,
   scale: 1000, // scale
   geometryType: 'polygon',
   eightConnected: false,
   labelProperty: 'zone',
   bestEffort: true,
   maxPixels: 1e13,
   tileScale: 3 // In case of error.
});

var collections_mosaic_WC = ee.ImageCollection(collections_mosaic).map(clipping_w)
print('Collection clipped by waterbody', collections_mosaic_WC.getInfo())

2 Answers 2

0

The error you're getting is because ee.Image.reduceToVectors tries to connect pixels with the same values into vector features, which isn't possible with floating point (decimal) images. Your image needs to be an integer datatype to avoid that error.

Assuming that you want one feature anywhere that NDWI >= 0, you could instead do:

var water_body_Vector=NDWI.gte(0).selfMask().reduceToVectors({
   geometry: aoi,
   crs: projection,
   scale: 1000, // scale
   geometryType: 'polygon',
   eightConnected: false,
   labelProperty: 'zone',
   bestEffort: true,
   maxPixels: 1e13,
   tileScale: 3 // In case of error.
});

NDWI.gte(0) returns an integer image (0 or 1), and selfMask removes the zero values so that you only get 1 feature representing water.

Also note that I changed the geometry parameter to aoi instead of the image geometry. Applying processing to an image (like calculating NDWI) causes it to lose its geometry data and become "unbounded", which would have caused another error.

1
  • Excellent. Thank you so much. Commented Nov 21, 2024 at 2:00
0

Your premise seems wrong. You don't need to convert the raster to a vector just to use it on another raster. You can simply mask one image using another image, directly. (You're also turning a lot of single images into collections for no reason).

var result = collections_1.median().updateMask(NDWI.gte(0))

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.