I have generated a segmentation using SNIC on GEE and calculated some statistics/features for each segment, using ee.Reducer e.g. mean, std, median, etc. I want to calculate more features based on my own equations. However, I didn't figure out how I can use a custom function inside the ee.Reducer. If there is no functionality for doing so, what optimal approach do you recommend me to calculate my custom statistics for each segment?

The script I'm using is something like the following:

var imageCollection = ee.ImageCollection('USDA/NAIP/DOQQ');
var geometry = /* color: #0b4a8b */ee.Geometry.Polygon(
        [[[-121.89511299133301, 38.98496606984683],
          [-121.89511299133301, 38.909335196675435],
          [-121.69358253479004, 38.909335196675435],
          [-121.69358253479004, 38.98496606984683]]], null, false);

var cdl2016 = ee.Image('USDA/NASS/CDL/2016');

var bands = ['R', 'G', 'B', 'N']
var img = imageCollection
    .filterDate('2015-01-01', '2017-01-01')
img = ee.Image(img).clip(geometry).divide(255).select(bands)
Map.centerObject(geometry, 13)
Map.addLayer(img, {gamma: 0.8}, 'RGBN', false)

var seeds = ee.Algorithms.Image.Segmentation.seedGrid(36);

// Run SNIC on the regular square grid.
var snic = ee.Algorithms.Image.Segmentation.SNIC({
  image: img, 
  size: 32,
  compactness: 5,
  connectivity: 8,
  seeds: seeds
}).select(['R_mean', 'G_mean', 'B_mean', 'N_mean', 'clusters'], ['R', 'G', 'B', 'N', 'clusters'])

var clusters = snic.select('clusters')
Map.addLayer(clusters.randomVisualizer(), {}, 'clusters')
Map.addLayer(snic, {bands: ['R', 'G', 'B'], min:0, max:1, gamma: 0.8}, 'means', false)

// Compute per-cluster stdDev.
var stdDev = img.addBands(clusters).reduceConnectedComponents(ee.Reducer.stdDev(), 'clusters', 256)

// Area, Perimeter, Width and Height
var area = ee.Image.pixelArea().addBands(clusters).reduceConnectedComponents(ee.Reducer.sum(), 'clusters', 256)

var minMax = clusters.reduceNeighborhood(ee.Reducer.minMax(), ee.Kernel.square(1));
var perimeterPixels = minMax.select(0).neq(minMax.select(1)).rename('perimeter');
Map.addLayer(perimeterPixels, {min: 0, max: 1}, 'perimeterPixels');

var perimeter = perimeterPixels.addBands(clusters)
    .reduceConnectedComponents(ee.Reducer.sum(), 'clusters', 256);

var sizes = ee.Image.pixelLonLat().addBands(clusters).reduceConnectedComponents(ee.Reducer.minMax(), 'clusters', 256)
var width = sizes.select('longitude_max').subtract(sizes.select('longitude_min')).rename('width')
var height = sizes.select('latitude_max').subtract(sizes.select('latitude_min')).rename('height')
  • Thank @DanielWiell for the reply. It's image regions generated by a segmentation. So, according to your comment, it seems that I can also convert my image regions to an array and then apply the map over it?
    – Federico
    May 12 '20 at 12:38
  • I added a snippet. As you can see, several features (like std, area, perimeter, etc.) are calculated for each region (i.e. image segment) using the respective built-in functions. Now, I want to calculate some other features for each region based on my own functions. Thank you
    – Federico
    May 12 '20 at 15:26
  • Thanks, I see. Since this isn't about reducing an image collection but connected components or neighbors, I'm unfortunately out of ideas. Sorry. May 12 '20 at 15:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.