1

I tried illumination correction on Sentinel-2 images and obtain monthly median images.

However, I'm struggling with the following error: Image (Error) reduce.median: Can't apply calendarRange filter to objects without a timestamp.

Could you look at my code and help me.

I tried these two methods.

return img_plus_ic.set('system:time_start',img.get('system:time_start'));

return img_plus_ic.copyProperties(img);

But they did not work.

Full code below (Also here, https://code.earthengine.google.com/c3a6647a1013ffcebcbe750ac7b07a5a)

var roi = ee.Geometry.Polygon([[[-115.51858045584667, 45.29650713146457],
          [-115.51858045584667, 44.2632748294202],
          [-113.60146619803417, 44.2632748294202],
          [-113.60146619803417, 45.29650713146457]]], null, false);
Map.centerObject(roi);
Map.addLayer(roi);



function cloud_mask(image) {
  var qa = image.select('QA60');
  var cloudBitMask = 1 << 10;
  var cirrusBitMask = 1 << 11;
  var mask = qa.bitwiseAnd(cloudBitMask).eq(0).and(
             qa.bitwiseAnd(cirrusBitMask).eq(0));
  var out = image.updateMask(mask).divide(10000)
      .select("B.*")
      .copyProperties(image);
  return out;
  }
  
var dem = ee.Image("USGS/SRTMGL1_003");

function topoCorr_IC(img){

  // Extract image metadata about solar position
  var SZ_rad = ee.Image.constant(ee.Number(img.get('MEAN_SOLAR_ZENITH_ANGLE'))).multiply(3.14159265359).divide(180).clip(img.geometry().buffer(10000)); 
  var SA_rad = ee.Image.constant(ee.Number(img.get('MEAN_SOLAR_AZIMUTH_ANGLE')).multiply(3.14159265359).divide(180)).clip(img.geometry().buffer(10000)); 
  // Creat terrain layers
  var slp = ee.Terrain.slope(dem).clip(img.geometry().buffer(10000));
  var slp_rad = ee.Terrain.slope(dem).multiply(3.14159265359).divide(180).clip(img.geometry().buffer(10000));
  var asp_rad = ee.Terrain.aspect(dem).multiply(3.14159265359).divide(180).clip(img.geometry().buffer(10000));

  // Calculate the Illumination Condition (IC)
  // slope part of the illumination condition
  var cosZ = SZ_rad.cos();
  var cosS = slp_rad.cos();
  var slope_illumination = cosS.expression("cosZ * cosS", 
                                          {'cosZ': cosZ,
                                           'cosS': cosS.select('slope')});
  // aspect part of the illumination condition
  var sinZ = SZ_rad.sin(); 
  var sinS = slp_rad.sin();
  var cosAziDiff = (SA_rad.subtract(asp_rad)).cos();
  var aspect_illumination = sinZ.expression("sinZ * sinS * cosAziDiff", 
                                           {'sinZ': sinZ,
                                            'sinS': sinS,
                                            'cosAziDiff': cosAziDiff});
  // full illumination condition (IC)
  var ic = slope_illumination.add(aspect_illumination);

  // Add IC to original image
  var img_plus_ic = ee.Image(img.addBands(ic.rename('IC')).addBands(cosZ.rename('cosZ')).addBands(cosS.rename('cosS')).addBands(slp.rename('slope')));
  return img_plus_ic.copyProperties(img, ["system:time_start"]);
}

var S2 = ee.ImageCollection("COPERNICUS/S2")
                              .filterDate("2019-01-01", "2019-12-31")
                              .filterBounds(roi)
                              .map(cloud_mask)
                              .map(topoCorr_IC);


var m1 = S2.filter(ee.Filter.calendarRange(1, 31, 'day_of_year')).median();

print (m1);

Image (Error) reduce.median: Can't apply calendarRange filter to objects without a timestamp.

1

The cloud masking, at line 18, is discarding the system:time_start property (by default system properties aren't copied). Add another copy_properties to catch it:

var out = image.updateMask(mask).divide(10000)
    .select("B.*")
    .copyProperties(image)
    .copyProperties(image, ["system:time_start"])

or better, just replace the bands in the original image with the scaled ones and don't fiddle with properties at all:

function cloud_mask(image) {
  var qa = image.select('QA60')
  var cloudBitMask = 1 << 10
  var cirrusBitMask = 1 << 11
  var mask = qa.bitwiseAnd(cloudBitMask).eq(0).and(
             qa.bitwiseAnd(cirrusBitMask).eq(0))
  var scaled = image.select("B.*").updateMask(mask).divide(10000)
  return image.addBands(scaled, null, true)
}

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.