5

In Earth Engine, I want to draw rectangular boxes around points, with the constraint that the box will exactly fit a pixel grid (from another raster).

Drawing a rectangular box around a point has been already discussed (see Creating planar rectangle about points of interest in Google Earth Engine?): use x.buffer(50).bounds().

But how can I adjust that box so that it fit exactly a raster grid, i.e. it contains only 100% covered pixels?

See example below, I would like either a smaller box (removing the <100% covered pixels) or bigger (including also the <100% covered pixels). Link for this code: link

enter image description here

var point = ee.Geometry.Point([-103.44862, 25.90856])
var box = point.buffer(50).bounds()
var LS = ee.ImageCollection("LANDSAT/LC8_L1T_32DAY_NDVI")

var pal = ["#000004FF", "#56106EFF", "#BB3754FF", "#F98C0AFF", "#FCFFA4FF"]

// Display the polygon on the map
Map.centerObject(point, 18);
Map.addLayer(point, {color: 'FF0000'}, 'point');
Map.addLayer(ee.Image(LS.first()).clip(box.buffer(30)), {min:0.1, max:0.2, palette: pal}, 'LS');
Map.addLayer(box, {}, 'box');

1 Answer 1

6

You can get the coordinates of the box in the projection of the grid you want to match, and then round them to integers in that projection.

However, the image you're using is a composite, so it doesn't have a projection (it also isn't cloud masked). You probably want to use the projection of one of the underlying Landsat images:

var point = ee.Geometry.Point([-103.44862, 25.90856])
var box = point.buffer(50).bounds()

var LS = ee.ImageCollection("LANDSAT/LC8_L1T_32DAY_NDVI")
var firstImage = ee.ImageCollection("LANDSAT/LC08/C01/T1").filterBounds(point).first()
var proj = firstImage.select(0).projection()

// Get the coordinates in the image's projection.
var coords = ee.List(box.transform(proj, 1).coordinates().get(0))
// Find the extents.
var minMax = ee.Dictionary(coords.reduce(ee.Reducer.minMax().repeat(2)))
// Round up/down to an integer number of pixels in the projection.
var mins = ee.List(minMax.get("min")).map(function(n) { return ee.Number(n).floor() })
var maxs = ee.List(minMax.get("max")).map(function(n) { return ee.Number(n).ceil() })
// Make a new geometry in the given projection then transform back to EPSG:4326
var box2 = ee.Geometry.Rectangle(mins.cat(maxs), proj, true, false).transform("EPSG:4326")

var pal = ["#000004FF", "#56106EFF", "#BB3754FF", "#F98C0AFF", "#FCFFA4FF"]

// Display the polygon on the map
Map.centerObject(point, 18);
Map.addLayer(ee.Image(LS.first()).clip(box2), {min:0.1, max:0.2, palette: pal}, 'LS');
Map.addLayer(box, {}, 'box');
Map.addLayer(point, {color: 'FF0000'}, 'point');

https://code.earthengine.google.com/c6b19beb40bf444e0be52663e5c4d355

2
  • Thanks, this is brilliant! Could you kindly elaborate a little more on how rounding to the integer makes it end up on a corner of the raster's pixels? That sounds like magic to me... is that a general property of projection, or just with this specific one, or just with EE? Thanks so much!!
    – Matifou
    Commented Feb 15, 2021 at 17:34
  • 3
    In any given projection(), the grid always starts on integer boundaries. And at the scale of the projection each "pixel" is exactly 1.0 "projection units" away from its neighbor (that's essentially the definition of a pixel in the projection). Commented Feb 15, 2021 at 18:15

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.