I am working with the Global Forest Cover Change (GFCC) rasters for 2000 to create a forest quality score for 0.01 degree tiles (the percent of the tile with +50% forest cover, divided by the percent of the tile with +10% forest cover).

var gfcc00 = ee.ImageCollection('NASA/MEASURES/GFCC/TC/v3')
      .filter(ee.Filter.date('2000-01-01', '2000-12-31'))

var gfcc2000 = gfcc00.reduce(ee.Reducer.mean());

For simplicity, I wanted to produce per-tile counts of pixels with +50% FC and +10% FC. I did so by reclassifying the raster so that only the values that fall in this range are 1s, else zero.

var fifty00 = ee.Image(1)
          .where(gfcc2000.gte(50).and(gfcc2000.lte(100)), 1)
          .where(gfcc2000.lt(50), 0)
          .where(gfcc2000.gt(100), 0);

Then I used a reducer function, to sum up the pixel values.

var count50 = tiles1.map(function(feature) {
  return feature.set(fifty002.reduceRegion({
    reducer: ee.Reducer.sum(),
    geometry: feature.geometry(),
    scale: 30

I expected the image reducer to give me an integer value for each tile, but instead, it's a decimal value. Why is that? How do I get an integer value? Full code here.


When images are resampled to the chosen output resolution (scale when performing a reduceRegion), the input pixel grid and the output pixel grid are misaligned. This results in output pixels which are partially covered by the input pixels, and these values have mask values which are not 0 (no data) or 1 (full coverage) but a number in between.

Fractional mask values also appear at the edges of the area reduced over, since the geometry usually does not have edges that follow pixel boundaries.

In reduceRegion, these mask values are used as weights to the reducer, which scale the pixel's contribution to the sum (or other reduction). For example, if one of the 30-meter pixels has only a quarter of its area covered by the input data, then its mask value will be 0.25, and its value will be multiplied by 0.25 before being added to the sum.

Thus, your fractional result is not an error; it better reflects the area of the original data, which is not a whole number of 30-meter pixels. (It's not, however, the same as doing the computation at the original scale, because the lt and gt conditions were evaluated on the resampled data.)

It's possible to get an integer result by using ee.Reducer.sum().unweighted(), which causes the reducer to ignore fractional mask values and treat them as 1, but that will introduce a bias of over-counting areas.

An improvement unrelated to your question: getting an image equal to 1 in a certain range and 0 elsewhere can be done much simpler, because that's what the image boolean operations do by default; just use them directly without any where:

var fifty00 = gfcc2000.gte(50).and(gfcc2000.lte(100));

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.