Quickstart

คู่มือนี้อธิบายวิธีเริ่มต้นใช้งานการออกคําค้นหาไปยัง Earth Engine REST API จาก Python โดยใช้ Google Colab อย่างรวดเร็ว แนวคิดเดียวกันนี้ใช้ได้กับการเข้าถึง API จากภาษาและสภาพแวดล้อมอื่นๆ ด้วย

หมายเหตุ: REST API มีฟีเจอร์ใหม่และขั้นสูงที่อาจไม่เหมาะกับผู้ใช้บางราย หากคุณเพิ่งเริ่มใช้ Earth Engine โปรดเริ่มต้นด้วยคู่มือ JavaScript

ก่อนเริ่มต้น

ทำตามวิธีการเหล่านี้เพื่อ

ตั้งค่า Colab Notebook

หากคุณเริ่มต้นคู่มือฉบับย่อนี้ตั้งแต่ต้น คุณสามารถสร้างสมุดบันทึก Colab ใหม่ได้โดยคลิกสมุดบันทึกใหม่จากหน้าเริ่มต้นของ Colab แล้วป้อนตัวอย่างโค้ดด้านล่างลงในโค้ดเซลล์ใหม่ Colab ติดตั้ง Cloud SDK ไว้แล้ว ซึ่งรวมถึง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 Notebook ได้ (หากใช้บรรทัดคำสั่ง คุณจะต้องตรวจสอบว่าได้ติดตั้งไลบรารีที่จำเป็นแล้ว)

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 Editor ที่ code.earthengine.google.com มาดูข้อมูล Sentinel 2 กัน (หากใช้โปรแกรมแก้ไขโค้ดเป็นครั้งแรก ระบบจะแจ้งให้คุณให้สิทธิ์เข้าถึง Earth Engine ในนามของคุณเมื่อคุณลงชื่อเข้าใช้) ในเครื่องมือแก้ไขโค้ด ให้ค้นหา "sentinel" ในช่องค้นหาที่ด้านบน ชุดข้อมูลแรสเตอร์หลายชุดจะปรากฏขึ้น

คลิก "Sentinel-2: MultiSpectral Instrument (MSI), Level-1C"

หน้าคำอธิบายชุดข้อมูลเช่นหน้านี้มีข้อมูลสำคัญที่คุณต้องใช้เพื่อใช้ชุดข้อมูลในแคตตาล็อกข้อมูลสาธารณะของ Earth Engine ซึ่งรวมถึงคำอธิบายสั้นๆ ของชุดข้อมูล ลิงก์ไปยังผู้ให้บริการข้อมูลเพื่อดูรายละเอียดเพิ่มเติม ข้อมูลเกี่ยวกับการจำกัดการใช้งานที่อาจมีผลกับชุดข้อมูล และรหัสชิ้นงาน Earth Engine ของชุดข้อมูล

ในกรณีนี้ เราจะเห็นทางด้านขวาของหน้าต่างว่านี่คือชิ้นงานคอลเล็กชันรูปภาพที่มีเส้นทางเป็น COPERNICUS/S2

ค้นหารูปภาพที่เฉพาะเจาะจง

ชุดข้อมูล Sentinel-2 มีรูปภาพกว่า 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

เห็นได้ชัดว่ามีรูปภาพ 2 รูปเหนือจุดนี้ซึ่งถ่ายในเดือนนี้และมีเมฆปกคลุมต่ำ

ตรวจสอบรูปภาพที่เฉพาะเจาะจง

ดูเหมือนว่าการจับคู่รายการหนึ่งจะไม่มีเมฆปกคลุมเลย มาดูรายละเอียดเนื้อหาที่มีรหัส 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"
}

รายการแถบข้อมูลสอดคล้องกับสิ่งที่เราเห็นก่อนหน้านี้ในคำอธิบายชุดข้อมูล เราจะเห็นว่าชุดข้อมูลนี้มีข้อมูลจำนวนเต็ม 16 บิตในระบบพิกัด EPSG:32610 หรือ UTM Zone 10N แถบแรกมีรหัส B1 และความละเอียด 60 เมตรต่อพิกเซล ต้นทางของรูปภาพอยู่ที่ตำแหน่ง (499980,4200000) ในระบบพิกัดนี้

ค่าลบของ affineTransform.scaleY แสดงว่าจุดเริ่มต้นอยู่ที่มุมซ้ายบนของรูปภาพ ซึ่งมักจะเป็นเช่นนั้น โดยการเพิ่มดัชนีพิกเซล y จะสอดคล้องกับการลดพิกัดเชิงพื้นที่ y (มุ่งหน้าไปทางใต้)

การดึงค่าพิกเซล

มาส่งคำค้นหา projects.assets.getPixels เพื่อดึงข้อมูลบางอย่างจากแถบความละเอียดสูงของรูปภาพนี้กัน หน้าคำอธิบายชุดข้อมูลระบุว่าแถบความถี่ B2, B3, B4 และ B8 มีความละเอียด 10 เมตรต่อพิกเซล สคริปต์นี้จะดึงข้อมูลไทล์ขนาด 256x256 พิกเซลที่ด้านซ้ายบนจากแถบทั้ง 4 แถบ การโหลดข้อมูลในรูปแบบ 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 จะมีลักษณะดังนี้ (ใช้เครื่องมือแสดงรูปภาพ IPython ของ Colab)

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)

นี่คือภาพขนาดย่อที่ได้