4

I tried multi-temporal filtering of the Sentinel-1 images by adopting the code available at https://code.earthengine.google.com/01e247bc0c59442437a737cfc28f7430

I need to apply the multi-temporal filtering for the images of whole year (2017). However, I got this error:

ImageCollection (Error)
Error in map(ID=S1B_IW_GRDH_1SDV_20170101T011828_20170101T011857_003648_006414_E48C):
Image.multiply: If one image has no bands, the other must also have no bands. Got 1 and 0.

Here is my code:

var aoi = ee.Geometry.Polygon(
        [[[-113.04179687499999, 44.484512810104995],
          [-113.04179687499999, 40.26669922631106],
          [-105.13164062499999, 40.26669922631106],
          [-105.13164062499999, 44.484512810104995]]], null, false);

function multitemporalDespeckle(images, radius, units, opt_timeWindow) {
  var timeWindow = opt_timeWindow 
  var bandNames = ee.Image(images.first()).bandNames()
  var bandNamesMean = bandNames.map(function(b) { return ee.String(b).cat('_mean') })
  var bandNamesRatio = bandNames.map(function(b) { return ee.String(b).cat('_ratio') })
  var meanSpace = images.map(function(i) {
    var reducer = ee.Reducer.mean()
    var kernel = ee.Kernel.square(radius, units)
    var mean = i.reduceNeighborhood(reducer, kernel).rename(bandNamesMean)
    var ratio = i.divide(mean).rename(bandNamesRatio)
    return i.addBands(mean).addBands(ratio)
  })

  function multitemporalDespeckleSingle(image) {
    var t = image.date()
    var from = t.advance(ee.Number(timeWindow.before), timeWindow.units)
    var to = t.advance(ee.Number(timeWindow.after), timeWindow.units)
    var meanRatioBefore = ee.ImageCollection(meanSpace).select(bandNamesRatio).filterDate(from, t)
      .filter(ee.Filter.eq('relativeOrbitNumber_start', image.get('relativeOrbitNumber_start'))) 
    var meanRatioAfter = ee.ImageCollection(meanSpace).select(bandNamesRatio).filterDate(t, to)
      .filter(ee.Filter.eq('relativeOrbitNumber_start', image.get('relativeOrbitNumber_start'))) 
    var SDmeanRatioBefore = meanRatioBefore.reduce(ee.Reducer.stdDev());
    var SDmeanRatioAfter = meanRatioAfter.reduce(ee.Reducer.stdDev());
    var b = image.select(bandNamesMean)
    var monoLookBack = b.multiply(meanRatioBefore.sum()).divide(meanRatioBefore.count()).rename(bandNames)
    var biLookBackForward = monoLookBack.where(SDmeanRatioBefore.gt(SDmeanRatioAfter), b.multiply(meanRatioAfter.sum()).divide(meanRatioAfter.count()).rename(bandNames));
    return biLookBackForward;
    }
    return meanSpace.map(multitemporalDespeckleSingle).select(bandNames)
}

var s1 = ee.ImageCollection('COPERNICUS/S1_GRD')
  .filterBounds(aoi)
  .filterDate('2017-01-01','2017-12-31')
  .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV'))
  .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VH'))
  .filter(ee.Filter.eq('instrumentMode', 'IW'))
  .filter(ee.Filter.eq('orbitProperties_pass', 'ASCENDING'));

print (s1);

var s1vv = s1.select('VV')
  .sort('system:time_start', true);

print (s1vv);

var s1vh = s1.select('VV')
  .sort('system:time_start', true);

var s1Denoised_vv = multitemporalDespeckle(s1vv, 7, 'pixels', { before: -8, after: 8, units: 'week' });
var s1Denoised_vh = multitemporalDespeckle(s1vh, 7, 'pixels', { before: -8, after: 8, units: 'week' });

print (s1Denoised_vv);
5

The problem is with the date filtering that defines the meanRatioBefore collection. There are no images earlier than the earliest image in the collection, so when the multitemporalDespeckleSingle function is working on the first image in the time series, the filter .filterDate(from, t) fails to return any images because it is looking for images from eight weeks before the given image (inclusive) to the timestamp of the given image (exclusive). Since there are no images, there are no bands to perform band math with, hence the "Image.multiply" error.

One easy solution is to add one second to the t timestamp to make the date filter inclusive (will include the given image in the meanRatioBefore collection):

var meanRatioBefore = ee.ImageCollection(meanSpace)
  .select(bandNamesRatio)
  .filterDate(from, t.advance(1, 'second'))

Here is your script with the edit included. Note that I limited printing the results to the first 50 images - otherwise the memory limit is exceeded. This is an expensive operation, you'll likely need to start a batch task (export your results) to succeed.

See the ### START DEBUG ### section for the bug identification commentary.

var aoi = ee.Geometry.Polygon(
        [[[-113.04179687499999, 44.484512810104995],
          [-113.04179687499999, 40.26669922631106],
          [-105.13164062499999, 40.26669922631106],
          [-105.13164062499999, 44.484512810104995]]], null, false);

function multitemporalDespeckle(images, radius, units, opt_timeWindow) {
  var timeWindow = opt_timeWindow 
  var bandNames = ee.Image(images.first()).bandNames()
  var bandNamesMean = bandNames.map(function(b) { return ee.String(b).cat('_mean') })
  var bandNamesRatio = bandNames.map(function(b) { return ee.String(b).cat('_ratio') })
  var meanSpace = images.map(function(i) {
    var reducer = ee.Reducer.mean()
    var kernel = ee.Kernel.square(radius, units)
    var mean = i.reduceNeighborhood(reducer, kernel).rename(bandNamesMean)
    var ratio = i.divide(mean).rename(bandNamesRatio)
    return i.addBands(mean).addBands(ratio)
  })

  function multitemporalDespeckleSingle(image) {
    var t = image.date()
    var from = t.advance(ee.Number(timeWindow.before), timeWindow.units)
    var to = t.advance(ee.Number(timeWindow.after), timeWindow.units)
    var meanRatioBefore = ee.ImageCollection(meanSpace).select(bandNamesRatio).filterDate(from, t)
      .filter(ee.Filter.eq('relativeOrbitNumber_start', image.get('relativeOrbitNumber_start'))) 
    var meanRatioAfter = ee.ImageCollection(meanSpace).select(bandNamesRatio).filterDate(t, to)
      .filter(ee.Filter.eq('relativeOrbitNumber_start', image.get('relativeOrbitNumber_start'))) 
    var SDmeanRatioBefore = meanRatioBefore.reduce(ee.Reducer.stdDev());
    var SDmeanRatioAfter = meanRatioAfter.reduce(ee.Reducer.stdDev());
    var b = image.select(bandNamesMean)
    var monoLookBack = b.multiply(meanRatioBefore.sum()).divide(meanRatioBefore.count()).rename(bandNames)
    var biLookBackForward = monoLookBack.where(SDmeanRatioBefore.gt(SDmeanRatioAfter), b.multiply(meanRatioAfter.sum()).divide(meanRatioAfter.count()).rename(bandNames));
    return biLookBackForward;
  }
  return meanSpace.map(multitemporalDespeckleSingle).select(bandNames)
}

var s1 = ee.ImageCollection('COPERNICUS/S1_GRD')
  .filterBounds(aoi)
  .filterDate('2017-01-01','2017-12-31')
  .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV'))
  .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VH'))
  .filter(ee.Filter.eq('instrumentMode', 'IW'))
  .filter(ee.Filter.eq('orbitProperties_pass', 'ASCENDING'));

//print (s1);

var s1vv = s1.select('VV')
  .sort('system:time_start', true);

//print (s1vv);

var s1vh = s1.select('VV')
  .sort('system:time_start', true);

// var s1Denoised_vv = multitemporalDespeckle(s1vv, 7, 'pixels', { before: -8, after: 8, units: 'week' });
// var s1Denoised_vh = multitemporalDespeckle(s1vh, 7, 'pixels', { before: -8, after: 8, units: 'week' });
//print (s1Denoised_vv);

// #############################################################################
// ### START DEBUG ###
// #############################################################################

// Filter to the offending image:
var badImg = s1vh.filter(ee.Filter.eq('system:index', 'S1B_IW_GRDH_1SDV_20170101T011828_20170101T011857_003648_006414_E48C'))
print(badImg)

// Set variables to mock up the multitemporalDespeckle function arguments
var images = ee.ImageCollection(badImg)
var radius = 7
var units = 'pixels'
var opt_timeWindow = { before: -8, after: 8, units: 'week' }

// Run throught multitemporalDespeckle function lines.
var timeWindow = opt_timeWindow 
var bandNames = ee.Image(images.first()).bandNames()
var bandNamesMean = bandNames.map(function(b) { return ee.String(b).cat('_mean') })
var bandNamesRatio = bandNames.map(function(b) { return ee.String(b).cat('_ratio') })
var meanSpace = images.map(function(i) {
  var reducer = ee.Reducer.mean()
  var kernel = ee.Kernel.square(radius, units)
  var mean = i.reduceNeighborhood(reducer, kernel).rename(bandNamesMean)
  var ratio = i.divide(mean).rename(bandNamesRatio)
  return i.addBands(mean).addBands(ratio)
})
// Check results - they look good.
print('meanSpace', meanSpace)


// Set variables to mock up the multitemporalDespeckleSingle function arguments
var image = meanSpace.first()

// Run throught multitemporalDespeckleSingle function lines.
var t = image.date()
var from = t.advance(ee.Number(timeWindow.before), timeWindow.units)
var to = t.advance(ee.Number(timeWindow.after), timeWindow.units)

var meanRatioBefore = ee.ImageCollection(meanSpace).select(bandNamesRatio).filterDate(from, t)
  .filter(ee.Filter.eq('relativeOrbitNumber_start', image.get('relativeOrbitNumber_start'))) 
// Check results - !!! EMPTY COLLECTION !!!
print('meanRatioBefore', meanRatioBefore)

var meanRatioAfter = ee.ImageCollection(meanSpace).select(bandNamesRatio).filterDate(t, to)
  .filter(ee.Filter.eq('relativeOrbitNumber_start', image.get('relativeOrbitNumber_start')))
// Check results - looks good.
print('meanRatioAfter', meanRatioAfter)  

var SDmeanRatioBefore = meanRatioBefore.reduce(ee.Reducer.stdDev());
// Check results - !!! NO BANDS !!!
print('SDmeanRatioBefore', SDmeanRatioBefore)

var SDmeanRatioAfter = meanRatioAfter.reduce(ee.Reducer.stdDev());
// Check results - looks good.
print('SDmeanRatioAfter', SDmeanRatioAfter)

var b = image.select(bandNamesMean)
// Check results - looks good.
print('b', b)

var monoLookBack = b.multiply(meanRatioBefore.sum()).divide(meanRatioBefore.count()).rename(bandNames)
// Check results - !!! FAILS !!!
print('monoLookBack', monoLookBack)
// meanRatioBefore.sum() results in 0 bands
print('meanRatioBefore.sum()', meanRatioBefore.sum())
// b has one band and meanRatioBefore.sum() has 0 bands - can;t multiply.
// Problem is that there are no images prior to image 'S1B_IW_GRDH_1SDV_20170101T011828_20170101T011857_003648_006414_E48C'

// Check to see if 'S1B_IW_GRDH_1SDV_20170101T011828_20170101T011857_003648_006414_E48C'
// is first in time series - yes it is.
print(s1vv.sort('system:time_start').first().id())

// var biLookBackForward = monoLookBack.where(SDmeanRatioBefore.gt(SDmeanRatioAfter), b.multiply(meanRatioAfter.sum()).divide(meanRatioAfter.count()).rename(bandNames));

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.