Google Earth Engine (GEE) as a public supercomputer

Google Earth Engine Serviceprovides an opportunity to work with huge amounts of spatial information free of charge. For example, in a matter of minutes you can get a composite mosaic (composite image) of a million space images. Assuming that each scene (set of spectral channels) of Landsat 8 occupies 1 GB in compressed form, this request processes an information volume of about 1 PB. And all of this is available for free, quickly, and at any time. But there is such an opinion (wrong) that GEE on free accounts allows you to process and export only small datasets. In fact, this impression is caused only by the fact that you can start programming in GEE without even reading the service documentation, but you will not be able to extract a lot of data without reading the documentation.Next, we will look at three different solutions to the raster vectorization problem and in two different ways write a server-side GEE function to calculate the geohash.













Introduction



( , )? — ! , . ( — , , , - ), ( - , ). , . , , ( , , , - ). , . , — , , 128 , , , - . , ( , ), (, - Amazon AWS). . , , , . , , … , — , - , , ( ) , , ( - — , ). , , .







Google Earth Engine. , — javascript (, , API ). . , , - . , , , , Google Drive ( ) (, GeoTIFF) Export.image.toDrive. , , , . — 21 10 Google Drive GeoJSON, 2. ( , ).









:







  1. , , :


var points_with_attributes = Image.reduceRegion({
  reducer: ee.Reducer.toList(Image.bandNames().size()),
  geometry: points
})
      
      





, , , . .







  1. , . :


var attributes = Image.reduceRegion({
  reducer: ee.Reducer.toList(Image.bandNames().size()),
  geometry: some_area
})
      
      





, . ? , . , . , ( , ). :







var latlon = ee.Image.pixelLonLat()
var points_with_attributes = image
  .addBands(latlon)
  .reduceRegion({
    reducer: ee.Reducer.toList(),
    geometry: some_area
  });
      
      





ee.Image.pixelLonLat() , . , ( , GEE , , ). , , :







var latlon = ee.Image.pixelLonLat().reproject(image.projection())
var points_with_attributes = image
  .addBands(latlon)
  .reduceRegion({
    reducer: ee.Reducer.toList(),
    geometry: some_area
  });
      
      





, :







var latlon = ee.Image.pixelLonLat()
var points_with_attributes = image
  .addBands(latlon)
  .add(image.select(0).add(0))
  .reduceRegion({
    reducer: ee.Reducer.toList(),
    geometry: some_area
  });
      
      





(, ), , . , , , ( ), . , () .







  1. , , , :


var latlon = ee.Image.pixelLonLat()
var points_with_attributes = image
  .sample({
    region: some_area,
    geometries: true
  });
      
      





"geometries" , .









, " ", - . , , GEE. , , . , ( ). GEE, , . , (z-curve). , , , GEE. ? , — . PostgreSQL/PostGIS, Google BigQuery . , -:







var geohash_accumulate = function(obj, list) {
  // define common variables
  var base32 = ee.String('0123456789bcdefghjkmnpqrstuvwxyz'); // (geohash-specific) Base32 map
  // get previous state variables
  var prev = ee.Dictionary(ee.List(list).get(-1));
  var lat = ee.Number(prev.get('lat',0));
  var lon = ee.Number(prev.get('lon',0));
  var idx = ee.Number(prev.get('idx',0));
  var bit = ee.Number(prev.get('bit',0));
  var evenBit = ee.Number(prev.get('evenBit',1));
  var geohash = ee.String(prev.get('geohash',''));
  var latMin = ee.Number(prev.get('latMin',-90));
  var latMax = ee.Number(prev.get('latMax',90));
  var lonMin = ee.Number(prev.get('lonMin',-180));
  var lonMax = ee.Number(prev.get('lonMax',180));

  // calculate substep bit step idx
  // bisect E-W longitude
  var lonMid = ee.Number(ee.Algorithms.If(evenBit.gt(0),                      lonMin.add(lonMax).divide(2), 0)      );
  idx =        ee.Number(ee.Algorithms.If(evenBit.gt(0).and(lon.gte(lonMid)), idx.multiply(2).add(1),       idx)    );
  lonMin =     ee.Number(ee.Algorithms.If(evenBit.gt(0).and(lon.gte(lonMid)), lonMid,                       lonMin) );
  idx =        ee.Number(ee.Algorithms.If(evenBit.gt(0).and(lon.lt(lonMid)),  idx.multiply(2),              idx)    );
  lonMax =     ee.Number(ee.Algorithms.If(evenBit.gt(0).and(lon.lt(lonMid)),  lonMid,                       lonMax) );
  // bisect N-S latitude
  var latMid=  ee.Number(ee.Algorithms.If(evenBit.eq(0),                      latMin.add(latMax).divide(2), 0)      );
  idx =        ee.Number(ee.Algorithms.If(evenBit.eq(0).and(lat.gte(latMid)), idx.multiply(2).add(1),       idx)    );
  latMin =     ee.Number(ee.Algorithms.If(evenBit.eq(0).and(lat.gte(latMid)), latMid,                       latMin) );
  idx =        ee.Number(ee.Algorithms.If(evenBit.eq(0).and(lat.lt(latMid)),  idx.multiply(2),              idx)    );
  latMax =     ee.Number(ee.Algorithms.If(evenBit.eq(0).and(lat.lt(latMid)),  latMid,                       latMax) );
  // check position
  evenBit = evenBit.not();
  bit =     bit.add(1);
  geohash = ee.String(ee.Algorithms.If(bit.eq(5), geohash.cat(base32.slice(idx,ee.Number(idx).add(1))), geohash));
  idx =     ee.Number(ee.Algorithms.If(bit.eq(5), ee.Number(0), idx));
  bit =     ee.Number(ee.Algorithms.If(bit.eq(5), ee.Number(0), bit));

  // return state
  var curr = prev
    .set('idx',     idx     )
    .set('bit',     bit    )
    .set('evenBit', evenBit)
    .set('geohash', geohash)
    .set('latMin',  latMin )
    .set('latMax',  latMax )
    .set('lonMin',  lonMin )
    .set('lonMax',  lonMax );
  return ee.List([curr]);
};
function geohash_encode(lat, lon, precision) {
  var init = ee.Dictionary({lat: lat, lon: lon})
  var state = ee.List.sequence(1,precision*5).iterate(geohash_accumulate, ee.List([init]))
  return ee.String(ee.Dictionary(ee.List(state).get(-1)).get('geohash'))
}
      
      











// PostGIS check from https://postgis.net/docs/ST_GeoHash.html
print (ee.Algorithms.If(geohash_encode(48, -126, 20).compareTo('c0w3hf1s70w3hf1s70w3'),'Error','OK'));
// Google BigQuery check from https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_geohash
print (ee.Algorithms.If(geohash_encode(47.62, -122.35, 10).compareTo('c22yzugqw7'),'Error','OK'));
      
      





geohash_encode() geohash_accumulate() 5 . , GEE , . ? "calculate substep bit step idx" geohash_accumulate() ( , ). . , -, , , :







var geohash_accumulate = function(obj, list) {
  // define common variables
  var range4 = ee.List.sequence(0,4).map(function(val){return ee.Number(val).multiply(1/4)});
  var range8 = ee.List.sequence(0,8).map(function(val){return ee.Number(val).multiply(1/8)});

  // get previous state
  var prev = ee.Dictionary(ee.List(list).get(-1))
  var lat = ee.Number(prev.get('lat',0))
  var lon = ee.Number(prev.get('lon',0))
  var n = ee.Number(prev.get('n',0)).add(1)
  var geohash = ee.String(prev.get('geohash',''))
  var latMin = ee.Number(prev.get('latMin',-90))
  var latMax = ee.Number(prev.get('latMax',90))
  var lonMin = ee.Number(prev.get('lonMin',-180))
  var lonMax = ee.Number(prev.get('lonMax',180))

  // calculate step n
  var base32 = ee.String(ee.Algorithms.If(n.mod(2).eq(1), '028b139c46df57eghksujmtvnqwyprxz', '0145hjnp2367kmqr89destwxbcfguvyz'));
  var latRange = ee.List(ee.Number(ee.Algorithms.If(n.mod(2).eq(1), range4, range8)));
  latRange = latRange.map(function(item){return ee.Number(item).multiply(latMax.subtract(latMin)).add(latMin)});
  var lonRange = ee.List(ee.Number(ee.Algorithms.If(n.mod(2).eq(1), range8, range4)));
  lonRange = lonRange.map(function(item){return ee.Number(item).multiply(lonMax.subtract(lonMin)).add(lonMin)});
  var latIdx = latRange.indexOf(latRange.filter(ee.Filter.lte('item', lat)).get(-1));
  latIdx = ee.Number(ee.Algorithms.If(latIdx.gte(latRange.size().add(-1)), latIdx.add(-1), latIdx));
  var lonIdx = lonRange.indexOf(lonRange.filter(ee.Filter.lte('item', lon)).get(-1));
  lonIdx = ee.Number(ee.Algorithms.If(lonIdx.gte(lonRange.size().add(-1)), lonIdx.add(-1), lonIdx));
  var idx = lonIdx.multiply(latRange.size().add(-1)).add(latIdx);
  // reset bounds
  latMin = latRange.get(latIdx)
  latMax = latRange.get(latIdx.add(1))
  lonMin = lonRange.get(lonIdx)
  lonMax= lonRange.get(lonIdx.add(1))
  // define geohash symbol
  var geohash = geohash.cat(base32.slice(idx,ee.Number(idx).add(1)));

  // return state
  var curr = prev
    .set('n',       n       )
    .set('geohash', geohash )
    .set('latMin',  latMin  )
    .set('latMax',  latMax  )
    .set('lonMin',  lonMin  )
    .set('lonMax',  lonMax  );
  return ee.List([curr]);
};
function geohash_encode(lat, lon, precision) {
  var init = ee.Dictionary({lat: lat, lon: lon})
  var state = ee.List.sequence(1,precision).iterate(geohash_accumulate, ee.List([init]))
  return ee.String(ee.Dictionary(ee.List(state).get(-1)).get('geohash'))
}
      
      





, , Javascript-, , .









. , , , . , GitHub ( GIS Snippets GEE). , — , .








All Articles