1

I want to convert a clipped ee.Image to 2-D arrays for each band and 2-D arrays for the lats and the lons of each pixel. Some of the pixels could be masked.

Using pixelLonLat() with sampleRectangle() the 2D array is not generated as I expected.

I expected a 2-D array with the latitudes of each pixel. This is the result for the other image bands. But I get a single value, that I don't recognise.

// Select a random image and band. 
var bandName= "B1";
var asset = ee.Image("COPERNICUS/S2_SR/20200110T000231_20200110T000234_T55HFB").select(bandName); 
var minMaxReducer = ee.Reducer.minMax();
var theMinMax = asset.reduceRegion(minMaxReducer, asset.geometry());
// print(theMinMax);
var min = theMinMax.get(bandName + '_min').getInfo();
var max = theMinMax.get(bandName + '_max').getInfo();
print('min: ' +  min, ' max: ' +  max)
// create an AOI
var centroid = asset.geometry().centroid(10);
var largeArea = centroid.buffer(100000);
var smallArea = centroid.buffer(15000);

// Add a 'longitude' and 'latitude' band.
var imageWithCoords = asset.addBands(ee.Image.pixelLonLat())
var smallImage = imageWithCoords.clip(largeArea);
print('smallImage', smallImage);
print('bandNames', smallImage.bandNames());
// Confirm the bands render as exected.
Map.addLayer(smallImage, {"bands":[bandName],"min":min,"max":max}, bandName);
Map.addLayer(smallImage, {"bands":["longitude"],"min":147.676,"max":149.850}, 'longitude');
Map.addLayer(smallImage, {"bands":["latitude"],"min":-35.585,"max":-34.253}, 'latitude');
Map.centerObject(smallImage);

// Get 2-d pixel array for AOI - returns feature with 2-D pixel array as property per band.
var band_arrs = imageWithCoords.unmask(0).sampleRectangle(smallArea)
// Get individual band arrays.
var band_arr = band_arrs.get(bandName);
var band_arr_lats = band_arrs.get('latitude');
var band_arr_lons = band_arrs.get('longitude');

print('bandname', band_arr.getInfo());  // Note the shape is a list of lists (50, 50)
print('lats', band_arr_lats.getInfo()); // Expected the same shape but get (1, 1)
print('lons', band_arr_lons.getInfo()); // Expected the same shape but get (1, 1)

The actual output is lats [[-34.5]] lons [[148.5]] I am also not sure why the numbers are rounded to half a degree.

An alternative approach is to use reducer.toList() but this gives a 1-D array sampled at a different scale, so not as easy to align with the band arrays.

var latlonList = smallImage.reduceRegion({
    reducer: ee.Reducer.toList(),
    geometry: smallArea,
    scale: 10
  })

var lats =ee.Array(latlonList.get("latitude")).getInfo();
var lons = ee.Array(latlonList.get("longitude")).getInfo();
print('lats', lats);
print('lons', lons);

This prints two lists of 69832 elements each. Depending on the AOI and the scale.

EDIT Adding the image to a pixelLonLat() doesn't work either. i.e.

smallImage = ee.Image.pixelLonLat().addBands(smallImage)

1 Answer 1

2

As per the docs for sampleRectangle:

Each band is sampled in its input projection

The pixelLonLat image has no projection so it defaults to EPSG:4326 at 1 degree per pixel. So there's only 1 pixel in your region. Set the default projection for that image like this:

var band_arrs = imageWithCoords.unmask(0)
    .setDefaultProjection(asset.projection())
    .sampleRectangle(smallArea)
1
  • Thanks, it is indeed the answer. I was thrown off by the map showing a gradation of lats and lons.
    – intotecho
    Nov 6, 2021 at 1:23

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.