Quickstart

이 가이드에서는 Google Colab을 사용하여 Python에서 Earth Engine REST API에 쿼리를 빠르게 시작하는 방법을 설명합니다. 다른 언어와 환경에서 API에 액세스하는 경우에도 동일한 개념이 적용됩니다.

참고: REST API에는 일부 사용자에게 적합하지 않을 수 있는 새롭고 고급 기능이 포함되어 있습니다. Earth Engine을 처음 사용하는 경우 JavaScript 가이드로 시작하세요.

시작하기 전에

이 안내에 따라 다음 작업을 할 수 있습니다.

Colab 노트북 설정하기

이 빠른 시작을 처음부터 시작하는 경우 Colab 시작 페이지에서 새 노트북을 클릭하여 새 Colab 노트북을 만들고 아래의 코드 샘플을 새 코드 셀에 입력하면 됩니다. Colab에는 Cloud SDK가 이미 설치되어 있습니다. 여기에는 Cloud 서비스를 관리하는 데 사용할 수 있는 gcloud 명령줄 도구가 포함됩니다. 또는 이 페이지 시작 부분에 있는 버튼에서 데모 노트북을 실행합니다.

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에서 노트북 VM에 다운로드하려면 다음을 실행하세요.

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 요청을 수행할 승인된 세션을 만듭니다. 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'}

데이터 세트 선택

code.earthengine.google.comEarth Engine 코드 편집기를 사용하여 사용 가능한 데이터 세트를 검색하고 탐색할 수 있습니다. Sentinel 2 데이터를 찾아보겠습니다. (코드 편집기를 처음 사용하는 경우 로그인할 때 Earth Engine에 액세스할 수 있도록 승인하라는 메시지가 표시됩니다.) 코드 편집기에서 상단의 검색창에 'sentinel'을 검색합니다. 여러 래스터 데이터 세트가 표시됩니다.

'Sentinel-2: MultiSpectral Instrument (MSI), Level-1C'를 클릭합니다.

이 페이지와 같은 데이터 세트 설명 페이지에는 데이터 세트의 간략한 설명, 추가 세부정보를 얻기 위한 데이터 제공업체 링크, 데이터 세트에 적용될 수 있는 사용 제한에 관한 정보, 데이터 세트의 Earth Engine 애셋 ID 등 Earth Engine 공개 데이터 카탈로그에서 데이터 세트를 사용하는 데 필요한 중요한 정보가 포함되어 있습니다.

이 경우 창의 오른쪽에 경로가 COPERNICUS/S2인 이미지 컬렉션 저작물이 표시됩니다.

특정 이미지 쿼리

이 Sentinel-2 데이터 세트에는 2015년부터 현재까지 전 세계를 대상으로 한 200만 개 이상의 이미지가 포함되어 있습니다. 이미지 컬렉션에 대해 projects.assets.listImages 쿼리를 실행하여 2017년 4월의 데이터 중 캘리포니아주 마운틴뷰의 특정 지점을 포함하고 구름이 적은 데이터를 찾아보겠습니다.

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 응답을 디코딩하고, 일치하는 각 이미지 애셋의 애셋 ID와 운량을 출력합니다. 다음과 같이 출력됩니다.

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

이 지점에는 이번 달에 촬영되었으며 구름이 적은 두 개의 이미지가 있는 것으로 보입니다.

특정 이미지 검사

일치하는 항목 중 하나는 구름이 거의 없는 것으로 보입니다. ID가 COPERNICUS/S2/20170430T190351_20170430T190351_T10SEG인 애셋을 자세히 살펴보겠습니다. 모든 공개 카탈로그 애셋은 earthengine-public 프로젝트에 속합니다. 다음은 projects.assets.get 쿼리를 실행하여 ID별로 특정 애셋의 세부정보를 가져오고, 사용 가능한 데이터 밴드를 출력하고, 첫 번째 밴드에 관한 자세한 정보를 출력하는 Python 스니펫입니다.

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

데이터 범위 목록은 앞서 데이터 세트 설명에서 본 내용과 일치합니다. 이 데이터 세트에는 EPSG:32610 좌표계(UTM Zone 10N)의 16비트 정수 데이터가 있습니다. 이 첫 번째 밴드의 ID는 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)

결과 썸네일 이미지는 다음과 같습니다.