1

I am looking at the NDVI of various mangrove forests in the UAE. Using the .gt function I have binarily separated forests into not canopy versus canopy, based on an NDVI-value threshold. Then using ee.Reducer.sum() I managed to get the number of pixels in each mangrove site that are classified as "canopy".

If I wanted to know the size of each of those pixels in order to find out the total canopy size of each site, what should I do? I've tried the ee.Image.pixelArea() function but it doesn't seem to work or maybe I don't fully understand it.

My main train of thought was that just knowing the scale which is set at 10, shouldn't that be enough to find out the square meter coverage of 1 pixel?

3

(Almost) every map projection, including the one used in the Code Editor's interactive map, has a different scale at different points. Therefore, there is no single number which accurately describes the area of a pixel anywhere on the map.

ee.Image.pixelArea() may be used to determine the area of individual pixels so that you can perform accurate area calculations.

Generate an image in which the value of each pixel is the area of that pixel in square meters. The returned image has a single band called "area."

For example, if you add it to the map,

Map.addLayer(ee.Image.pixelArea());

then click the “Inspector” tab in the Code Editor and click on the map, then the inspector will report the area of the specific pixel you clicked on. This area depends on the zoom level and where you are.


In order to use pixelArea() with a sum or count reducer, the usually correct thing to do is to multiply the input image by pixelArea(). Thus, each pixel's value is multiplied (weighted, if you like) by that pixel's area, so the overall answer is a sum over the area rather than the pixels.

To illustrate, I've added a threshold and reduceRegion to Earth Engine's NDVI example:

var region = ee.Geometry.Polygon([[[-95.5, 39.5], [-95.5, 38.8], [-94.3, 38.8], [-94.3, 39.5]]], null, false);
Map.addLayer(region);
Map.setCenter(-94.84497, 39.01918, 8);

var img = ee.Image('MODIS/006/MOD09GA/2012_03_09');
var ndvi = img.normalizedDifference(['sur_refl_b02', 'sur_refl_b01']);

Map.addLayer(ndvi, {min: 0, max: 1}, 'NDVI');
var thresholded = ndvi.gt(0.35);

Map.addLayer(ee.Image.pixelArea(), {}, 'Area', false);
Map.addLayer(thresholded, {}, 'Thresholded');

print('Scale 100 m', thresholded.multiply(ee.Image.pixelArea()).reduceRegion({
  reducer: ee.Reducer.sum(),
  geometry: region,
  scale: 100,
}).get('nd'));
print('Scale 1 km', thresholded.multiply(ee.Image.pixelArea()).reduceRegion({
  reducer: ee.Reducer.sum(),
  geometry: region,
  scale: 1000,
}).get('nd'));

https://code.earthengine.google.com/91f1ec1f3d8d7e2e4e1942849bf645b9

Since thresholded has a value of either 0 or 1, multiplying it by the area, thresholded.multiply(ee.Image.pixelArea()), produces that pixel's contribution to the total area: either nothing or the area of the pixel.

(The same idea works if the input image is some sort of density value rather than a binary threshold: summing density times area gives a total quantity.)

In the example, I'm running the reduction twice, with two different scales. You can see that the results are approximately the same, indicating that the scale / pixel area has been compensated for.

4
  • Thank you so much! I tried the code but it didn't work towards the end as it said an error regarding the "nd" however that might be as my region was a feature collection and/or that I used a Landsat 8 image for NDVI as opposed to MODIS your example. Nonetheless, however, I altered the code to this: var A =canopy.multiply(ee.Image.pixelArea()).reduceRegion({ reducer: ee.Reducer.sum(), geometry: EasternMangroves, scale: 100 }); print('A', A); – badiskhiari Feb 23 at 11:40
  • I used that code with the geometry of each individual site, so a bit tediously I had to run it 11 times as I am studying 11 sites. For this example, it gave me: "B5: 141788.4688648897" so around 7.5 square km of tree canopy. – badiskhiari Feb 23 at 11:43
  • I have found one error, however, for one of my sites. When I reduce the binary of that site using var CanSum = canopy.reduceRegions({ reducer: ee.Reducer.sum(), collection: ROIEdit, scale: 10}); print('CanSum', CanSum); It says that in that site, there are 27.2 pixels with an NDVI higher than 0.3 thus classified as "1". However, when I use the ee.Image.pixelArea() and reudce it by the sum with a scale of 100, it prints out "0" do you know why that might be? – badiskhiari Feb 23 at 12:18
  • @badiskhiari Not enough information — for debugging it's really important to have a complete runnable script. Comments are not a good place for this (they are meant for discussing improvements to a question or answer); please post a new question with your problem. – Kevin Reid Feb 23 at 15:26

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.