0

I want to calculate the SAVI in Google Earth Engine. I am using the formula as below:

((NIR-Red)/(NIR+Red+0.5))*1.5

The value range should come between -1 to 1.

I am using Sentinel 2 image. But after the calculation, the lower value range is within -1. But the upper-value range is going beyond 1. I am using the following code below.

Am I calculating it in the wrong way?

    //Load the study area
var studyarea = ee.FeatureCollection('users/swadhinakoley/Hazaribagh_geo');
Map.addLayer(studyarea, {}, 'studyarea');

/**
 * 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);
}

var S2_display = {bands: ['B4', 'B3', 'B2'], min: 0, max: 3000};

function addsa(input){
  var NIR = input.select('B8');
  var RED = input.select('B4');
  var sa_neu = NIR.subtract(RED);
  var sa_deno = NIR.add(RED).add(0.5);
  var sa = sa_neu.multiply(1.5).divide(sa_deno).rename('savi');
  return input.addBands(sa);
}

var S2 = ee.ImageCollection("COPERNICUS/S2")
  .filterDate('2019-04-15', '2019-05-31')
  .filterMetadata('CLOUDY_PIXEL_PERCENTAGE', 'less_than', 1)
  .map(function(image){return image.clip(studyarea)})
  .map(addsa);

var savi_S2 = S2.select('savi').max();

Export.image.toDrive({
  image: savi_S2,
  description: 'SAVI_Gumla2_Z',
  scale: 10,
  region: geometry6
});

1 Answer 1

1

If you look at the band description in the dataset catalog, you'll notice that the the red and NIR band have a scale of 0.0001, meaning the values are between 0 and 10000 instead between 0 and 1. So, you need to multiply your bands with the scale.

input = input.multiply(0.0001)

For a simple normalized difference, this makes no difference, but in this case it does matter. With the correctly scaled bands, if NIR = 1 and Red = 0, you'll get (1/(1+0.5))*1.5, which is 1. NIR = 100000 and Red = 0, you'll get (10000/(10000+0.5))*1.5 which is close to 1.5.

I typically use expression strings for non-trivial calculations. Here's how it would look for you, just copy/pasting the formula you had in the question:

function addsa(input) {
  var sa = ee.Image().expression('((NIR-Red)/(NIR+Red+0.5))*1.5', {
    NIR: input.select('B8').multiply(0.0001),
    Red: input.select('B4').multiply(0.0001)
  }).rename('savi')
  return input.addBands(sa)
}
1
  • Okay! Now I get it. Thanks! Feb 19, 2022 at 11:04

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.