0

I am trying to create a time series of the total area of water pixels in a particular region using the ee.Image.pixelArea() method. I understand that this method creates a raster whereby the value of each pixel is the corresponding area of a specific pixel. This means that we would need a raster of strictly value 1 to multiply with that raster, to get the area, as is shown in Quantifying Forest Change and Calculating Area in Google Earth Engine.

I previously saw an answer to Counting number of pixel identified as water from a collection of landsat image using Google Earth Engine, which is similar to the output I want, except the answer does not convert the NDWI band to 1 (water pixels = 1, non-water = 0) but immediately multiplies the NDWI raster with the ee.Image.pixelArea(), which contradicts the two other articles i mentioned previously.

Despite me dividing the water pixels extracted by NDWI by itself (so everything = 1), my resultant values would be exactly the same if I had not done that (i.e. change water1 to water01, and erase the subsequent line where water01 = water1.divide(water1), which baffles me.

Can anyone provide some insight as to why this is so, or point out exactly what is wrong with my script?

// last modified on 9/7/2020
// script to extract total area of water pixels from given area (fp), using landsat 8
// two outputs: one where clouds are masked, one where clouds are not masked

var roi = ee.Geometry.Polygon([
  [[95.1,20.5],[95.3,21],[96.3,21],[96.1,20.5]]
  ]);
Map.centerObject(roi,10);

// loading image collection 
var landsat8= ee.ImageCollection('LANDSAT/LC08/C01/T1_SR').filterBounds(roi)
.filterDate('2013-01-01', '2015-07-31')
.filterMetadata("CLOUD_COVER","less_than",20);
  
var visParams = {
  bands: ['B4', 'B3', 'B2'],
  min: 0,
  max: 3000,
  gamma: 1.4,
};
Map.addLayer(landsat8, visParams,'original images');


// Function to extract water, then calculate area of water pixel 
var waterfunction = function(image){
  //add the NDWI band to the image
  var ndwi = image.normalizedDifference(['B3', 'B5']).rename('NDWI');
  //get pixels above the threshold
  var water1 = ndwi.gt(-0.2);
  //convert all pixels to value 1
  var water01 = water1.divide(water1);
  //extract only water pixels 
  image = image.addBands(water01).updateMask(water01);

// now to calculate water area, multiply water01 (all values are 1) by ee.Image.pixelArea; since that image gives us the area of each pixel
// then rename the band 
  var waterArea = water01
                         .multiply(ee.Image.pixelArea())
                         .rename('waterArea')
                        .divide(1e6);

// adding area of water as a band
  image = image.addBands(waterArea);

// calculate area 
  var stats = waterArea.reduceRegion({
    reducer: ee.Reducer.sum(), 
    geometry: roi, 
    scale: 30,
  })
  ;

  return image.set(stats);
};

// function to mask clouds out
function maskL8sr(image) {
  // Bits 3 and 5 are cloud shadow and cloud, respectively.
  var cloudShadowBitMask = (1 << 3);
  var cloudsBitMask = (1 << 5);
  // Get the pixel QA band.
  var qa = image.select('pixel_qa');
  // Both flags should be set to zero, indicating clear conditions.
  var mask = qa.bitwiseAnd(cloudShadowBitMask).eq(0)
                .and(qa.bitwiseAnd(cloudsBitMask).eq(0));
  return image.updateMask(mask);
}

// mapping water function over my collection 
var collection = landsat8.map(waterfunction);
print(collection,'collection');
var visParams2 = {min: -0.2, 
  max: 1, 
    bands: 'NDWI', 
    palette: ['00FFFF', '0000FF']};

var NDWICollection = collection.select('NDWI')
Map.addLayer(NDWICollection.first(), visParams2,'water');
//creating a chart 
var title = {
  title: 'Total area of water pixels (No clouds masked out)',
  hAxis: {title: 'Time'},
  vAxis: {title: 'Area (sq km)'},
};

// var cloudChart = ui.Chart.image.series({
//   imageCollection: collection.select('waterArea'), 
//   region: fp, 
//   reducer: ee.Reducer.sum(), 
//   scale: 30,
// })
// .setOptions(title);
// print(cloudChart);

// masking clouds, then mapping water function over the collection
var cloudlessCollection = landsat8.map(maskL8sr).map(waterfunction);
var title2 = {
  title: 'Total area of water pixels (Clouds masked out)',
  hAxis: {title: 'Time'},
  vAxis: {title: 'Area (sq km)'},
};
var cloudlessChart = ui.Chart.image.series({
  imageCollection: cloudlessCollection.select('waterArea'), 
  region: roi, 
  reducer: ee.Reducer.sum(), 
  scale: 30,
})
.setOptions(title2);
print(cloudlessChart);
1

This line already makes a binary map of values 1 (values greater than -0.2) and 0 (values lower than -0.2). No need to divide.

//get pixels above the threshold
var water1 = ndwi.gt(-0.2);
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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