1

I'm trying to extract from Google Earth Engine a large raster based on MODIS 250m data. However, when it gets sent to Google Drive, the resulting .tif has only a few pixels.

Here's my code for exporting the image (which I've visualized and which is clearly at high resolution in GEE):

Export.image.toDrive({
  image: evi_delta,
  description: 'modis_evi_diff_worldcover_masked_' + startdate + "_" + enddate,
  region: geomPoly,
  crs: projection.crs,
  scale: 250,
  maxPixels: 1e13,
  crsTransform: projection.transform,
  fileFormat: 'GeoTIFF',
  formatOptions: {
    cloudOptimized: true
  }
});

But as you can clearly see, not only is the data not at 250m resolution as requested, it only has a few hundred pixels in total! It's taking about 40 minutes for the request to run, which suggests to me that it's actually computing the large high-resolution raster and then just giving me this very low-resolution one instead.

What's going on here? I've been trying this 10 different ways and at this point I'm very frustrated with GEE.

enter image description here

2
  • Hey there, could you share the rest of your code to allow us to recreate the error
    – M. Nicolas
    Nov 16, 2022 at 20:10
  • @M.Nicolas I actually solved the problem; see explanation below. It has to do with how GEE automatically labels the output of a "reduce" step with the wrong resolution.
    – Holt Dwyer
    Nov 27, 2022 at 20:54

1 Answer 1

1

Figured out the solution.

The problem is that when you apply a "reduce" operation across multiple ee.Images in GEE, GEE produces an output image which is not in the original ee.Images' projections, but rather in the default GEE projection, EPSG:4236. It also sets the "scale" of the resulting image to the default "scale" of EPSG:4236, which is 1 degree (approximately 111 km at the equator)--even though the input ee.Images, and thus the output ee.Image, are actually at higher resolution. When you run Export.image.toDrive, GEE will write an image with resolution equal to the "scale" of the projection of the output image.

The solution is to manually overwrite the output image with the correct "scale", i.e. the scale of the input images.

The key line is:

//We have to manually set the scale of the output back to 231 meters
minn = minn.setDefaultProjection(minn.projection(), null, 231);

Code illustrating this procedure:

//////////////////////////
//Define boundary box for Indonesia to clip data to:
//All of Indonesia
var geomPoly = ee.Geometry
.BBox(85, -12, 145, 8);

//Center viewer on area of interest
//Coordinates are longitude, latitude, zoom level
//Can also pass in a geometry object e.g.
//var geometry = ee.Geometry.Point([130,05])
// Map.setCenter(130, -5,4);
Map.centerObject(geomPoly);

//Want to see this on satellite background
Map.setOptions('SATELLITE');


////////////////////////////////////////
//Get Modis EVI data betwen specified dates, 
//clip to Indonesia, download

//Image collection consists of multiple images at different
//times and locations and possibly variables.
//Collect data over a year to take quantiles
var prior_year = "2002";
var current_year = "2003";
var startdate = prior_year + "-10-16";
var enddate = current_year + "-10-15";

//Pull in Modis MOD13Q1 Vegetation Indices, 250m.
// https://developers.google.com/earth-engine/datasets/catalog/MODIS_061_MOD13Q1
// https://www.sciencedirect.com/science/article/pii/S0034425702000962
// The Mod13Q1 data are temporal composites of 16-day periods created
// by selecting the best cloud-free and close-to-nadir observations

var evi_coll = ee.ImageCollection('MODIS/061/MOD13Q1')
  .filterDate(startdate, enddate)
  .select("EVI");
  
print("MODIS EVI", evi_coll);
print("Modis EVI projection: ", evi_coll.first().projection());

//MODIS EVI comes in at 231m resolution (approximately)
print("MODIS EVI resolution: ", evi_coll.first().projection().nominalScale());
  
//Create quantile composites (converts from imageCollection to Image)
var almostMinMax = ee.Reducer.percentile([2,98],["min","max"])

//Run a reducer which takes a collection of images and takes
//(pixel by pixel) the 98th and 2nd percentiles.
var extrema = evi_coll.reduce(almostMinMax);

//Annoyingly, applying a Reducer tags the output image as EPSG:4236
//with 1 degree scale even though it's not actually in that projection
//or resolution, and must be manually overwritten.
// https://gis.stackexchange.com/questions/428384/whats-correct-order-of-resampling-reprojecting-and-composing-imagecollection-i
// https://developers.google.com/earth-engine/apidocs/ee-image-setdefaultprojection

print("Extrema: ", extrema);

var minn = extrema.select("EVI_min")
.clip(geomPoly);

//We have to manually set the scale of the output back to 231 meters
minn = minn.setDefaultProjection(minn.projection(), null, 231);

var maxx = extrema.select("EVI_max").clip(geomPoly)
.clip(geomPoly);

//Manually setting scale here also (another output of the reduce)
maxx = maxx.setDefaultProjection(maxx.projection(), null, 231);

print("Minn: ", minn);
print("Maxx: ", minn);

print("Minn native resolution: ", minn.projection().nominalScale());

//Take differences between the max and min to get a delta:
var evi_diff = maxx.subtract(minn).clip(geomPoly);

print("EVI diff: ", evi_diff);

//The nominal scale is now correctly set back to 231 meters
print("EVI diff native resolution: ", evi_diff.projection().nominalScale());


//////////////////////////////
//Visualize and export resulting data

var projection=evi_diff.projection().getInfo();

//Recommended colorization from page:
//https://developers.google.com/earth-engine/datasets/catalog/MODIS_MOD09GA_006_EVI
var colorizedVis = {
  min: 0.0,
  max: 8000,
  palette: [
    'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718', '74A901',
    '66A000', '529400', '3E8601', '207401', '056201', '004C00', '023B01',
    '012E01', '011D01', '011301'
  ],
};


//Color scheme for visualizing the difference in EVI, which has a different scale.
var diffVis = {
  min: -1000.0,
  max: 5000.0,
  palette: [
    "ffffff","ce7e45","df923d","f1b555","fcd163",
    "99b718","74a901","66a000","529400","489b01",
    "33b602","09ab02","009b00","036602","025802",
    "024702","044d04"],
};

//Add the images to the map using the visualization scheme.
Map.addLayer(minn, colorizedVis, "Trough");
Map.addLayer(maxx, colorizedVis, "Peak");
Map.addLayer(evi_diff, diffVis, "Diff");

//Nominal scale will now be correct
var scale = evi_diff.projection().nominalScale().int();

print("Scale: ", scale);

//True scale of output image.
var myscale = 230;

// Export image to Google Drive. Not automatic,
// have to hit a button under "Tasks" on the right.
Export.image.toDrive({
  image: evi_diff,
  description: "modis_scale_" + myscale.toString() + "_epsg_evi_diff_" + startdate + "_" + enddate,
  region: geomPoly,
  crs: projection.crs,
  scale: myscale,
  maxPixels: 1e13,
  crsTransform: projection.transform,
  fileFormat: 'GeoTIFF',
  formatOptions: {
    cloudOptimized: true
  }
});

The result of this is a .tif that has the correct resolution but in EPSG:4236 CRS.

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.