I am exporting MOD10A1 imagery from Google Earth Engine and the exported data are not aligned properly in space. I tried defining the export crs as per Nicholas Clinton's advice here but to no avail. I discovered the issue after exporting both the raster and vector data and projecting simultaneously in R. They do not align (note that the vector ROI drops off the lower-left side of the plotting window):
I verified that it is not a problem with the vector data by opening it separately in Google Earth Pro - the vector data are projected fine. And I believe the actual data in the raster are correct; low-quality pixels are unmasked with the value set to 255, and we can clearly see the outline of Mono Lake, which is the focus of this toy ROI. Thus, I am led to believe that the issue is in the proj information for the raster dataset.
Reproducible example (first the GEE data acquisition and export):
//// ROI
var Sample = ee.Geometry.Polygon([
[[-119.22, 38.06], [-119.23, 37.97], [-119.01, 37.91],
[-118.89, 37.93], [-118.85, 38.02], [-119.01, 38.09],
[-119.22, 38.06]]
]);
// Generate Region of Interest
var ROI = ee.FeatureCollection(Sample);
// visualize
Map.centerObject(ROI, 7); // Center on the Grand Canyon.
Map.addLayer(ROI, {color: '6a0dad', opacity:0.99}, 'ROI');
//// Data filters
// Create a QA mask + clipping function
var masker = function(image){
var mask = image.select('NDSI_Snow_Cover_Basic_QA').lte(1);
var maskedImage = image.updateMask(mask);
return maskedImage.unmask(255).clip(ROI);
};
//// Acquire data
// Compile the data
var dataset = ee.ImageCollection('MODIS/006/MOD10A1')
.filter(ee.Filter.date('2019-01-01', '2020-01-01'))
.map(masker);
print("MOD10A1 Image Collection", dataset);
// Select the data you're interested in
var ndsi = dataset.select('NDSI_Snow_Cover');
print("MOD10A1 NDSI Collection",ndsi);
// Plot the data
Map.addLayer(ndsi, {}, 'NDSI');
//// PREPARE DATA FOR EXPORT
// Thanks Tyler Erickson for the stacking function
// https://gis.stackexchange.com/a/254778/67264
// The code below is slightly modified from Erickson's
// approach in order to rename using dateString in
// stackCollection function
var stackCollection = function(collection) {
// Create an initial image.
var first = ee.Image(collection.first()).select([]);
// Write a function that appends a band to an image.
var appendBands = function(image, previous) {
var dateString = ee.Date(image.get('system:time_start')).format('yyyy-MM-dd');
return ee.Image(previous).addBands(image.rename(dateString));
};
return ee.Image(collection.iterate(appendBands, first));
};
var ndsi_img = stackCollection(ndsi);
print("NDSI stacked collection", ndsi_img);
//// Export the data
// Export table for plotting
Export.table.toDrive({
collection: ROI,
description: 'SampleROI',
folder: "AlignmentTroubleshooting",
fileFormat: 'SHP'
});
// Export imagery
// Specify a crs as per Nicholas Clinton's advice
// https://gis.stackexchange.com/a/257647/67264
// Export a cloud-optimized GeoTIFF.
// See https://developers.google.com/earth-engine/exporting
Export.image.toDrive({
image: ndsi_img,
description: 'NDSI_2019',
folder: "AlignmentTroubleshooting",
scale: 500,
region: ROI,
crs: ndsi_img.select(0).projection(),
fileFormat: 'GeoTIFF',
formatOptions: {
cloudOptimized: true
}
});
Reproducible part II (R import and plotting):
library(raster)
library(rgdal)
# Raster
ras = raster::stack("NDSI_2019.tif")
proj4string(ras)
# ROI
roi = readOGR(".",
"SampleROI")
proj4string(roi)
roi = spTransform(roi, CRSobj = crs(ras))
# Plot
plot(ras[[150]])
plot(roi, add = T)
The NDSI_2019.tif and SampleROI.shp files can be accessed without running the Earth Engine code here.