3

I'm working on a project where we're trying to measure the shape of coastlines. After some experimentation, I came up with an edge detector that has very little noise. Now, my goal is to get the longitude and latitude of only the white pixels in an area and put them in a array or dictionary. Then I can put them into MatLab or Excel and create a curve function. Can some one help me with getting the long/lat or even an x/y value of only the white pixels?

Below is the code I have in GEE:

var test_curve = 
/* color: #ffebcc */
/* shown: false */
/* displayProperties: [
  {
    "type": "rectangle"
  }
] */
ee.Geometry.Polygon(
    [[[17.936393079223645, -32.69828825968294],
      [17.936393079223645, -32.72363697964223],
      [17.970382031860364, -32.72363697964223],
      [17.970382031860364, -32.69828825968294]]], null, false);

// USGS Landsat 8 TOA Reflectance (Orthorectified) Set
var l8 = ee.ImageCollection('LANDSAT/LC8_L1T_TOA');

// Center on ROI and zoom to level 14
Map.centerObject(test_curve, 14);

/****************************************************
 * Preprocess the data set, filter by images related to 
 * the ROI, within the 2017 year, and minimal cloud interferance
 * **************************************************/

// Specify only the area in the test_curve polygon
var spatialFiltered = l8.filterBounds(test_curve);

// Further filter the number of images by only 
// choosing the ones from 2017
var temporalFiltered = spatialFiltered.filterDate('2017-01-01', '2017-12-31');

// This will sort from least to most cloudy.
var sorted = temporalFiltered.sort('CLOUD_COVER');

// Get the first (least cloudy) image.
var image = sorted.first();

/*******************************************************
 * Convert image to grayscale and normalize to reduce noise.
 * perform edge detection to isolate points on the curves.
 * *****************************************************/

// Create an NDWI image, define visualization parameters and display.
// This will reduce the noise and return and image with fewer artifacts.
var ndwi = image.normalizedDifference(['B3', 'B5']);
// this will reduce the palette to only black and white
// min: .50 returns the best result but they are hard to see
// so min: .41 has been used for visulization purposes.
var ndwiViz = {min: 0.41, max: 1, palette: ['000000','FFFFFF']};

// After experimentation, edge detection was done with laplacian8
// and magnitude set to .21, as it returned the cleanest results.
var p = ee.Kernel.laplacian8({ magnitude: 0.21, normalize: false});

// Apply edge-detection kernel
var edgy = ndwi.convolve(p);

/*******************************************************
 * Display image
 * ****************************************************/


Map.addLayer(edgy, ndwiViz, 'curve_1', true, 1);

1 Answer 1

3

Below is one approach. It masks pixels in ee.Image.pixelLonLat() that are not white enough and doesn't have enough connected pixels (to get rid of noise). These thresholds are definitely up for tweaking. It runs reduceRegion() with a toList() reducer, assembles the collected lon/lat values into a feature collection and exports it.

var edgy = ndwi.convolve(p).clip(test_curve);
var white = edgy.gt(0.15)
var connected = white.selfMask() // selfMask() masks out 0 pixels
  .connectedPixelCount(3).eq(3) // Need to be connected with at least 3 pixels
  .selfMask()
var lonLat = ee.Image.pixelLonLat().updateMask(white.and(connected))
  // .reproject('EPSG:4326', null, 30) // If adding this to the map, it can be useful to see this in nominal resolution

var pixels = lonLat.reduceRegion({
  reducer: ee.Reducer.toList(),
  geometry: test_curve,
  crs: 'EPSG:4326',
  scale: 30
})

var table = ee.FeatureCollection(ee.List(pixels.get('longitude'))
  .zip(ee.List(pixels.get('latitude')))
  .map(function (lonLat) {
    // You probably either want to provide an ee.Geometry or set the lon, lat columns
    // I'm showing both here just to illustrate
    return ee.Feature(ee.Geometry.Point(lonLat))
      .set('lon', ee.List(lonLat).get(0))
      .set('lat', ee.List(lonLat).get(1))
  }))

print(table)
Map.addLayer(table)

Export.table.toDrive({
  collection: table,
  description: 'edges',
  selectors: ['.geo', 'lon', 'lat'] // Select which columns you want - again probably .geo or lon/lat
})

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

1
  • Sorry for the late reply, I had to put this project down for a while. Thank you so much for this solution. It's pretty much exactly what I've been trying to do. If you have some time I'd like to ask you some more questions about how to isolate the curves in my region, thanks again.
    – Rice Man
    May 23, 2020 at 0:27

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.