# How to find the frequency of pixel categories inside a geometry (Google Earth Engine)

The pixels of a certain Image are classified into 4 categories. I want to count how many pixels within a certain geometry fall in each category.

I thought my code below was doing pretty much that. However, there are two things about the results that I find very odd.

• Thing #1: the counts have decimal places. They should be integers, no? They are, after all, counts.

• Thing #2: I have two geometries with the same area. The number of pixels inside them should be, at least to an approximation, the same. That, however, is not the case. The total number of "pixels" in one geometry is more than twice the number of pixels in the other geometry.

These two facts lead me to believe that I am not achieving what I am trying to achieve. I'm stuck.

Am I achieving what I am trying to achieve?

Here's my code. You can run it in Google Earth Engine following this link. At the end of the code, I print the frequencies of each category in each geometry. In the first, the total frequency is 24 + 41616.96 +3019.09 + 26091.79 = 70751.85. In the second, we get 25.20 + 1706.94 + 1715.46 + 28427.35 = 31874.97.

``````// imports
var jrc2003 = ee.Image("JRC/GSW1_0/YearlyHistory/19"),
pt1 = /* color: #d63000 */ee.Geometry.Point([-64.64, -9.27]),
pt2 = /* color: #98ff00 */ee.Geometry.Point([-51.77, -3.13]);

// select the image band
var water = jrc2003.select(['waterClass'])

// create buffers
var bf1 = pt1.buffer(10 * 1000);
var bf2 = pt2.buffer(10 * 1000);

// areas of the buffers I just created -- they are the same
print('Area of bf1 in km2:', bf1.area().divide(1000 * 1000));
print('Area of bf2 in km2:', bf2.area().divide(1000 * 1000));

// this is what I think I should do to get the count of pixels,
// within each geometry, in each category
var dic1 = water.reduceRegion({
reducer  : ee.Reducer.frequencyHistogram(),
geometry : bf1,
scale:30,
maxPixels: 1e9});

var dic2 = water.reduceRegion({
reducer  : ee.Reducer.frequencyHistogram(),
geometry : bf2,
scale:30,
maxPixels: 1e9});

// print histograms -- results look odd to me
print('Hist 1', dic1);
{
"waterClass": {
"0": 24,
"1": 41616.96470588233,
"2": 3019.090196078431,
"3": 26091.796078431376
}
}

print('Hist 2', dic2);
{
"waterClass": {
"0": 25.20392156862745,
"1": 1706.9450980392155,
"2": 1715.4666666666667,
"3": 28427.356862745102
}
}
``````

The frequencies are decimals because they are square pixels cut at angles by the buffer.

The sum of frequencies in each buffer do not add to the total because most of each buffer is covered by null values. The frequencies are only reporting data values. For example, bf1 sums to 70752 pixels. Pixel size = 30 * 30 m. Total area of pixels with data = 70752 * 30 * 30 / 1000000 = ~64 km^2. bf2 data area = ~29 km^2.

bf1:

bf2: edit:

``````// imports
var jrc2003 = ee.Image("JRC/GSW1_0/YearlyHistory/19"),
pt1 = /* color: #d63000
*/ee.Geometry.Point([-64.63881572813477,-9.268996723190652]),

// select the image band
var water = jrc2003.select(['waterClass'])
Map.addLayer(water, {'bands': 'waterClass', 'min': 0, 'max':5})
// create buffers
var bf1 = pt1.buffer(30);
print('Area of bf1 in m2:', bf1.area());

var dic1 = water.reduceRegion({
reducer  : ee.Reducer.frequencyHistogram(),
geometry : bf1,
scale:30,
maxPixels: 1e9});

print('Hist 1', dic1);
``````

Using the code above, buffer 30 m (area = 2794 m^2), two data pixels, two no data pixels (each pixel = 900 m^2), the following object is returned:

``````waterClass: Object (2 properties)
1: 0.7647058823529411
2: 0.8
``````

... which is consistent with my previous claims that: a) frequencies report partial pixels (each quadrant is ~699 m^2, or 77% of a 900 m^2 pixel), and b) only pixels containing data values are reported. • Thanks, @phloem. Can you provide code showing that the number of pixels masked + number of pixels in each category is roughly the same in the two buffers?
– djas
Jul 13, 2019 at 1:26
• That sounds like homework for me :). You've shown that each buffer is 310 km^2, and you can visually see that bf1 is about 20% that area and bf2 is about 10%. I suppose you can take it or leave it. Jul 13, 2019 at 5:42
• Not at all. You made a claim I just asked you to add proof. The same actually applies for your claim about pixel fractions. As is, I need to take your word for it. It's just an impression, but it seems to me that the standards on GIS Stack Exchange are usually lower than those on SO.
– djas
Jul 13, 2019 at 22:14