במדריך הזה מוסבר איך להתחיל במהירות להנפיק שאילתות ל-Earth Engine REST API מ-Python באמצעות Google Colab. אותם מושגים רלוונטיים לגישה לממשק ה-API משפות ומסביבות אחרות.
הערה: ממשק REST API כולל תכונות חדשות ומתקדמות, שיכול להיות שלא יתאימו לכל המשתמשים. אם אתם חדשים ב-Earth Engine, כדאי להתחיל עם מדריך JavaScript.
לפני שמתחילים
פועלים לפי ההוראות האלה כדי:
הגדרת מחברת Colab
אם אתם מתחילים את המדריך הזה מאפס, אתם יכולים ליצור notebook חדש של Colab על ידי לחיצה על NEW NOTEBOOK בדף הפתיחה של Colab, ולהזין את דוגמאות הקוד שבהמשך בתא קוד חדש. ב-Colab כבר מותקן Cloud SDK. הוא כולל את כלי שורת הפקודה gcloud
שבעזרתו אפשר לנהל שירותי ענן. אפשר גם להריץ את ה-notebook של ההדגמה באמצעות הלחצן שבתחילת הדף הזה.
אימות ל-Google Cloud
הדבר הראשון שצריך לעשות הוא להתחבר כדי שאפשר יהיה לשלוח בקשות מאומתות אל Google Cloud.
ב-Colab אפשר להריץ:
PROJECT = 'my-project' !gcloud auth login --project {PROJECT}
(או אם אתם מריצים באופן מקומי, משורת פקודה, בהנחה שה-Cloud SDK מותקן:)
PROJECT='my-project' gcloud auth login --project $PROJECT
מאשרים את האפשרות להתחבר באמצעות חשבון המשתמש האישי שלכם ב-Google ומשלימים את תהליך הכניסה.
קבלת קובץ מפתח פרטי לחשבון השירות
כדי להשתמש בחשבון השירות לאימות, צריך להוריד קובץ מפתח פרטי. כדי לעשות את זה ב-Colab, צריך להוריד את הקובץ למכונה הווירטואלית של ה-notebook:
SERVICE_ACCOUNT='foo-name@project-name.iam.gserviceaccount.com' KEY = 'my-secret-key.json' !gcloud iam service-accounts keys create {KEY} --iam-account {SERVICE_ACCOUNT}
לחלופין, משורת הפקודה:
SERVICE_ACCOUNT='foo-name@project-name.iam.gserviceaccount.com' KEY='my-secret-key.json' gcloud iam service-accounts keys create $KEY --iam-account $SERVICE_ACCOUNT
גישה לפרטי הכניסה ובדיקה שלהם
עכשיו אפשר לשלוח את השאילתה הראשונה אל Earth Engine API. משתמשים במפתח הפרטי כדי לקבל פרטי כניסה. משתמשים בפרטי הכניסה כדי ליצור סשן מורשה לשליחת בקשות HTTP. אפשר להזין את זה בתא קוד חדש ב-notebook של Colab. (אם אתם משתמשים בשורת הפקודה, תצטרכו לוודא שהספריות הנדרשות מותקנות).
from google.auth.transport.requests import AuthorizedSession from google.oauth2 import service_account credentials = service_account.Credentials.from_service_account_file(KEY) scoped_credentials = credentials.with_scopes( ['https://www.googleapis.com/auth/cloud-platform']) session = AuthorizedSession(scoped_credentials) url = 'https://earthengine.googleapis.com/v1alpha/projects/earthengine-public/assets/LANDSAT' response = session.get(url) from pprint import pprint import json pprint(json.loads(response.content))
אם הכל מוגדר בצורה נכונה, הפעלת הפקודה הזו תפיק פלט שנראה כך:
{'id': 'LANDSAT',
'name': 'projects/earthengine-public/assets/LANDSAT',
'type': 'FOLDER'}
בחירת מערך נתונים
אפשר לחפש ולעיין במערכי נתונים זמינים באמצעות כלי העריכה של קוד Earth Engine בכתובת code.earthengine.google.com. בואו נחפש נתונים של Sentinel 2. (אם זו הפעם הראשונה שאתם משתמשים בכלי לעריכת קוד, תתבקשו לאשר לו גישה ל-Earth Engine בשמכם כשתיכנסו לחשבון). בתיבת החיפוש בחלק העליון של עורך הקוד, מחפשים את המחרוזת sentinel. מופיעים כמה מערכי נתוני רסטר:

לוחצים על Sentinel-2: MultiSpectral Instrument (MSI), Level-1C:

דפי תיאור של מערכי נתונים כמו זה כוללים את המידע החשוב שצריך כדי להשתמש במערך נתונים כלשהו בקטלוג הנתונים הציבורי של Earth Engine, כולל תיאור קצר של מערך הנתונים, קישורים לספק הנתונים כדי לקבל פרטים נוספים, מידע על הגבלות שימוש שעשויות לחול על מערך הנתונים ומזהה הנכס של מערך הנתונים ב-Earth Engine.
במקרה הזה, בצד שמאל של החלון אפשר לראות שמדובר בנכס של אוסף תמונות, והנתיב שלו הוא COPERNICUS/S2
.
שאילתות לגבי תמונות ספציפיות
מערך הנתונים הזה של Sentinel-2 כולל יותר משני מיליון תמונות שמכסות את העולם משנת 2015 ועד היום. נריץ שאילתת projects.assets.listImages על אוסף התמונות כדי למצוא נתונים מאפריל 2017 עם כיסוי עננים נמוך שכולל נקודה מסוימת במאונטיין ויו, קליפורניה.
import urllib coords = [-122.085, 37.422] project = 'projects/earthengine-public' asset_id = 'COPERNICUS/S2' name = '{}/assets/{}'.format(project, asset_id) url = 'https://earthengine.googleapis.com/v1alpha/{}:listImages?{}'.format( name, urllib.parse.urlencode({ 'startTime': '2017-04-01T00:00:00.000Z', 'endTime': '2017-05-01T00:00:00.000Z', 'region': '{"type":"Point", "coordinates":' + str(coords) + '}', 'filter': 'CLOUDY_PIXEL_PERCENTAGE < 10', })) response = session.get(url) content = response.content for asset in json.loads(content)['images']: id = asset['id'] cloud_cover = asset['properties']['CLOUDY_PIXEL_PERCENTAGE'] print('%s : %s' % (id, cloud_cover))
הסקריפט הזה שולח שאילתה לאוסף כדי למצוא תמונות תואמות, מפענח את תגובת ה-JSON שמתקבלת ומדפיס את מזהה הנכס ואת כיסוי הענן לכל נכס תמונה תואם. הפלט אמור להיראות כך:
COPERNICUS/S2/20170420T184921_20170420T190203_T10SEG : 4.3166
COPERNICUS/S2/20170430T190351_20170430T190351_T10SEG : 0
נראה שיש שתי תמונות מעל הנקודה הזו שצולמו החודש ושיש בהן כיסוי עננים נמוך.
בדיקת תמונה מסוימת
נראה שאחד מהתצלומים התואמים צולם כמעט ללא עננים. בואו נבדוק את הנכס הזה, שמזהה שלו הוא COPERNICUS/S2/20170430T190351_20170430T190351_T10SEG
. שימו לב: כל הנכסים בקטלוג הציבורי שייכים לפרויקט earthengine-public
. הנה קטע קוד ב-Python שיבצע שאילתת projects.assets.get כדי לאחזר את הפרטים של אותו נכס ספציפי לפי מזהה, להדפיס את רצועות הנתונים הזמינות ולהדפיס מידע מפורט יותר על הרצועה הראשונה:
asset_id = 'COPERNICUS/S2/20170430T190351_20170430T190351_T10SEG' name = '{}/assets/{}'.format(project, asset_id) url = 'https://earthengine.googleapis.com/v1alpha/{}'.format(name) response = session.get(url) content = response.content asset = json.loads(content) print('Band Names: %s' % ','.join(band['id'] for band in asset['bands'])) print('First Band: %s' % json.dumps(asset['bands'][0], indent=2, sort_keys=True))
הפלט אמור להיראות כך:
Band Names: B1,B2,B3,B4,B5,B6,B7,B8,B8A,B9,B10,B11,B12,QA10,QA20,QA60
First Band: {
"dataType": {
"precision": "INTEGER",
"range": {
"max": 65535
}
},
"grid": {
"affineTransform": {
"scaleX": 60,
"scaleY": -60,
"translateX": 499980,
"translateY": 4200000
},
"crsCode": "EPSG:32610",
"dimensions": {
"height": 1830,
"width": 1830
}
},
"id": "B1",
"pyramidingPolicy": "MEAN"
}
רשימת רצועות הנתונים תואמת למה שראינו קודם בתיאור מערך הנתונים. אפשר לראות שבמערך הנתונים הזה יש נתוני מספרים שלמים (integer) של 16 ביט במערכת הקואורדינטות EPSG:32610, או UTM Zone 10N. לרצועה הראשונה יש מזהה B1
ורזולוציה של 60 מטרים לכל פיקסל. המיקום של מקור התמונה במערכת הקואורדינטות הזו הוא (499980,4200000).
הערך השלילי של affineTransform.scaleY
מציין שהמקור נמצא בפינה הצפון-מערבית של התמונה, כמו בדרך כלל: עלייה באינדקסים של הפיקסלים y
מתאימה לירידה בקואורדינטות המרחביות y
(התקדמות דרומה).
אחזור ערכי פיקסלים
נריץ שאילתת projects.assets.getPixels כדי לאחזר נתונים מהפסי הרזולוציה הגבוהה של התמונה הזו. בדף התיאור של מערך הנתונים מצוין שהרזולוציה של הפסים B2
, B3
, B4
ו-B8
היא 10 מטרים לכל פיקסל. הסקריפט מאחזר את משבצת הנתונים בגודל 256x256 פיקסלים בפינה הימנית העליונה מתוך ארבעת הפסים האלה. טעינת הנתונים בפורמט numpy
NPY מאפשרת לפענח בקלות את התשובה למערך נתונים של Python.
import numpy import io name = '{}/assets/{}'.format(project, asset_id) url = 'https://earthengine.googleapis.com/v1alpha/{}:getPixels'.format(name) body = json.dumps({ 'fileFormat': 'NPY', 'bandIds': ['B2', 'B3', 'B4', 'B8'], 'grid': { 'affineTransform': { 'scaleX': 10, 'scaleY': -10, 'translateX': 499980, 'translateY': 4200000, }, 'dimensions': {'width': 256, 'height': 256}, }, }) pixels_response = session.post(url, body) pixels_content = pixels_response.content array = numpy.load(io.BytesIO(pixels_content)) print('Shape: %s' % (array.shape,)) print('Data:') print(array)
הפלט אמור להיראות כך:
Shape: (256, 256)
Data:
[[( 899, 586, 351, 189) ( 918, 630, 501, 248) (1013, 773, 654, 378) ...,
(1014, 690, 419, 323) ( 942, 657, 424, 260) ( 987, 691, 431, 315)]
[( 902, 630, 541, 227) (1059, 866, 719, 429) (1195, 922, 626, 539) ...,
( 978, 659, 404, 287) ( 954, 672, 426, 279) ( 990, 678, 397, 304)]
[(1050, 855, 721, 419) (1257, 977, 635, 569) (1137, 770, 400, 435) ...,
( 972, 674, 421, 312) (1001, 688, 431, 311) (1004, 659, 378, 284)]
...,
[( 969, 672, 375, 275) ( 927, 680, 478, 294) (1018, 724, 455, 353) ...,
( 924, 659, 375, 232) ( 921, 664, 438, 273) ( 966, 737, 521, 306)]
[( 920, 645, 391, 248) ( 979, 728, 481, 327) ( 997, 708, 425, 324) ...,
( 927, 673, 387, 243) ( 927, 688, 459, 284) ( 962, 732, 509, 331)]
[( 978, 723, 449, 330) (1005, 712, 446, 314) ( 946, 667, 393, 269) ...,
( 949, 692, 413, 271) ( 927, 689, 472, 285) ( 966, 742, 516, 331)]]
כדי לבחור קבוצה אחרת של פיקסלים מהתמונה הזו, פשוט מציינים את affineTransform
בהתאם. חשוב לזכור שה-affineTransform
מצוין במערכת הייחוס של הקואורדינטות המרחביות של התמונה. אם רוצים להתאים את מיקום נקודת המוצא בקואורדינטות של פיקסלים, אפשר להשתמש בנוסחה הפשוטה הזו:
request_origin = image_origin + pixel_scale * offset_in_pixels
יצירת תמונה ממוזערת
אנחנו יכולים להשתמש במנגנון דומה כדי ליצור תמונה ממוזערת של התמונה הזו בפורמט RGB. במקום לבקש נתונים ברזולוציה המקורית שלהם, נציין אזור וממדי תמונה באופן מפורש. כדי לקבל תמונה ממוזערת של התמונה כולה, אפשר להשתמש בגיאומטריה של טביעת הרגל של התמונה כאזור הבקשה. לבסוף, על ידי ציון של רצועות התמונה האדומות, הירוקות והכחולות וטווח מתאים של ערכי נתונים, אפשר לקבל תמונה ממוזערת אטרקטיבית ב-RGB.
הקוד המלא של Python נראה כך (באמצעות הווידג'ט של Colab IPython
לתצוגת תמונות):
url = 'https://earthengine.googleapis.com/v1alpha/{}:getPixels'.format(name) body = json.dumps({ 'fileFormat': 'PNG', 'bandIds': ['B4', 'B3', 'B2'], 'region': asset['geometry'], 'grid': { 'dimensions': {'width': 256, 'height': 256}, }, 'visualizationOptions': { 'ranges': [{'min': 0, 'max': 3000}], }, }) image_response = session.post(url, body) image_content = image_response.content from IPython.display import Image Image(image_content)
הנה התמונה הממוזערת שנוצרה:
