0

I would like to use a function like argmax() on pixels of an image collection, but see no corresponding reducer function in GEE. I think I need a custom reducer because, as far as I can tell this doesn't exist.

None of the provided reducers do what I need. I can see the "minimum" pixel. But what I want to know is which layer has the minimum pixel (so really I need an argmin(), I guess List here: https://developers.google.com/earth-engine/apidocs/ee-reducer-max

For example, say I want to run a any neighborhood analysis at multiple scales and want to know at what scale is stdev minimzed.

I can

  1. create an image collection of the analysis at each scale, then
  2. check each corresponding pixels and see what the maximum value is.

But I am looking to find out which layer has the maximum value not the maximum itself (ie, argmin() not min()).

Is there a reducer function I am missing, or is there a clever way to combine reducers to get there?

Here is what I have so far:

// get imagery in AOI
var aoi = ee.Geometry.Polygon(
  [[[-84.10607,31.49740],
  [-84.07174,31.49740],
  [-84.07174,31.52689],
  [-84.10607,31.52689],
  [-84.10607,31.49740]]])
var img = ee.ImageCollection('USDA/NAIP/DOQQ')
    .filterBounds(aoi)
    .filter(ee.Filter.date('2015-01-01', '2018-09-10'))
    .first()
    .clip(aoi)
    
// convert image to monochrome
var makeMonochrome = function(image) {
  var mono = image.expression('RED + BLUE + GREEN', {
    'RED' : image.select('R'),
    'BLUE' : image.select('B'),
    'GREEN' : image.select('G')
  });
  return image.addBands(mono.rename('MONO'));
};

// focal analysis function for different scales
var myfun = function(img, dim) {
  var kern = ee.Kernel.circle(dim)
  var texture = img.reduceNeighborhood({
    reducer: ee.Reducer.stdDev(),
    kernel: kern,
  });
  return(texture)
}


img = makeMonochrome(img).select('MONO')
var scales = ee.Array([5, 10, 15])
var coll = scales.toList().map(function(scale) {return myfun(img, scale)})
coll = ee.ImageCollection(coll)
print(coll, 'collection')

// Gives the maximum variance... But I want to know *at which scale* max variance occurs
var reduced_coll = coll.reduce(ee.Reducer.max()); \\not what i need
//var reduced_coll = coll.reduce(ee.Reducer.argmax()); \\ doesn't exist

Map.addLayer(reduced_coll,{min: 0,max: 100}, 'reduced')
print(reduced_coll)

/// If argmax could be applied as a reducer and return the layeer number with the highest value, that would work fine for me!
print(scales.argmax()) // but i need min

1 Answer 1

0

This is possible using the numImputs argument to the max reducer. When numImputs is greater than 1, the reducer will 1) identify the maximum value of the first band, and 2) identify the corresponding value of any other bands.

First, you'll need to add an additional band to each image in coll to identify the scale of the image. I've modified myfun below with that change:

// focal analysis function for different scales
var myfun = function(img, dim) {
  var kern = ee.Kernel.circle(dim)
  var texture = img.reduceNeighborhood({
    reducer: ee.Reducer.stdDev(),
    kernel: kern,
  });
  // The "scale" band identifies the scale of each image
  var scale = ee.Image.constant(dim).int().rename("scale");
  return(texture.addBands(scale))
}

Now each image in coll has two bands: the standard deviation and the constant scale. Next, specify a numImputs of 2 when you make the max reducer.

var reduced_coll = coll.reduce(ee.Reducer.max(2)).rename(["max_stdDev", "scale"]);

The resulting image will have one band with the maximum standard deviation, and one band with the scale that had that maximum value (shown below).

The color-coded scale associated with the maximum value at each pixel

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.