Google Earth Engine – Calculating Distance to Water from Every Non-Water Pixel

distancegoogle-earth-engineraster

I have an MNDWI (Modified Normalised Difference Water Index) layer for an area of interest (aoi). I then identified water sources as pixels with MNDWI > 0 and created a water layer where a pixel either has a value of 0 (no water) or 1 (water). Now, I would like to calculate the distance from every 0 (no water) pixel to the nearest pixel with water (value = 1) and get an output raster where its values correspond to distances. Below, is my code for calculating MNDWI and the water layer.

First, get Sentinel imagery:

var S2 = ee.ImageCollection('COPERNICUS/S2')
    .filterDate("2018-08-16", "2018-09-12")
    .filterBounds(aoi);

var image = ee.Image(S2.sort('CLOUD_COVER', false).mosaic());

Then, calculate MNDWI and the water layer:

var image_mndwi = image.normalizedDifference(['B3','B8']);
var image_water = image_mndwi.gt(0)

Map.addLayer(image_water, {}, 'water')

Example of the water layer

Best Answer

I think you will need image.cumulativeCost, define every pixel with constant value 1 (so the 'cost' to travel through each pixel is similar to one pixel).

I tried something like this, but maybe a problem is that the answer is variable with zoom-level. You possibly will have to set a scale when you export the result.

// Define a aoi
var aoi = ee.Geometry.Polygon(
    [[[4.775452845304471, 51.97127706847272],[4.766526453702909, 51.90248482244104],
      [5.008225672452909, 51.90502671938598],[5.003419153898221, 51.986502926791026],
      [4.775796168058378, 51.986080056157746]]]);

// Load an least cloudy image
var image = ee.ImageCollection('COPERNICUS/S2')
                    .filterDate("2018-01-01", "2018-12-31")
                    .filterBounds(aoi)
                    .sort('CLOUD_COVER').first();

// Calculate the MNDWI
var image_mndwi = image.normalizedDifference(['B3','B8']);
var image_water = image_mndwi.gt(0);
var image_nonWater = image_mndwi.lte(0);

// Define the sources. Mask the sources.
var sources = ee.Image().toByte().paint(image.geometry(), 1);
sources = sources.updateMask(image_water);

// Define what is necesarry for you as low as possible to decrease computational time
var maxDist = 10000;

// cost image.
var dist = image_nonWater.cumulativeCost({
  source: sources, 
  maxDistance: maxDist,  
});

// Add to the map
Map.addLayer(image_water,{}, 'water');
Map.addLayer(dist,{min: 0, max: maxDist}, 'dist');
Map.centerObject(aoi);
Related Question