3

I am working on a time series with Landsat 7 and I have issues with the scan line correction. I already saw the question LS7 filling the gaps image with google earth engine and tried to adopt the posted solution. I do not know why exactly the code does not work and if it is so, because the original post used raw scenes, and I am using surface reflectance.

I only changed few lines of this GEE code and used SR-Landsat scenes in my study area. I always get the error in line 40

regress.ReduceNeighborhood is not a function

I normally get such an error, if an ImageCollection instead of an image it used, so I wonder, why this error appears.

var MIN_SCALE = 1/3;
var MAX_SCALE = 3;
var MIN_NEIGHBORS = 144;

/* Apply the USGS L7 Phase-2 Gap filling protocol, using a single kernel size. */
var GapFill = function(src, fill, kernelSize, upscale) {
  var kernel = ee.Kernel.square(kernelSize * 30, "meters", false)

  // Find the pixels common to both scenes.
  var common = src.mask().and(fill.mask())
  var fc = fill.updateMask(common)
  var sc = src.updateMask(common)
  Map.addLayer(common.select(0).mask(common.select(0)), {palette:['000000']}, 'common mask (both exist)', false)

  // Find the primary scaling factors with a regression.
  // Interleave the bands for the regression.  This assumes the bands have the same names.
  var regress = fc.addBands(sc)

  regress = regress.select(regress.bandNames().sort())
  print(regress,'regress')
  var ratio = 5

  if(upscale) {
    var fit = regress
      .ReduceResolution(ee.Reducer.median(), false, 500)
      .reproject(regress.select(0).projection().scale(ratio, ratio))
      .ReduceNeighborhood(ee.Reducer.linearFit().forEach(src.bandNames()), kernel, null, false)
      .unmask()
      .reproject(regress.select(0).projection().scale(ratio, ratio))
  } else {

    var fit = regress
      .ReduceNeighborhood(ee.Reducer.linearFit().forEach(src.bandNames()), kernel, null, false)
  }

  var offset = fit.select(".*_offset")
  var scale = fit.select(".*_scale")

  Map.addLayer(scale.select('B1_scale'), {min:-2, max:2}, 'scale B1', false)

  // Find the secondary scaling factors using just means and stddev
  var Reducer = ee.Reducer.mean().combine(ee.Reducer.stdDev(), null, true)

  if(upscale) {
    var src_stats = src
      .ReduceResolution(ee.Reducer.median(), false, 500)
      .reproject(regress.select(0).projection().scale(ratio, ratio))
      .ReduceNeighborhood(Reducer, kernel, null, false)
      .reproject(regress.select(0).projection().scale(ratio, ratio))

    var fill_stats = fill
      .ReduceResolution(ee.Reducer.median(), false, 500)
      .reproject(regress.select(0).projection().scale(ratio, ratio))
      .ReduceNeighborhood(Reducer, kernel, null, false)
      .reproject(regress.select(0).projection().scale(ratio, ratio))
  } else {
    var src_stats = src
      .ReduceNeighborhood(Reducer, kernel, null, false)

    var fill_stats = fill
      .ReduceNeighborhood(Reducer, kernel, null, false)
  }

  var scale2 = src_stats.select(".*stdDev").divide(fill_stats.select(".*stdDev"))
  var offset2 = src_stats.select(".*mean").subtract(fill_stats.select(".*mean").multiply(scale2))

  var invalid = scale.lt(MIN_SCALE).or(scale.gt(MAX_SCALE))
  Map.addLayer(invalid.select(0).mask(invalid.select(0)), {palette:['550000']}, 'invalid1', false)
  scale = scale.where(invalid, scale2)
  offset = offset.where(invalid, offset2)

  // When all else fails, just use the difference of means as an offset.  
  var invalid2 = scale.lt(MIN_SCALE).or(scale.gt(MAX_SCALE))
  Map.addLayer(invalid2.select(0).mask(invalid2.select(0)), {palette:['552020']}, 'invalid2', false)
  scale = scale.where(invalid2, 1)
  offset = offset.where(invalid2, src_stats.select(".*mean").subtract(fill_stats.select(".*mean")))

  // Apply the scaling and mask off pixels that didn't have enough neighbors.
  var count = common.ReduceNeighborhood(ee.Reducer.count(), kernel, null, true, "boxcar")
  var scaled = fill.multiply(scale).add(offset)
      .updateMask(count.gte(MIN_NEIGHBORS))

  return src.unmask(scaled, true)
}

//////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

var etmCol = ee.ImageCollection('LANDSAT/LE07/C01/T1_SR')
                    .filterDate('2005-05-30', '2005-10-30');
// Define a collection filter.
var colFilter = ee.Filter.and(
  ee.Filter.bounds(area),
ee.Filter.lt('CLOUD_COVER', 30),  
  ee.Filter.lt('GEOMETRIC_RMSE_MODEL', 10),
ee.Filter.or(
    ee.Filter.eq('IMAGE_QUALITY', 9),
    ee.Filter.eq('IMAGE_QUALITY_OLI', 9)
  ));
// Filter collections and prepare them for merging.
var l7images = etmCol.filter(colFilter);
print(l7images,'Landsat 7')

var source    = ee.Image(listOfImages.get(0))
var fill      = ee.Image(listOfImages.get(1))
Map.addLayer(fill,    {min:400, max:2500, gamma: 2.222 , bands:["B3", "B2", "B1"]}, "1", true)
Map.addLayer(source,  {min:400, max:2500, gamma: 2.222 , bands:["B3", "B2", "B1"]}, "2", true)
print(source,'First')
print(fill,'Second')
//var source  = ee.Image("LANDSAT/LE07/C01/T1_SR/LE07_167063_20150207")
//var fill    = ee.Image(" LANDSAT/LE07/C01/T1_SR/LE07_167063_20150615")

var result = GapFill(source, fill, 10, false);
Map.addLayer(result,  {min:0, max:200, bands:["B3", "B2", "B1"]}, "filled", true)

var result = GapFill(source, fill, 10, true);
Map.addLayer(result,  {min:0, max:200, bands:["B3", "B2", "B1"]}, "filled (upscaled)", true)

Here is my code https://code.earthengine.google.com/690a5042671f6effed934d1f8e0ef01d

0

2 Answers 2

2

You should just start functions in the GEE with lowercase letters. Thus:

reduceResolution() and reduceNeighborhood

Link code

0

I am not sure why your code is spitting out an error, but it seems to be as part of the 'if-else' statement. I do not have a solution to your code, but I can offer another code that works without an if-else statement and also includes a cloud mask function. I obtained this from stackExchange, but I cannot remember who wrote the original code. Just supply a variable point that is your AOI.

var cloudMaskL7 = function(image) {
  var qa = image.select('pixel_qa');
  var cloud = qa.bitwiseAnd(1 << 5)
                    .and(qa.bitwiseAnd(1 << 7))
                    .or(qa.bitwiseAnd(1 << 3));
  var mask2 = image.mask().reduce(ee.Reducer.min());
  return image.updateMask(cloud.not()).updateMask(mask2);
};

var l7 = ee.ImageCollection('LANDSAT/LE07/C01/T1_SR')
    .map(cloudMaskL7);

var kernelSize = 10;
var kernel = ee.Kernel.square(kernelSize * 30, 'meters', false);

var GapFill = function(image) {
  var start = image.date().advance(-1, 'year');
  var end = image.date().advance(1, 'year');
  var fill = l7.filterDate(start, end).median();
  var regress = fill.addBands(image); 
  var regress = regress.select(regress.bandNames().sort());
  var fit = regress.reduceNeighborhood(ee.Reducer.linearFit().forEach(image.bandNames()), kernel, null, false);
  var offset = fit.select('.*_offset');
  var scale = fit.select('.*_scale');
  var scaled = fill.multiply(scale).add(offset);
  return image.unmask(scaled, true);
};

// TESTING CODE

Map.centerObject(point, 11);

var check = ee.ImageCollection('LANDSAT/LE07/C01/T1_SR')
    .filterBounds(point)
    .filterDate('2004-06-15', '2004-12-31');
var checkImage = ee.Image(check.first());
var visParams = {bands: ['B4', 'B3', 'B2'], min: 200, max: 5500};
Map.addLayer(checkImage, visParams, 'source');

// Test composite.
var checkStart = checkImage.date().advance(-1, 'year');
var checkEnd = checkImage.date().advance(1, 'year');
var composite = l7.filterDate(checkStart, checkEnd).median();
Map.addLayer(composite, visParams, 'median');

// Rough implementation for comparison.
var replaced = checkImage.unmask(composite);
Map.addLayer(replaced, visParams, 'simple');

// Fancy implementation.
var filled = ee.Image(check.map(GapFill).first());
Map.addLayer(filled, visParams, 'filled');

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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