maskinggoogle-earth-engineelevationsatellite-image

Masking image by elevation in Google Earth Engine


I'm a grad student new to GEE and GIS work generally. For work related to my doctoral research, I am looking at Planet imagery of a coastal region. I am trying to exclusively look at regions of low lying salt marsh, so I have been trying to mask pixels below a certain elevation - to no avail.

I have three images for now, and have been using the US 3DEP elevation data native to GEE, which takes the form of an ImageCollection. Loading in images, visualizing them and masking zeros works well.

var us3DEP = ee.ImageCollection('USGS/3DEP/1m');
var us3DEPvis = {
  min: 0,
  max: 3000,
  palette: [
    '3ae237', 'b5e22e', 'd6e21f', 'fff705', 'ffd611', 'ffb613', 'ff8b13',
    'ff6e08', 'ff500d', 'ff0000', 'de0101', 'c21301', '0602ff', '235cb1',
    '307ef3', '269db1', '30c8e2', '32d3ef', '3be285', '3ff38f', '86e26f'
  ],
};

var im1 = ee.Image('/20220114_151633_65_245c_3B_Visual')
var im2 = ee.Image('/20220114_151635_96_245c_3B_Visual')
var im3 = ee.Image('/20220114_151638_26_245c_3B_Visual')


//mask zero values

var mask1 = im1.select('b1').neq(0)
var maskim1 = im1.updateMask(mask1)

var mask2 = im2.select('b1').neq(0)
var maskim2 = im2.updateMask(mask2)

var mask3 = im3.select('b1').neq(0)
var maskim3 = im3.updateMask(mask3)

However I can't seem to find a way to integrate elevation data from the collection into a band in my image. So far I have been able to clip the area of one image from the elevation image collection, but that leaves me with an image containing multiple bands of elevation data:

var im1geo = maskim1.geometry()
var inter1 = us3DEP.filterBounds(im1geo)
var bands1 = inter1.toBands()
var over1 = bands1.clip(im1geo)

I tried using a ee.Reducer.allNonZero to make a mask across all the bands, but that seemed to remove the whole image (or just didn't work for a reason beyond me, but no errors came up)

Am I going about this wrong? My goal is to be able to match elevation data per pixel to image data per pixel, so maybe I shouldn't worry about adding a band - but I don't know how to go about that.

Thank you!


Solution

  • Think about what you need. You want to compare the elevation with your data. So, toBands() is not the right operation, because that's creating a band for each image in the collection USGS/3DEP/1m — which is a bunch of images of different regions with very little to no spatial overlap. So, you'll just end up with many bands that are mostly masked.

    Instead, you need a single image with elevation data for your region of interest. If your ROI is covered by one image in 3DEP then it would be sufficient to do us3DEP.filterBounds(im1geo).first(), but a more robust answer (in case you are near an image boundary) is to create a composite image of all available data: us3DEP.filterBounds(im1geo).mean().

    (In many cases it would be appropriate to also filter with a date range, but this collection doesn't seem to have historical data.)

    Once you have the elevation image, it should be simple to use it as a mask.

    var elevation = us3DEP.filterBounds(im1geo).mean();
    var maxElevation = 30;
    var elevationMask = elevation.lt(maxElevation);
    

    Then just .mask(elevationMask) the images you want to process.