Quickstart

本指南介绍了如何使用 Google Colab 快速开始通过 Python 向 Earth Engine REST API 发出查询。从其他语言和环境访问该 API 时,也适用相同的概念。

注意: REST API 包含新功能和高级功能,可能不适合所有用户。如果您刚开始接触 Earth Engine,请先参阅 JavaScript 指南。

准备工作

请按照这些说明执行以下操作:

设置 Colab 笔记本

如果您是从头开始本快速入门,可以点击 Colab 起始页中的新建笔记本,创建一个新的 Colab 笔记本,然后将以下代码示例输入到新的代码单元中。Colab 已安装 Cloud SDK。其中包括 gcloud 命令行工具,可用于管理 Cloud 服务。或者,您也可以点击本页开头的按钮,运行演示笔记本。

向 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 中执行此操作,请下载到笔记本虚拟机:

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

选择数据集

您可以使用 Earth Engine 代码编辑器(网址为 code.earthengine.google.com)搜索和探索可用数据集。我们来查找一些 Sentinel 2 数据。(如果您是首次使用代码编辑器,系统会在您登录时提示您授权其代表您访问 Earth Engine。)在代码编辑器顶部的搜索框中搜索“sentinel”。系统会显示多个光栅数据集:

点击“Sentinel-2: MultiSpectral Instrument (MSI), Level-1C”:

像这样的数据集说明页面包含您使用 Earth Engine 公共 Data Catalog 中的任何数据集所需的关键信息,包括数据集的简要说明、指向数据提供商的链接(可获取更多详细信息)、可能适用于数据集的任何使用限制的相关信息,以及数据集的 Earth Engine 资产 ID。

在本例中,我们在窗口右侧看到,这是一个路径为 COPERNICUS/S2_HARMONIZED 的图片集资源。

查询特定图片

此 Sentinel-2 数据集包含 2015 年至今覆盖全球的 200 多万张图像。我们针对该图片集合发出 projects.assets.listImages 查询,以查找 2017 年 4 月的一些数据,这些数据具有低云量,并且包含加利福尼亚州山景城的一个特定点。

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

此脚本会查询集合中匹配的图片,解码生成的 JSON 响应,并输出每个匹配图片素材资源的资产 ID 和云量。输出应如下所示:

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

显然,该点上方有两张图片是在本月拍摄的,且云量较低。

检查特定映像

其中一个匹配项的云量似乎基本上为零。我们来详细了解一下该资产,其 ID 为 COPERNICUS/S2_HARMONIZED/20170430T190351_20170430T190351_T10SEG。请注意,所有公开目录资源都属于项目 earthengine-public。以下 Python 代码段会发出 projects.assets.get 查询,以按 ID 提取该特定资产的详细信息,输出可用的数据波段,并输出有关第一个波段的更详细信息:

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

输出应如下所示:

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 图片显示 widget):

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)

以下是生成的缩略图: