Skip to content
This repository was archived by the owner on May 23, 2024. It is now read-only.

Commit c7df903

Browse files
committed
Google Earth Engine integration
1 parent a7a2d58 commit c7df903

File tree

6 files changed

+152
-26
lines changed

6 files changed

+152
-26
lines changed

Readme.md

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
pyEOM
22
=====
33

4-
Earth Observation Monitor
4+
pyEOM is the Python package for the Earth Observation Monitor (www.earth-observation-monitor.net), a project developed by the Friedrich-Schiller-University Jena, Department for Earth Observation (www.eo.uni-jena.de).
5+
6+
You can use pyEOM to extract time-series data for different MODIS products and Landsat data and a given geometry (individual Pixel or Polygon).
7+
8+
*Please note:* The development of this package is in an early state. Documentation, testing and completion of the work will follow.
9+
10+
If you have any questions, please do not hesitate to contact me: Jonas Eberle <jonas.eberle@uni-jena.de>
511

612
Installation
713
-----------
@@ -18,6 +24,8 @@ Installation
1824
* gdalbuildvrt
1925
* gdal_merge.py
2026

27+
Please make sure that the command-line tools are within the System path. Otherwise you have to specify the path to the tools within the GDAL class (class variable "path") in processing.py.
28+
2129
*Further requirements:*
2230
For MODIS HDF data processing, HDF4 image format has to be available for gdal command-line tools.
2331

@@ -38,3 +46,32 @@ Usage
3846
'source': 'LPDAAC'
3947
})
4048
output = ingest.start()
49+
50+
Installation
51+
------------
52+
53+
No setup.py is available at the moment. Please download the pyEOM folder and set the Python path to the parent directory.
54+
import sys
55+
sys.path.append('/directory/to/parent/folder/of/pyEOM')
56+
57+
Available datasets
58+
------------------
59+
* MODIS Surface Reflectance: MOD09A1, MOD09Q1
60+
* MODIS Snow: MOD10A1, MYD10A1, MOD10A2, MYD10A2, MOD10C1, MYD10C1, MOD10C2, MYD10C2, MOD10CM, MYD10CM
61+
* MODIS Land Surface Temperature: MOD11A1, MYD11A1, MOD11A2, MYD11A2, MOD11B1, MYD11B1, MOD11C1, MYD11C1, MOD11C2, MYD11C2, MOD11C3, MYD11C3
62+
* MODIS Vegetation Indices: MOD13A1, MYD13A1, MOD13A2, MYD13A2, MOD13A3, MYD13A3, MOD13C1, MYD13C1, MOD13C2, MYD13C2, MOD13Q1, MYD13Q1
63+
* MODIS MCD15A2, MCD15A3
64+
* MODIS MCD43A3
65+
* MODIS MOD44B
66+
* MODIS MCD45A1
67+
68+
Further information to the datasets can be found at the following sites:
69+
* http://lpdaac.usgs.gov/products/modis_products_table
70+
* NSIDC
71+
72+
Google Earth Engine
73+
-------------------
74+
75+
If you have an account for the Google Earth Engine (https://earthengine.google.org), you can also use the Python bindings to have access to specific MODIS products and Landsat datasets.
76+
77+
Please set the variables MY_SERVICE_ACCOUNT and MY_PRIVATE_KEY_FILE in gee_init.py to your service account username and the private key file.

pyEOM/datasets/Landsat.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,44 @@
11
__author__ = 'Jonas Eberle <jonas.eberle@eberle-mail.de>'
2+
from pyEOM.sources import *
3+
4+
class GEE(GEESource):
5+
dataset = None
6+
start = '1900-01-01'
7+
end = '2100-01-01'
8+
epsg = 'EPSG:4326'
9+
scale = 30
10+
11+
def __init__(self, task):
12+
self.task = task
13+
if 'dataset' not in task:
14+
raise Exception('No dataset found in task')
15+
sys.exit(1)
16+
self.dataset = task['dataset']
17+
if 'geom' not in task:
18+
raise Exception('No geometry found in task')
19+
sys.exit(1)
20+
if 'start' in task:
21+
self.start = task['start']
22+
if 'end' in task:
23+
self.end = task['end']
24+
if 'scale' in task:
25+
self.scale = int(task['scale'])
26+
if 'publishPath' not in task:
27+
self.publishPath = os.getcwd()
28+
else:
29+
self.publishPath = task['publishPath']
30+
31+
self.connect()
32+
33+
self.geom = self.processGeometry(task['geom'])
34+
35+
def setPublishPath(self, path):
36+
self.publishPath = path
37+
38+
def run(self):
39+
# dataset bands geom start end epsg scale crsTransform
40+
data = self.getData(self.dataset, None, self.geom, self.start, self.end, self.epsg, self.scale, None)
41+
return data
42+
43+
def ingest(self, format=None):
44+
return self.run()

pyEOM/datasets/MODIS.py

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,43 @@ def getTilesFromGeometry(self, geom):
3535

3636

3737
class GEE(GEESource):
38+
dataset = None
39+
start = '1900-01-01'
40+
end = '2100-01-01'
41+
epsg = 'SR-ORG:6974'
42+
43+
def __init__(self, task):
44+
self.task = task
45+
if 'dataset' not in task:
46+
raise Exception('No dataset found in task')
47+
sys.exit(1)
48+
self.dataset = task['dataset']
49+
if 'geom' not in task:
50+
raise Exception('No geometry found in task')
51+
sys.exit(1)
52+
if 'start' in task:
53+
self.start = start
54+
if 'end' in task:
55+
self.end = end
56+
if 'publishPath' not in task:
57+
self.publishPath = os.getcwd()
58+
else:
59+
self.publishPath = task['publishPath']
3860

39-
def __init__(self, task, dataset):
4061
self.connect()
41-
pass
4262

43-
def process(self):
44-
pass
63+
self.geom = self.processGeometry(task['geom'])
64+
65+
def setPublishPath(self, path):
66+
self.publishPath = path
4567

46-
def ingest(self, downloadPath=None):
68+
def run(self):
69+
# dataset bands geom start end epsg scale crsTransform
70+
data = self.getData(self.dataset, None, self.geom, self.start, self.end, self.epsg, None, True)
71+
return data
4772

48-
pass
73+
def ingest(self, format=None):
74+
return self.run()
4975

5076

5177
def TestDatasetLPDAAC():

pyEOM/processing.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ def compress(self, type):
317317

318318
class GDAL(object):
319319
outputfilext = {'GTiff': '.tif', 'netCDF': '.nc', 'HDF4Image': '.hdf','VRT': '.vrt', 'KEA': '.kea', }
320+
path = '' # with a training slash
320321

321322
resample_methods = ['near', 'bilinear', 'cubic', 'cubicspline', 'lanczos']
322323

@@ -346,7 +347,7 @@ def execute(self, cmd, output):
346347
def gdal_translate(self, input, output, format="GTiff"):
347348
#if not os.path.isfile(input):
348349
# raise Exception('Input file not found!')
349-
return self.execute(['gdal_translate', '-of', format, input, output], output)
350+
return self.execute([self.path+'gdal_translate', '-of', format, input, output], output)
350351

351352

352353
def gdal_merge(self, inputfiles, output, format="GTiff", nodata=""):
@@ -355,7 +356,7 @@ def gdal_merge(self, inputfiles, output, format="GTiff", nodata=""):
355356
#if len(inputfiles) <= 1:
356357
# raise Exception('Inputfiles needs more than 1 file!')
357358

358-
return self.execute(['gdal_merge.py', '-o', output, '-of', format, inputfiles], output)
359+
return self.execute([self.path+'gdal_merge.py', '-o', output, '-of', format, inputfiles], output)
359360

360361

361362
def gdalwarp(self, inputfile, output, format, dstnodata, epsg, resample, cutline):
@@ -378,14 +379,14 @@ def gdalwarp(self, inputfile, output, format, dstnodata, epsg, resample, cutline
378379
else:
379380
format = ''
380381

381-
return self.execute(['gdalwarp', format, srcnodata, dstnodata, reproject, cutline, inputfile, output], output)
382+
return self.execute([self.path+'gdalwarp', format, srcnodata, dstnodata, reproject, cutline, inputfile, output], output)
382383

383384

384385
def gdal_compress(self, inputfile, output, type):
385-
return self.execute(['gdal_translate', '-co COMPRESS='+type, inputfile, output], output)
386+
return self.execute([self.path+'gdal_translate', '-co COMPRESS='+type, inputfile, output], output)
386387

387388
def gdallocationinfo(self, inputfile, x, y):
388-
return self.execute(['gdallocationinfo', '-valonly', '-geoloc', '-wgs84', inputfile, str(x), str(y)], None)
389+
return self.execute([self.path+'gdallocationinfo', '-valonly', '-geoloc', '-wgs84', inputfile, str(x), str(y)], None)
389390

390391
def gdalbuildvrt(self, inputs, output, separate=True):
391392
inputfilelist = ''
@@ -397,4 +398,4 @@ def gdalbuildvrt(self, inputs, output, separate=True):
397398
else:
398399
separate = ''
399400

400-
return self.execute(['gdalbuildvrt', separate, inputfilelist, output, inputs], output)
401+
return self.execute([self.path+'gdalbuildvrt', separate, inputfilelist, output, inputs], output)

pyEOM/sources.py

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import pyEOM.gee_init as gee
44
import ee
55
import sys
6+
import ogr
67

78
def TestGEESource():
89
source = GEESource()
@@ -28,6 +29,16 @@ def connect(self, username=None, password=None):
2829
else:
2930
raise Exception('No valid user authentication found')
3031

32+
def processGeometry(self, wkt):
33+
if 'POINT' in wkt:
34+
geom = ogr.CreateGeometryFromWkt(wkt)
35+
return self.getEEPoint(geom.GetX(), geom.GetY())
36+
elif 'POLYGON' in wkt:
37+
return self.getEEPolygon(wkt)
38+
else:
39+
raise Exception('Wrong geometry type (either POINT or POLYGON necessary)')
40+
sys.exit(1)
41+
3142
def getEEPoint(self, x, y):
3243
return ee.Geometry.Point(x, y)
3344

@@ -45,23 +56,30 @@ def getData(self, dataset, bands, eeGeometry, start, end, epsg='SR-ORG:6974', sc
4556
if isinstance(bands, basisstring):
4657
bands = [bands]
4758
collection = collection.select(bands)
59+
if crsTransform == True:
60+
image = collection.first().getInfo()
61+
crsTransform = image['bands'][0]['crs_transform']
4862
try:
4963
data = collection.getRegion(eeGeometry, scale, epsg, crsTransform).getInfo()
5064
except Exception, e:
51-
if e.message['code'] == 400 and "Too many values" in e.message['message']:
52-
LOGGER.info('Too many pixels in polygon: '+e.message['message'])
53-
54-
msgAr = e.message['message'].split(' ')
55-
points = int(msgAr[msgAr.index('points')-1])
56-
bands = int(msgAr[msgAr.index('bands')-1])
57-
images = int(msgAr[msgAr.index('images')-1])
58-
limit = 1048576
59-
else:
60-
raise e
61-
sys.exit(1)
65+
raise e
66+
#if e.message['code'] == 400 and "Too many values" in e.message['message']:
67+
# LOGGER.info('Too many pixels in polygon: '+e.message['message'])
68+
#
69+
# msgAr = e.message['message'].split(' ')
70+
# points = int(msgAr[msgAr.index('points')-1])
71+
# bands = int(msgAr[msgAr.index('bands')-1])
72+
# images = int(msgAr[msgAr.index('images')-1])
73+
# limit = 1048576
74+
#else:
75+
# raise e
76+
# sys.exit(1)
6277

6378
return data
6479

80+
def reduceRegion(self):
81+
pass
82+
6583
def download(self, image, path):
6684
urls = []
6785
if isinstance(image, ee.Image):

pyEOM/tasks.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,9 @@ def start(self):
142142
return self.processing['source'].ingest(self.format)
143143

144144
elif "LANDSAT" == dataset[0]:
145-
pass
146-
#self.processing[dataset] = Landsat.Dataset(dataset)
145+
from datasets import Landsat
146+
self.processing['source'] = Landsat.GEE(task)
147+
return self.processing['source'].run()
147148
elif "NOAA" == dataset[0]:
148149
pass
149150

0 commit comments

Comments
 (0)