0

I have a code that analyze NDVI for any shapfile and then compute the mean and the standard deviation for each image. My goal is to be able to do more calculation with the statistics I have calculated, but seems like because it's a dictionary I can't calculte.

I want to calculate the next things-

  1. Standard deviation/2
  2. mean+ (standard deviation/2)
  3. mean-(standard deviation/2)

I have tried to calculate it by I get ''NaN'' all the time.

this is the code I have written-


/**
 * 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)
  .copyProperties(image, ['system:time_start']);
}

// Map the function over one year of data and take the median.
// Load Sentinel-2 TOA reflectance data.
var dataset = ee.ImageCollection('COPERNICUS/S2')
                  .filterDate('2019-06-01', '2019-06-30')
                  // Pre-filter to get less cloudy granules.
                  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 20))
                  .select('B1','B2','B3','B4','B8','QA60')
                  .filterBounds(geometry)
                  .map(maskS2clouds);

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

var clippedCol=dataset.map(function(im){ 
   return im.clip(geometry);
});

//test if clipping the image collection worked
Map.centerObject(geometry,9);
Map.addLayer(clippedCol.median(), rgbVis, 'RGB');

//function to calculate NDVI
var addNDVI = function(image) {
  var ndvi = image.normalizedDifference(['B8', 'B4'])
  .rename('NDVI')
  .copyProperties(image,['system:time_start']);
  return image.addBands(ndvi);

};

//NDVI to the clipped image collection
var withNDVI = clippedCol.map(addNDVI).select('NDVI');


var colorizedVis = {
  min: 0.0,
  max: 1.0,
  palette: [
    'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718', '74A901',
    '66A000', '529400', '3E8601', '207401', '056201', '004C00', '023B01',
    '012E01', '011D01', '011301'
  ],
};


//analyze images from image collection collection
var listOfImages = withNDVI.toList(withNDVI.size());
var listOfNumbers =[0];

for (var i in listOfNumbers) {
  var image = ee.Image(listOfImages.get(listOfNumbers[i]));
  var meanDictionary = image.reduceRegion({
  reducer: ee.Reducer.mean(),
  geometry:geometry.geometry()
  });

 var STDDictionary = image.reduceRegion({
  reducer: ee.Reducer.stdDev(),
  geometry:geometry.geometry()

});

print(i,'mean',meanDictionary,'standard deviation',STDDictionary);

 }

var std2=STDDictionary/2;

My end goal is to be able to classify the image into 3 classes-

  1. pixels with value that is between mean-std/2 and mean+std/1
  2. pixels with higher value than mean+std2
  3. pixels with value that is smaller than mean-std2

1 Answer 1

1

The problem you have Reut, is that as you receive the result from the EarthEngine as a dictionary, you cannot do any calculations on it as is.

You first need to access the dictionary value, and you have to tell your code what to expect from it. Here is the code modification that should make it work.

var std2 = ee.Number(STDDictionary.get("NDVI")).divide(2);

print(std2)

Several things are going on here.

1) The center of all the brackets.

STDDictionary.get("NDVI")

This returns the value of the key "NDVI" from your dictionary.

2) Inform your code that it will be number.

ee.Number(STDDictionary.get("NDVI"))

This returns a number that is sitting of the server (ee.Number is a server value)

3) Divide the server number by 2

ee.Number(STDDictionary.get("NDVI")).divide(2);

You need to use the EE number function for divide. You CANNOT use the Javascript equivalent of "/" because your browser doesn't know what is there as it is sitting on the server.

4) You assign it to your std2 variable and print it.

var std2 = ee.Number(STDDictionary.get("NDVI")).divide(2);

print(std2)

From here on you can use the std2 to further your calculations. However, you must remember that the it is an ee. variable, so it is sitting on the server, and too manipulate it in any way you MUST use the ee.Number functions. You can find them in the docs ee.Number.

Also familiarise yourself with Earth Engine Objects to help you track down these bugs in the future. (it really took me a long time to grasp this concept.)

Your Answer

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

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