1

I am trying to get 100m resolution maps of NDVI where water is identified using the ESA landcover data set and masked. Both the NDVI and landcover data sets have a native resolution of 10m. however when I use the .reduceResolution function I get an error the following error:

Error: Image.reduceResolution: The input to reduceResolution does not have a valid default projection. Use setDefaultProjection() first. (Error code: 3)

I've seen answers that if I reproject first and then reduce resolution it will run and that does indeed work, but it doesn't do what I want. The new image is not an average of the 10m pixels within each new 100m pixel.

Any suggestions for getting around this so that rather than resampling it is reducing the resolution?

Code shown below:

/*

Create 100m ndvi maps for each C40 city using:
  - Sentinel 2 10m data to calculate NDVI &
  - ESA 10m landcover data identify & mask water
  
*/

// cities 
var cities = ee.FeatureCollection("users/gretam/sample_cities");

// one city (in sample) for testing of code
var paris = cities
    .filter(ee.Filter.equals('City', 'Paris'));
    
//////////////////////////////////////////////////////////////
// NDVI + water
//////////////////////////////////////////////////////////////

// sentinel 2 10m data
// select all images from 2020 and bands B4=Red, B8=NIR to calculate NDVI 
//(greenest pixel will remove cloudy pixels)
var s2a=ee.ImageCollection("COPERNICUS/S2_SR")
  .filterDate('2020-01-01', '2020-12-31') 
  .select('B4','B8'); 

// ESA landcover 2020 10m data 
var landcover=ee.ImageCollection("ESA/WorldCover/v100")
  .first();
  
//////////////////////////////////////////////////////////////
// Iteration over shapefiles 
//////////////////////////////////////////////////////////////
// iterate over the cities to create separate maps
cities.aggregate_array('City').evaluate(function(names) {
  names.map(function (name) {
    var city = cities
      .filter(ee.Filter.equals('City', name))
      .first();
    //create one set up for shape file itself 
    var city_shape=city.geometry();
    cityClip(city_shape, name);
  });
});

function cityClip(city_shape, name) {  
  
  // crop image collection to city
  var sentinel=s2a.filterBounds(city_shape);

  // create a function to calculate NDVI for all images left in the 
  // image collection 
  
  // function to calculate NDVI in Sentinel 2
  var addNDVI = function(image) {
    var NDVI = image.normalizedDifference(['B8', 'B4'])
    .rename('NDVI');
    return image.addBands(NDVI);
  };
  
  // create image collection of NDVI values
  var withNDVI = sentinel.map(addNDVI).select('NDVI');
  
  // reduce to one image (greenest pixel composite)
  var greenestPixel = withNDVI.qualityMosaic('NDVI');
  
  // define water
  var water=landcover.eq(80).or(greenestPixel.lte(0));
  
  //get a just green image that ignores water (landcover=open water OR NDVI<0)
  var ndvi10m= greenestPixel.updateMask(water.eq(0)).clip(city_shape);

  Map.addLayer(ndvi10m, {
    bands: 'NDVI',
    min: 0.0,
    max: 1.0,
    palette: [
      'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718', '74A901',
      '66A000', '529400', '3E8601', '207401', '056201', '004C00', '023B01',
      '012E01', '011D01', '011301'
  ]});
  
  var ndvi100 = ndvi10m
    // Force the next reprojection to aggregate instead of resampling.
    .reduceResolution({
      reducer: ee.Reducer.mean(),
      maxPixels: 1024
    })
    .reproject({
      crs: 'EPSG:4326',
      scale: 100
    });
  
  // Export ndvi 
  Export.image.toDrive({
    image: ndvi100,
    description:name,
    region: city_shape,
    scale:100
  });
  
} 
1
  • 1
    You need to post a complete (minimal) example showing the issue. Commented Aug 28, 2023 at 8:49

1 Answer 1

1

When you use .qualityMosaic(), you are reducing N images into a single image, each one with potentially different projections. Therefore, the resulting image does not have a valid projection.

Consider the following changes:

  // reduce to one image (greenest pixel composite)
  var greenestPixel = withNDVI.qualityMosaic('NDVI')
  .setDefaultProjection("EPSG:32631", null, 10)

EPSG:32631 seems to work well for Paris. You will need to figure out a way to set an appropriate projection for each feature in your collection.

  var ndvi100 = ndvi10m
    // Force the next reprojection to aggregate instead of resampling.
    .reduceResolution({
      reducer: ee.Reducer.mean(),
      maxPixels: 1024
    })
    .reproject({
      crs: 'EPSG:32631',    // Try with 4326 and 32631
      scale: 20    // Try with 20 and 100
    });

  Map.addLayer(ndvi100, {
    bands: 'NDVI',
    min: 0.0,
    max: 1.0,
    palette: [
      'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718', '74A901',
      '66A000', '529400', '3E8601', '207401', '056201', '004C00', '023B01',
      '012E01', '011D01', '011301'
  ]}, "Reprojected");

Set the same projection in crs, and visualize the result in the map. Try with scale:20 to make it easier to see that each four pixels result in one coarser pixel value that you want. Test it with EPSG:4326 and EPSG:32631. Can you see why the values of the reprojection when using EPSG:4326 don't match?

Try it here with a small feature (~four 100m pixels):

https://code.earthengine.google.com/54d13c3985f50f2d5e32d888c0aaca89

1
  • thank you so much! That makes a lot of sense. Commented Sep 28, 2023 at 19:48

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.