3

I would like to calculate the area of all non-zero pixels on multiple bands of an image. My idea was to use

var areaImage = image.multiply(ee.Image.pixelArea());

To do that I will need an image where pixel values equal 1, so I was trying to use

image.reduce(ee.Reducer.anyNonZero());

However, since I am using a multi-band image, I receive a flattened image with only 1 band.

How could I assign all non-zero pixels a value of 1 across all bands without losing the bands? Or is there a smarter way to go about it?

Here is the code I tried:

//----load MCD64A1 Version 6 Burned Area and create a multi-band image

var datasetAll = ee.ImageCollection(MODISglobal500)
                  .filter(ee.Filter.date('2000-01-01', '2019-12-31'))
                  .filterBounds(border);

var DSall1B = datasetAll.select('BurnDate')

var DSallImage = DSall1B.toBands()

//----convert pixels to value = 1

var ImageValue1= DSallImage.reduce(ee.Reducer.allNonZero())

//----create an image with pixels value = area

var ImageValueArea = ImageValue1.multiply(ee.Image.pixelArea())

2 Answers 2

1

Right now you are making one design mistake and one fatal error in your code.

The design mistake is that you shouldn't convert your ImageCollection to bands. Instead keep it as a collection and map over it. Then you won't have the issue of loosing your bands.

Your fatal error is the use of ee.Reducer.allNonZero(). If you look at the documentation you will notice, that this reducer will only return 0 or 1 depending on if all of the values supplied to it are non zero. What you want is to count the number of non zero pixels in an image.

This is how you would fix both of those things:

var datasetAll = ee.ImageCollection(MODISglobal500)
                  .filter(ee.Filter.date('2000-01-01', '2005-12-31'))
                  .filterBounds(region);

var DSall1B = datasetAll.select('BurnDate')

var maskAndArea = function(burnImage){
  var mask = burnImage.gt(0)
  var area = ee.Image.pixelArea()
                     .mask(mask)
                     .reduceRegion({
                       reducer: ee.Reducer.sum(), 
                       geometry: region,
                       scale: 500
                     })

  return(area.toImage())
}

var burnedArea = DSall1B.map(maskAndArea)

print(burnedArea)

A few things to note: First, the scale parameter has to be set accurately for the calculation to make sense. Second, you might want to change the output to something other than scale.toImage() because its not really necessary since for each Acquisition only one a single number is returned.

0

I think you're on the right track. I believe this should work:

var image = ee.Image('COPERNICUS/S2_SR/20200101T100319_20200101T100321_T32TQM')
  .normalizedDifference(['B8', 'B4'])
  .gt(0.8)

Map.addLayer(image)
Map.centerObject(image)

var area = ee.Image.pixelArea()
  .updateMask(image) // Your image contains 0s and 1s - it's a mask
  .reduceRegion({
    reducer: ee.Reducer.sum(),
    geometry: image.geometry(),
    scale: 30,
    maxPixels: 1e12
  }).getNumber('area')

print(area)  

https://code.earthengine.google.com/ffd21de76a66a5adca7d2620e700cc2f

1
  • maybe I did not understand your code completely, but the end result seems like a masked ee.Image.pixelArea(), which is a 1 band image. I needed to keep my multi-band image so Im not sure how to apply your suggestion. in any case, I created the 1 and 0 image by using the image.where(image, 1) function and it worked. also using image.not() two times seem to have the same affect. Not such an elegant solution but still worked.
    – Stavo
    Jan 24, 2020 at 9:38

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.