4

Regarding the LandTrendr algorithm in Earth Engine... I have prepared an input image collection and can successfully get a result from the algorithm (no errors), but how can I extract segmentation information for each of the points in a feature collection from the result?

Here is the code for building the input collection and running LandTrendr:

// #############################################################################
// ### INPUTS ###
// #############################################################################

// Define a point feature collection to run LandTrendr on.
var points = ee.FeatureCollection([
  ee.Feature(ee.Geometry.Point(-122.62346, 44.0332), {'id': 0}),
  ee.Feature(ee.Geometry.Point(-122.71169, 44.0404), {'id': 1}),
  ee.Feature(ee.Geometry.Point(-122.63977, 44.0409), {'id': 2})
]);

// Define annual composite date range. 
var startDoy = 175; // start at 175th day-of-year
var nDays = 90; // end 90 days later

// Define year range.
var startYear = 1984;
var endYear = 2012;

// Define band to use for segmentation.
var bandName = 'B7';

// Define LandTrendr parameters.
var ltParams = { 
  maxSegments: 6,
  spikeThreshold: 0.9,
  vertexCountOvershoot: 3,
  preventOneYearRecovery: true,
  recoveryThreshold: 0.25,
  pvalThreshold: 0.05,
  bestModelProportion: 0.75,
  minObservationsNeeded: 6
};

// #############################################################################
// ### COLLECTION PREPARATION ###
// #############################################################################

// Display the point.
Map.centerObject(points, 13);
Map.addLayer(points, {color: 'red'});
Map.setOptions('SATELLITE');

// Define function to mask clouds and cloud shadows.
function cfmask(img) {
  var cloudShadowBitMask = 1 << 3;
  var cloudsBitMask = 1 << 5;
  var qa = img.select('pixel_qa');
  var mask = qa.bitwiseAnd(cloudShadowBitMask)
    .eq(0)
    .and(qa.bitwiseAnd(cloudsBitMask).eq(0));
  return img.updateMask(mask);
}

// Import Landsat 5 surface reflectance collection
var lsCol = ee.ImageCollection("LANDSAT/LT05/C01/T1_SR");

// Define a list of years to make composites for.
var yearsList = ee.List.sequence(startYear, endYear, 1);

// Map over the year list to build an annual composite collection.
var annualCol = ee.ImageCollection.fromImages(
  yearsList.map(function(yr) {
    var startDate = ee.Date.fromYMD(yr, 1, 1).advance(startDoy, 'day');
    var middleDate = startDate.advance(nDays/2, 'day');
    var endDate = startDate.advance(nDays+1, 'day');
    var yearCol = lsCol
      .filterDate(startDate, endDate)
      .filterBounds(points)
      .select(bandName)
      .median();
    var nBands = yearCol.bandNames().size();
    return yearCol.set({
      'system:time_start': middleDate.millis(),
      'nBands': nBands
    });
  })
);

// Deal with missing years (no images or all pixels masked).
var yearsPresentCol = annualCol.filter(ee.Filter.neq('nBands', 0));

var yearsAbsentCol = annualCol.filter(ee.Filter.eq('nBands', 0));

// Make a filler image for missing years - all pixels masked.
var dummyImg = ee.Image(0).selfMask().rename(bandName);

// Add dummy image band to images with no bands (missing years).
yearsAbsentCol = yearsAbsentCol.map(function(img) {
  return img.addBands(dummyImg);
});

// Merge the missing years collection to the valid years collection.
var ltCol = yearsPresentCol.merge(yearsAbsentCol);

// Set the annual composite collection as the LandTrendr timeSeries parameter.
ltParams.timeSeries = ltCol;

// #############################################################################
// ### RUN LANDTRENDR ###
// #############################################################################

var ltArrImg = ee.Algorithms.TemporalSegmentation.LandTrendr(ltParams);
print(ltArrImg);
3

The result of the LandTrendr algorithm is an array image object. As with traditional ee.Image objects, it can be reduced by a region (.reduceRegion()) or regions (.reduceRegions()).

Since you have a feature collection of points, apply .reduceRegions() with the ee.Reducer.first() reducer to add LandTrendr segmentation information to the properties of each point for the pixels they intersect.

Below is an example that builds on your code to filter the feature collection to one of the points and plot the source and LandTrendr-fitted time series.

// #############################################################################
// ### REDUCE THE LANDTRENDR IMAGE BY INTERSECTION WITH POINTS ###
// #############################################################################

// Reduce the LandTrendr result by the aoi. Use ee.Reducer.first() to select
// the pixel that intersects the point.
var ltPoints = ltArrImg.reduceRegions({
  collection: points,
  reducer: ee.Reducer.first(),
  scale: 30
});

// The point feature collection is returned, but now each has LandTrendr
// segmentation information properties.
print('Reduction of LandTrendr image by points', ltPoints);

// #############################################################################
// ### PLOT SOURCE AND FITTED TIME SERIES FOR A SINGLE POINT ###
// #############################################################################

// Get the LandTrendr segmentation results from point: ID 0.
var ltPoint = ee.Array(
  ltPoints.filter(ee.Filter.eq('id', 0)).first().get('LandTrendr')
);
print('Segmentation info array for pixel intersecting point ID 0', ltPoint);

// Slice out data to plot in time series chart.
var year = ltPoint.slice(0, 0, 1).transpose();
var yValues = ltPoint.slice(0, 1, 3).transpose();

// Make a time series chart.
var chart = ui.Chart.array.values(yValues, 0, year)
  .setSeriesNames(['Orig', 'Fit'])
  .setChartType('LineChart')
  .setOptions({
    title: 'LandTrendr source and fit',
    hAxis: {
      title: 'Year', format: '####',
      viewWindow: {min: startYear, max: endYear}
    },
    vAxis: {title: bandName, format: '####'},
    pointSize: 0,
    lineWidth: 1
  });

print(chart);

Complete Code Editor script. Learn more about LandTrendr outputs and working with them.

enter image description here

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.