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. ( , ).
:
- , , :
var points_with_attributes = Image.reduceRegion({
reducer: ee.Reducer.toList(Image.bandNames().size()),
geometry: points
})
, , , . .
- , . :
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
});
(, ), , . , , , ( ), . , () .
- , , , :
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). , — , .