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
});
}