1

I’ve found a great code which is built for finding peaks in arrays, which print the result in the console (Finding peaks and troughs in time series data in a 1D array - Javascript) . I would like to apply it on each pixel of an 8-day NDVI image collection. The result should be an image with the peak number in each pixel.

I tried to apply the .toArray() function to the image collection to obtain an array. Then I created a function “findPeaks” that should add a peak number Band to the image. Then I tried to apply this function to the array image using .map(findPeaks), but I get an error “array.map is not a function” Here you find the code https://code.earthengine.google.com/32e78cc57f87c05a76665ed0e8b6c720.

var aoi = 
      ee.Geometry.Polygon(
        [[[11.111455811313702, 46.3205838600638],
          [11.111455811313702, 46.31527834569152],
          [11.11800040131004, 46.31527834569152],
          [11.11800040131004, 46.3205838600638]]], null, false);
var ndvi_IC=ee.ImageCollection("LANDSAT/LC08/C01/T1_8DAY_NDVI")
    .filterDate('2020-04-01','2020-10-01')
    .filter(ee.Filter.bounds(aoi))
var array=ndvi_IC.toArray()
print(array)
//code from https://stackoverflow.com/questions/43567335/finding-peaks-and-troughs-in-time-series-data-in-a-1d-array-javascript
//I would like to obtain a new image presenting the number of peaks found for each pixel.


var findPeaks=function(array) {
  var start = 1;                        // Starting index to search
  var end = array.length - 2;           // Last index to search
  var obj = { peaks: [], troughs: []  };// Object to store the indexs of peaks/thoughs
  
  for(var i = start; i<=end; i++)
  {
    var current = array[i];
    var last = array[i-1];
    var next = array[i+1];
    
    if(current > next && current > last) 
        obj.peaks.push(i);
    else if(current < next && current < last) 
        obj.troughs.push(i);
   }
  var peaksNum=obj.peaks.size()
  return array.addBands(peaksNum);
}

 var arraywithpeaksBand=array.map(findPeaks)
 
 print(arraywithpeaksBand)

Thank you for your help, I’m new to GEE and coding.

Davide

1 Answers1

1

You cannot use javascript for loops, conditionals or even math on Earth Engine images. All the Earth Engine stuff happens somewhere else on a server, and all the javascript stuff happens in your browser. You have to essentially vectorize the code to work with earth engine operators.

What you want to know is, for each point in time, if it is higher than its previous or next neighbor. Then you count how many times that's true. You can do this with a technique called forward-differencing. See this article and this presentation.

// Count the number of peaks in a 1D array image.
var countPeaks = function(image) {
  // Compute the forward and backwards difference.
  // Note: these arrays are 1 smaller than the input 
  // because the first/last pt doesn't have a prev/next neighbor.
  var left = image.arraySlice(0, 0, -1)
  var right = image.arraySlice(0, 1)
  var fwd = left.subtract(right)
  var back = right.subtract(left)
  
  // Test if each position is greater than its next/prev neighbor?
  var next = fwd.gt(0)
  var prev = back.gt(0)
  
  // Test if the first/last point is itself a peak
  var first = image.arrayGet([0]).gt(image.arrayGet([1])).toArray()
  var last = image.arrayGet([-1]).gt(image.arrayGet([-2])).toArray()
  
  // Reattach the end points.
  next = next.arrayCat(last, 0)
  prev = first.arrayCat(prev, 0)
  
  // Count how many times both next and prev are greater than 0 (or an end peak)
  // and get the result.
  var peaks = next.and(prev).arrayReduce(ee.Reducer.sum(), [0]).arrayGet([0])
  return peaks
}

var array = ee.Array([113,112,115,120,119,102,101,100,103,105,110,109,105,107])
var image = ee.Image.constant(array)
Map.addLayer(countPeaks(image))

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

Noel Gorelick
  • 489
  • 2
  • 10
  • This function is awesome, which can be used to phenology studies, https://github.com/kongdd/phenofit/blob/master/R/findpeaks.R. – Dongdong Kong Apr 21 '21 at 08:08