Calculate proportion of study area covered by image on Google Earth Engine using a pixel count

I want to calculate the proportion of a study area that is covered by (non null) pixels within an image. I have seen examples that do similar counts (here, here, and here), and followed code from here, but it doesn't seem to give the correct answer.

``````// get aoi feature
var aoi_ext = ee.Geometry.Polygon(
[[-3.0,53.0],
[-2.5,53.0],
[-2.5,53.5],
[-3.0,53.5],
[-3.0,53.0]]
);

// Get image collection from Sentinel 2
var collection = ee.ImageCollection("COPERNICUS/S2_SR")
.filterBounds(aoi_ext) // just images intersecting with this
.filterDate('2017-05-01', '2018-06-01') // %Y-%m-%d
.select(['B2', 'B3', 'B4', 'B5', 'QA60'])
.map(function(image) { return image.clip(aoi_ext); }) // clip here to mask extent
;

print('no. images', collection.size());

// Look at first image
var img1 = ee.Image(collection.first());
print('image 1', img1);

// Display image
Map.addLayer(img1, {bands:['B2'], min: 0, max: 3000}, 'image 1');
Map.centerObject(aoi_ext);

// calculate number of all pixels in aoi

// get an image of aoi
var aoi_img = ee.Image(1).clip(aoi_ext);

// count pixels in aoi image
var totPixels = ee.Number(aoi_img.reduceRegion({
reducer: ee.Reducer.count(),
scale: 10,
maxPixels: 999999999,
}).values().get(0));

// Count the non zero/null pixels in the image within the aoi
var actPixels = ee.Number(img1.select('B2').reduceRegion({
reducer: ee.Reducer.count(),
scale: 10,
geometry: aoi_ext, // need it here
maxPixels: 999999999,
}).values().get(0));

// calculate the perc of cover
var pcPix = actPixels.divide(totPixels).multiply(100);

print('pixels in image:', actPixels, 'pixels in aoi', totPixels);

print('% cover', pcPix);

``````

Looking at the display, I would estimate that about 15% was covered. With other images, it also clearly does not do the calculation I expect. I also tried masking the image with the result from a `.gte()` call, but it gives the same result.

You should restructure the code a bit. Unmask does (in your case) not unmask pixels outside the image extent. Thus, your variable `totPixels` is not right. Make an unbounded constant image, and apply `reduceRegion` with the crs and scale argument to calculate the number of total pixels with the same projection as your image:

``````// calculate number of all pixels in aoi

// count pixels in aoi image
var totPixels = ee.Number(ee.Image(1).reduceRegion({
reducer: ee.Reducer.count(),
geometry: aoi_ext,
scale: 10,
maxPixels: 999999999,
}).values().get(0));

// Count the non zero/null pixels in the image within the aoi
var actPixels = ee.Number(img1.select('B2').reduceRegion({
reducer: ee.Reducer.count(),
scale: 10,
geometry: aoi_ext,
maxPixels: 999999999,
}).values().get(0));

// calculate the perc of cover
var pcPix = actPixels.divide(totPixels).multiply(100);
``````

Link example, with an addition to map it over the full collection. Two additional notes: clipping is generally not necesary and when working with Sentinel-2 imagery, always consider first making daily composites. Then, you'll have unbounded composite images, which will work with the previous example.

• Thanks. There's a typo in your code here (carried through from the complete example) in totPix, crs should read "crs: img1.select('B2').projection()" so that it works with above example. Also, just to clarify, it's the clip that isn't somehow? extending beyond the image in my example? Unmask refers to the previous example.
– CCID
Apr 5 '20 at 7:36