# How to get rolling count of masked pixels in Google Earth Engine

Using the Global Forecast System from NOAA, which provides relative humidity (RH) estimates several hours in to the future (up to 16 days to be exact). I create a binary of the RH, call it leaf wetness, where >=90% is 1, otherwise, 0.

I am trying to come up with a way to count which pixels are greater than or equal to 90% RH for different lengths of time. The count tracks continuous state of >=90%, so if a pixel drops below 90% (would be a 0 in a binary mask), the tracker changes back to 0 and starts at one next time >=90%. I made a small mock data set to kind of illustrate what I mean. The columns "1", "2", "3", are pixels in binary images of the image collection (and their matching pixels in the new images) and the images (layers) of the collection are for the hours of the forecast. The 1s & 0s between the hour and the "|||" is that pixel's value at that hour. The rolling counts are on the right side of the "|||". Those would each be represented in their own layers that keep counts based on continuous 1 in the binary collection. The starting collection has as many images as hours to be forecast and the value in that starting collection are binary. I want the new images, one for each hour as well, to be the counts of continuity.

Time  1 2 3 ||| 1 2 3
00:00 1 0 1 ||| 1 0 1 = a new layer added to collection to represent the 1-hour counts
01:00 1 1 1 ||| 2 1 2 = a new layer added to collection to represent the 2-hour counts
02:00 1 1 0 ||| 3 2 0 = a new layer added to collection to represent the 3-hour counts
03:00 1 1 1 ||| 4 3 1 = a new layer added to collection to represent the 4-hour counts
04:00 1 0 0 ||| 5 0 0 = a new layer added to collection to represent the 5-hour counts
05:00 1 1 1 ||| 6 1 1 = a new layer added to collection to represent the 6-hour counts

In the example data above, the "pixel" (column) labelled "1" is always one, so the count layers keep accumulating by one. But in the "pixel" 2, if I check at 3am, it has had 3 continuous hours of 1, however by 4am, due to the pixel being 0 at that time, the layer for counting continuous positive values (which represents wetness for my needs) would have a 0 and would start at 1 next time there is another 1 for that pixel in the binary, in this case, 5am.

I have a script that can give me a cumulative count for a specified length of time. I don't know how to make it return to 0 and restart when a 1 occurs in a future hour. I hope that can be the basis for what I need.

var cou_h = ['Henderson'];
var st_c = ['North Carolina'];
var cobo4 = ee.FeatureCollection("TIGER/2016/Counties").filter(ee.Filter.inList('NAME', cou_h)).geometry();
var st_nc = ee.FeatureCollection("TIGER/2018/States").filter(ee.Filter.inList('NAME', st_c));
var hend = cobo4.intersection(st_nc);

// If you want to specify a particular forecast from the series,
// use 'forecast_hours' or 'forecast_time'. For example:
var colltrh = ee.ImageCollection("NOAA/GFS0P25")
.select(['temperature_2m_above_ground','relative_humidity_2m_above_ground'])
.filter(ee.Filter.eq('creation_time',ee.Date(0).update(2022,6,1,0,0,0).millis()))
//.filter(ee.Filter.eq('forecast_hours', 1))
.map(function(im){return im.clip(hend)});

// RH threshold function
var pos_leaf_wetness = function(im){
var plw = im.select('relative_humidity_2m_above_ground').gt(89).rename('leaf_wetness90');
}

var colltrh = colltrh.map(pos_leaf_wetness);

// Just lookin'...
print(colltrh,'thr');

var hours_m = 120
var timeStep = 1

// A time series to keep rolling counts of the positive thresholded values?
var timeSeries = ee.ImageCollection(
ee.List.sequence(0, hours_m, timeStep)
.map(function (hourly) {
var counting = colltrh.select('leaf_wetness90')
.filterDate(start, end)
.sum();
return counting
.set('system:time_start', start.millis())
.set('empty', counting.bandNames().size().eq(0))
})
);

// Lookin around some more.
print(timeSeries,'timeseries');

• This post reminds of analyzing runs in arrays - you might be able to modify the procedure described in this blog post for your purpose: medium.com/google-earth/runs-with-arrays-400de937510a Nov 16, 2022 at 16:16
• @JustinBraaten thanks for the link. Daniel's answer works. I've hit a hiccup in further processing as I'm trying to merge the result from his code with the starting image collection and there are duplicate images I'm trying to eliminate. I'm still trying to figure this out. May post another question soon whether or not I can figure this out, but I think I'm close to what I want now. Nov 16, 2022 at 16:37

You can iterate() your collection, inspect the last value to do the accumulation.

var date = '2022-06-01'
var humidityThreshold = 90
var hours = 30

var collection = ee.ImageCollection("NOAA/GFS0P25")
.select('relative_humidity_2m_above_ground')
.filter(ee.Filter.gte('forecast_time', ee.Date(date).millis()))
.filter(ee.Filter.eq('forecast_hours', 1))
.sort('forecast_time')
.map(function (image) {
return image
.gte(humidityThreshold)
.copyProperties(image, image.propertyNames())
})

var counts = ee.ImageCollection(collection.iterate(
function (image, acc) {
image = ee.Image(image)
acc = ee.ImageCollection(acc)
var last = ee.Image(acc.get('last'))
.where(image.not(), ee.Image(0))
.rename('count')
.byte()
return acc.merge(ee.ImageCollection([count]))
.set('last', count)
},
ee.ImageCollection([])
.set('last', ee.Image(0))
))