Quickstart

Z tego przewodnika dowiesz się, jak szybko zacząć wysyłać zapytania do interfejsu Earth Engine REST API z Pythona za pomocą Google Colab. Te same koncepcje dotyczą dostępu do interfejsu API z innych języków i środowisk.

Uwaga: interfejs API (typu) REST zawiera nowe i funkcje zaawansowane, które mogą nie być odpowiednie dla wszystkich użytkowników. Jeśli dopiero zaczynasz korzystać z Earth Engine, zapoznaj się z przewodnikiem po języku JavaScript.

Zanim zaczniesz

Postępuj zgodnie z tymi instrukcjami, aby:

Konfigurowanie notatnika Colab

Jeśli zaczynasz od zera, możesz utworzyć nowy notatnik Colab, klikając NOWY NOTATNIK na stronie startowej Colab, i wpisać przykładowe kody poniżej w nowej komórce kodu. W Colab jest już zainstalowany pakiet Cloud SDK. Obejmuje to narzędzie wiersza poleceń gcloud, którego możesz używać do zarządzania usługami Cloud. Możesz też uruchomić notatnik demonstracyjny, klikając przycisk na początku tej strony.

Uwierzytelnianie w Google Cloud

Najpierw musisz się zalogować, aby móc wysyłać uwierzytelnione żądania do Google Cloud.

W Colab możesz uruchamiać:

PROJECT = 'my-project'
!gcloud auth login --project {PROJECT}

(Jeśli pracujesz lokalnie, możesz użyć wiersza poleceń, zakładając, że masz zainstalowany pakiet Cloud SDK):

PROJECT='my-project'
gcloud auth login --project $PROJECT

Zaakceptuj opcję logowania się za pomocą konta użytkownika Google i dokończ proces logowania.

Uzyskiwanie pliku klucza prywatnego dla konta usługi

Zanim użyjesz konta usługi do uwierzytelniania, musisz pobrać plik klucza prywatnego. Aby to zrobić w Colab, pobierz plik na maszynę wirtualną notatnika:

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}

Możesz też użyć wiersza poleceń:

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

Uzyskiwanie dostępu do danych logowania i ich testowanie

Możesz teraz wysłać pierwsze zapytanie do interfejsu Earth Engine API. Użyj klucza prywatnego, aby uzyskać dane logowania. Użyj danych logowania, aby utworzyć autoryzowaną sesję do wysyłania żądań HTTP. Możesz go wpisać w nowej komórce kodu w notatniku Colab. (Jeśli używasz wiersza poleceń, musisz się upewnić, że zainstalowane są niezbędne biblioteki).

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))

Jeśli wszystko jest skonfigurowane prawidłowo, uruchomienie tego polecenia spowoduje wyświetlenie danych wyjściowych, które wyglądają tak:

{'id': 'LANDSAT',
 'name': 'projects/earthengine-public/assets/LANDSAT',
 'type': 'FOLDER'}

Wybierz zbiór danych

Dostępne zbiory danych możesz wyszukiwać i przeglądać za pomocą edytora kodu Earth Engine na stronie code.earthengine.google.com. Poszukajmy danych z satelity Sentinel 2. (Jeśli po raz pierwszy korzystasz z edytora kodu, po zalogowaniu się pojawi się prośba o autoryzację dostępu do Earth Engine w Twoim imieniu). W edytorze kodu wyszukaj „sentinel” w polu wyszukiwania u góry. Pojawi się kilka zbiorów danych rastrowych:

Kliknij „Sentinel-2: MultiSpectral Instrument (MSI), Level-1C” (Sentinel-2: instrument wielospektralny (MSI), poziom 1C):

Strony z opisem zbioru danych, takie jak ta, zawierają najważniejsze informacje potrzebne do korzystania z dowolnego zbioru danych w publicznym Data Catalog Earth Engine, w tym krótki opis zbioru danych, linki do dostawcy danych, pod którymi można znaleźć dodatkowe informacje, informacje o wszelkich ograniczeniach dotyczących korzystania ze zbioru danych oraz identyfikator zasobu zbioru danych w Earth Engine.

W tym przypadku po prawej stronie okna widzimy, że jest to komponent kolekcji obrazów, którego ścieżka to COPERNICUS/S2_HARMONIZED.

Zapytanie o konkretne obrazy

Ten zbiór danych Sentinel-2 zawiera ponad 2 miliony zdjęć z całego świata od 2015 roku do chwili obecnej. Wyślijmy zapytanie projects.assets.listImages do kolekcji zdjęć, aby znaleźć dane z kwietnia 2017 r. z niskim zachmurzeniem, które obejmują określony punkt w Mountain View w Kalifornii.

import urllib

coords = [-122.085, 37.422]

project = 'projects/earthengine-public'
asset_id = 'COPERNICUS/S2_HARMONIZED'
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))

Ten skrypt wysyła zapytanie do kolekcji o pasujące obrazy, dekoduje wynikową odpowiedź JSON i wyświetla identyfikator zasobu oraz zachmurzenie dla każdego pasującego komponentu z obrazem. Dane wyjściowe powinny wyglądać tak:

COPERNICUS/S2_HARMONIZED/20170420T184921_20170420T190203_T10SEG : 4.3166
COPERNICUS/S2_HARMONIZED/20170430T190351_20170430T190351_T10SEG : 0

Widać, że w tym miesiącu wykonano 2 zdjęcia tego punktu, na których zachmurzenie jest niewielkie.

Sprawdzanie konkretnego obrazu

Wygląda na to, że jedno z pasujących zdjęć nie ma praktycznie żadnego zachmurzenia. Przyjrzyjmy się bliżej temu zasobowi, którego identyfikator to COPERNICUS/S2_HARMONIZED/20170430T190351_20170430T190351_T10SEG. Pamiętaj, że wszystkie zasoby katalogu publicznego należą do projektu earthengine-public. Oto fragment kodu w Pythonie, który wysyła zapytanie projects.assets.get, aby pobrać szczegóły konkretnego zasobu według identyfikatora, wyświetlić dostępne pasma danych i wyświetlić bardziej szczegółowe informacje o pierwszym paśmie:

asset_id = 'COPERNICUS/S2_HARMONIZED/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))

Dane wyjściowe powinny wyglądać mniej więcej tak:

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"
}

Lista pasm danych odpowiada temu, co widzieliśmy wcześniej w opisie zbioru danych. Widzimy, że ten zbiór danych zawiera 16-bitowe dane całkowite w układzie współrzędnych EPSG:32610, czyli UTM Zone 10N. To pierwsze pasmo ma identyfikator B1 i rozdzielczość 60 metrów na piksel. Początek obrazu znajduje się w pozycji (499980,4200000) w tym układzie współrzędnych.

Ujemna wartość affineTransform.scaleY wskazuje, że punkt początkowy znajduje się w północno-zachodnim rogu obrazu, jak to zwykle bywa: rosnące indeksy pikseli y odpowiadają malejącym współrzędnym przestrzennym y (w kierunku południowym).

Pobieram wartości pikseli

Wyślijmy zapytanie projects.assets.getPixels, aby pobrać dane z pasm o wysokiej rozdzielczości tego obrazu. Na stronie opisu zbioru danych podano, że pasma B2, B3, B4 i B8 mają rozdzielczość 10 metrów na piksel. Ten skrypt pobiera z tych 4 pasm kafelek danych o wymiarach 256 x 256 pikseli w lewym górnym rogu. Wczytanie danych w formacie numpy NPY ułatwia dekodowanie odpowiedzi do tablicy danych Pythona.

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)

Dane wyjściowe powinny wyglądać tak:

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)]]

Aby wybrać inny zestaw pikseli z tego obrazu, odpowiednio określ affineTransform. Pamiętaj, że parametr affineTransform jest określony w układzie współrzędnych przestrzennych obrazu. Jeśli chcesz dostosować lokalizację punktu początkowego we współrzędnych pikseli, użyj tego prostego wzoru:

request_origin = image_origin + pixel_scale * offset_in_pixels

Generowanie miniatury

Możemy użyć podobnego mechanizmu, aby wygenerować miniaturę RGB tego obrazu. Zamiast prosić o dane w ich natywnej rozdzielczości, wyraźnie określimy region i wymiary obrazu. Aby uzyskać miniaturę całego obrazu, możemy użyć geometrii zasięgu obrazu jako regionu żądania. Na koniec, określając pasma obrazu czerwonego, zielonego i niebieskiego oraz odpowiedni zakres wartości danych, możemy uzyskać atrakcyjną miniaturę RGB.

Po połączeniu wszystkich elementów fragment kodu w Pythonie wygląda tak (przy użyciu widżetu wyświetlania obrazu 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)

Oto wynikowy obraz miniatury: