0

Because of the scan error in lANDSAT 7 the images have data gaps. however the data is still useful particularly in applications requiring data that covers longer periods. In my case, I need to calculate NDVI from Landsat 7 data and the gaps in each NDVI image using the mean of the previous and next images. I have prepared the code below but it is giving an error.Please advise.

// cloud mask for L7 Collection 2
var cloudMaskC2L7 = function(image) {
  var Q = image.select('QA_PIXEL');
   var cloud3BitMask = (1 << 3);
   var cloud4BitMask = (1 << 4);
   var maskx = Q.bitwiseAnd(cloud3BitMask).eq(0).and(Q.bitwiseAnd(cloud4BitMask).eq(0));
  return image.updateMask(maskx);
};

// Applies scaling factors when using USGS Landsat 5/7/8 Level 2, Collection 2.
function applyScaleFactors(image) {
  var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2);
  var thermalBands = image.select('ST_B.*').multiply(0.00341802).add(149.0);
  return image.addBands(opticalBands, null, true)
              .addBands(thermalBands, null, true);
}


// Load a Landsat 7 collection
var collection = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2')
  .filter(ee.Filter.eq('WRS_PATH', 168))
  .filter(ee.Filter.eq('WRS_ROW', 60))
  .filterDate('2015-01-01', '2015-12-31')
  .map(applyScaleFactors)
  .map(cloudMaskC2L7)
  .map(function(img) {
   var img_sub = img;
   var ndvi = img_sub.normalizedDifference(['SR_B4','SR_B3']);
   return ndvi.copyProperties(img_sub, img_sub.propertyNames());});

// Define a function to fill missing values with the mean of the next and previous images
var fillMissing = function(image, collection) {
  // Find the index of the current image in the collection
  var index = collection.toList(collection.size()).indexOf(image);

  // If the image is the first or last in the collection, do not fill missing values
  if (index === 0 || index === collection.size().subtract(1)) {
    return image;
  }
  
  // Get the previous and next images in the collection
  var prev = ee.Image(collection.get(index.subtract(1)));
  var next = ee.Image(collection.get(index.add(1)));
  
  // Compute the mean of the previous and next images
  var mean = prev.add(next).divide(2);
  
  // Fill missing values in the current image with the computed mean
  var filled = image.unmask(mean);
  
  return filled;
};

// Map the fillMissing function over the collection
var filledCollection = collection.map(function(image) {
  return fillMissing(image, collection);
});

var olddata = collection.filterDate('2015-03-01', '2015-10-31');
var newdata = filledCollection.filterDate('2015-03-01', '2015-10-31');

// Display the filled collection
print(filledCollection);
//Map.centerObject(filledCollection);
Map.addLayer(olddata.first());
Map.addLayer(newdata.first());
John Musau
  • 179
  • 8

1 Answers1

0

There are different approaches to this. Here's one that uses all imagery before and after to generate a mosaic before and after each image. This is of course costly. This can be more efficient if you only look at imagery in a time window. But that can leave you with more masked pixels. You also have the options to use joins for this. See this presentation for more on that.

var collection = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2')
  .filter(ee.Filter.eq('WRS_PATH', 168))
  .filter(ee.Filter.eq('WRS_ROW', 60))
  .filterDate('2015-01-01', '2016-01-01') // End date is exclusive
  .map(applyScaleFactors)
  .map(cloudMaskC2L7)
  .map(function(img) {
    var img_sub = img
    var ndvi = img_sub.normalizedDifference(['SR_B4', 'SR_B3'])
    var date = ee.Image(
      img.date().get('year').add(img.date().getFraction('year'))
    ).float().updateMask(ndvi.mask()).rename('date')
    return ndvi
      .addBands(date) // Fractional date, for picking up before pixel
      .addBands(date.multiply(-1).rename('negativeDate')) // Same but negative, to pick up next pixel
      .copyProperties(img_sub, img_sub.propertyNames())
  })


var filledCollection = collection.map(interpolate)

function interpolate(image) {
  var before = collection
    .filter(ee.Filter.lt('system:time_start', image.getNumber('system:time_start')))
    .qualityMosaic('date') // Last non-masked of images before
  var after = collection
    .filter(ee.Filter.gt('system:time_start', image.getNumber('system:time_start')))
    .qualityMosaic('negativeDate') // First non-masked of images after
  var date = image.date().get('year').add(image.date().getFraction('year'))
  var weight =  ee.Image()
    .expression('(t - t1) / (t2 - t1)', {
      t: date,
      t1: before.select('date'),
      t2: after.select('date'),
  })
  var interpolated = before.add(
    after.subtract(before).multiply(weight)
  )
  var bands = image
    .bandNames()
    .filter(ee.Filter.inList('item', ['date', 'negativeDate']).not())
  return image
    .unmask(interpolated) // Use the interpolated value when image is masked
    .select(bands) 
}

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

Daniel Wiell
  • 253
  • 2
  • 5