Google Earth Engine – Data Extraction from Imagery Using neighborhoodToArray

google-earth-enginegoogle-earth-engine-javascript-apikernel densityquery

I am new to Google Earth Engine and I'm working with a dataset contained multiple points with lat/lon coordinate. I want to query these points and extract the band value in the form of 2D array of the 3×3 group of values of each point by using Sentinel-2 composite. As far as I know, neighborhoodToArray is powerful tool for doing that.

How could I compute the median/mean from these nested lists? (To give a single value for each band)

enter image description here

My code is as below:

https://code.earthengine.google.com/ed1182484bd4c19069a18ad204e63016

// Paracou 
var aoi = 
    /* color: #0b4a8b */
    /* shown: false */
    /* displayProperties: [
      {
        "type": "rectangle"
      },
      {
        "type": "rectangle"
      },
      {
        "type": "rectangle"
      },
      {
        "type": "rectangle"
      }
    ] */
    ee.Geometry.MultiPolygon(
        [[[[-52.6965668016105, 4.103697563685889],
           [-52.6965668016105, 4.028527912014533],
           [-52.66257784897378, 4.028527912014533],
           [-52.66257784897378, 4.103697563685889]]],
         [[[-52.944764020870714, 5.289271129398686],
           [-52.944764020870714, 5.247049874677615],
           [-52.91446578783849, 5.247049874677615],
           [-52.91446578783849, 5.289271129398686]]],
         [[[11.550656910465511, -0.15383260074272592],
           [11.550656910465511, -0.240177754768104],
           [11.645242329166683, -0.240177754768104],
           [11.645242329166683, -0.15383260074272592]]],
         [[[9.85547793421202, -1.8999002299831818],
           [9.85547793421202, -1.9469089457924809],
           [9.892556791633895, -1.9469089457924809],
           [9.892556791633895, -1.8999002299831818]]]], null, false);


// Load Sentinel-2 spectral reflectance data.
var filter = ee.Filter.and(
  ee.Filter.bounds(point),
  ee.Filter.date('2019-01-01', '2020-01-01')
  
  )
var S2composite = ee.ImageCollection(
    ee.Join.saveFirst('cloudProbability').apply({
        primary: ee.ImageCollection('COPERNICUS/S2_SR').filter(filter),
        secondary: ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY').filter(filter),
        condition: ee.Filter.equals({leftField: 'system:index', rightField: 'system:index'})
    })
  ).map(function (image) {
  var cloudFree = ee.Image(image.get('cloudProbability')).lt(30)
  return image.updateMask(cloudFree).divide(10000)
  })
   .select(
      ['B2','B3','B4','B8','B11','B12'],
      ['Blue','Green','Red','NIR','SWIR1','SWIR2'])
   .map(function(image) {
var ndvi = image.expression(
'((NIR - Red) / (NIR + Red))', {
  'NIR': image.select('NIR'),
  'Red': image.select('Red')
}).rename('NDVI');
return image.addBands(ndvi,null,true);
})
var median = S2composite.median();

var neighborhoods = median.neighborhoodToArray(ee.Kernel.square(1));
var extracted = neighborhoods.reduceRegions({
  collection: point,
  reducer: ee.Reducer.first(),
  scale: 25,  // meters
  tileScale:16
});
Map.centerObject(aoi, 3)
Map.addLayer(point);
print(point.limit(100))
print(extracted.limit(10));

Best Answer

These 3×3 group of values are ee.Array objects and they need to be converted in lists with 'toList' array method. Afterward, these nine elements lists can be flattened for extracting median/mean with its respective reducers methods.

Following code snippet returns, as dictionary, median values for blue, green, ndvi, nir, red, swir1, swir2 bands of ten first extracted points of 6038 possible. Complete code can be accessed here.

print("count points", point.size());

print("count extracted", extracted.size());

var extracted_list = extracted.toList(extracted.size());

extracted_list = extracted_list.slice(0,10);

var medianBandDict = extracted_list.map(function (ele){
  
  var blue_median = ee.Array(ee.Feature(ele).get('Blue')).toList()
            .flatten().reduce(ee.Reducer.median());

  var green_median = ee.Array(ee.Feature(ele).get('Green')).toList()
            .flatten().reduce(ee.Reducer.median());

  var ndvi_median = ee.Array(ee.Feature(ele).get('NDVI')).toList()
            .flatten().reduce(ee.Reducer.median());

  var nir_median = ee.Array(ee.Feature(ele).get('NIR')).toList()
            .flatten().reduce(ee.Reducer.median());

  var red_median = ee.Array(ee.Feature(ele).get('Red')).toList()
            .flatten().reduce(ee.Reducer.median());

  var swir1_median = ee.Array(ee.Feature(ele).get('SWIR1')).toList()
            .flatten().reduce(ee.Reducer.median());

  var swir2_median = ee.Array(ee.Feature(ele).get('SWIR2')).toList()
            .flatten().reduce(ee.Reducer.median());
  
  return {'blue_median': blue_median, 
          'green_median' :green_median, 
          'ndvi_median': ndvi_median, 
          'nir_median': nir_median, 
          'red_median': red_median,
          'swir1_median':swir1_median,
          'swir2_median': swir2_median
          };
  
});

print("medianBandDict", medianBandDict);

After running above code in GEE code editor, I got following result. It can be observed only two dictionaries (for first two points) of 10 selected printed points. You decide how to manipulate the 6028 remaining points (set as points property, export to drive, etc.).

enter image description here