Quickstart

En esta guía, se explica cómo comenzar a emitir consultas a la API de REST de Earth Engine desde Python rápidamente con Google Colab. Los mismos conceptos se aplican al acceso a la API desde otros lenguajes y entornos.

Nota: La API de REST contiene funciones nuevas y avanzadas que tal vez no sean adecuadas para todos los usuarios. Si es la primera vez que usas Earth Engine, comienza con la guía de JavaScript.

Antes de comenzar

Sigue estas instrucciones para hacer lo siguiente:

Configura tu notebook de Colab

Si vas a comenzar esta guía de inicio rápido desde cero, puedes crear un notebook de Colab nuevo haciendo clic en NOTEBOOK NUEVO en la página de inicio de Colab y, luego, ingresar las muestras de código que se muestran a continuación en una celda de código nueva. Colab ya tiene instalado el SDK de Cloud. Esto incluye la herramienta de línea de comandos de gcloud que puedes usar para administrar los servicios de Cloud. También puedes ejecutar el notebook de demostración desde el botón que se encuentra al principio de esta página.

Autentica en Google Cloud

Lo primero que debes hacer es acceder para poder realizar solicitudes autenticadas a Google Cloud.

En Colab, puedes ejecutar lo siguiente:

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

(O, si ejecutas el comando de forma local, desde una línea de comandos, suponiendo que tienes instalado el SDK de Cloud):

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

Acepta la opción para acceder con tu cuenta de usuario de Google y completa el proceso de acceso.

Obtén un archivo de claves privadas para tu cuenta de servicio

Antes de poder usar la cuenta de servicio para la autenticación, debes descargar un archivo de claves privadas. Para hacerlo en Colab, descarga a la VM del 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}

O bien, desde la línea de comandos:

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

Cómo acceder a tus credenciales y probarlas

Ahora puedes enviar tu primera consulta a la API de Earth Engine. Usa la clave privada para obtener credenciales. Usa las credenciales para crear una sesión autorizada y realizar solicitudes HTTP. Puedes ingresar esto en una celda de código nueva de tu notebook de Colab. (Si usas la línea de comandos, deberás asegurarte de que estén instaladas las bibliotecas necesarias).

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

Si todo está configurado correctamente, al ejecutar este comando, se generará un resultado similar al siguiente:

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

Elige un conjunto de datos

Puedes buscar y explorar los conjuntos de datos disponibles con el Editor de código de Earth Engine en code.earthengine.google.com. Busquemos algunos datos de Sentinel 2. (Si es la primera vez que usas el editor de código, se te pedirá que lo autorices para acceder a Earth Engine en tu nombre cuando accedas). En el editor de código, busca "centinela" en el cuadro de búsqueda de la parte superior. Aparecerán varios conjuntos de datos ráster:

Haz clic en "Sentinel-2: MultiSpectral Instrument (MSI), Level-1C":

Las páginas de descripción de conjuntos de datos, como esta, incluyen la información fundamental que necesitas para usar cualquier conjunto de datos del catálogo de datos públicos de Earth Engine, como una breve descripción del conjunto de datos, vínculos al proveedor de datos para obtener detalles adicionales, información sobre las restricciones de uso que se puedan aplicar al conjunto de datos y el ID del activo de Earth Engine del conjunto de datos.

En este caso, vemos en el lado derecho de la ventana que se trata de un recurso de colección de imágenes cuya ruta es COPERNICUS/S2.

Cómo consultar imágenes específicas

Este conjunto de datos de Sentinel-2 incluye más de dos millones de imágenes que cubren el mundo desde 2015 hasta la actualidad. Emitamos una consulta projects.assets.listImages en la colección de imágenes para encontrar algunos datos de abril de 2017 con poca cobertura de nubes que incluyan un punto en particular en Mountain View, California.

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

Esta secuencia de comandos consulta la colección para buscar imágenes coincidentes, decodifica la respuesta JSON resultante y, luego, imprime el ID del activo y la cobertura de nubes de cada activo de imagen coincidente. El resultado debería verse así:

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

Evidentemente, hay dos imágenes sobre este punto que se tomaron en este mes y tienen una cobertura de nubes baja.

Cómo inspeccionar una imagen en particular

Parece que una de las coincidencias no tiene cobertura de nubes. Analicemos con más detalle ese activo, cuyo ID es COPERNICUS/S2/20170430T190351_20170430T190351_T10SEG. Ten en cuenta que todos los recursos del catálogo público pertenecen al proyecto earthengine-public. A continuación, se muestra un fragmento de Python que emitirá una consulta projects.assets.get para recuperar los detalles de ese activo en particular por ID, imprimir las bandas de datos disponibles y, luego, imprimir información más detallada sobre la primera banda:

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

El resultado debería ser similar a este:

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

La lista de bandas de datos corresponde a lo que vimos antes en la descripción del conjunto de datos. Podemos ver que este conjunto de datos tiene datos de números enteros de 16 bits en el sistema de coordenadas EPSG:32610 o UTM Zone 10N. Esta primera banda tiene el ID B1 y una resolución de 60 metros por píxel. El origen de la imagen se encuentra en la posición (499980,4200000) en este sistema de coordenadas.

El valor negativo de affineTransform.scaleY indica que el origen se encuentra en la esquina noroeste de la imagen, como suele ser el caso: los índices de píxeles y crecientes corresponden a coordenadas espaciales y decrecientes (dirección sur).

Cómo recuperar valores de píxeles

Emitamos una consulta projects.assets.getPixels para recuperar algunos datos de las bandas de alta resolución de esta imagen. En la página de descripción del conjunto de datos, se indica que las bandas B2, B3, B4 y B8 tienen una resolución de 10 metros por píxel. Este script recupera el mosaico de datos de 256 x 256 píxeles ubicado en la esquina superior izquierda de esas cuatro bandas. Cargar los datos en el formato numpy NPY facilita la decodificación de la respuesta en un array de datos de 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)

El resultado debería verse así:

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

Para seleccionar un conjunto diferente de píxeles de esta imagen, simplemente especifica el affineTransform según corresponda. Recuerda que el affineTransform se especifica en el sistema de referencia de coordenadas espaciales de la imagen. Si deseas ajustar la ubicación del origen en coordenadas de píxeles, usa esta fórmula simple:

request_origin = image_origin + pixel_scale * offset_in_pixels

Cómo generar una imagen de miniatura

Podemos usar un mecanismo similar para generar una miniatura RGB de esta imagen. En lugar de solicitar datos en su resolución nativa, especificaremos una región y dimensiones de imagen de forma explícita. Para obtener una miniatura de toda la imagen, podemos usar la geometría de la huella de la imagen como región de solicitud. Por último, si especificamos las bandas de imagen roja, verde y azul, y un rango adecuado de valores de datos, podemos obtener una atractiva imagen en miniatura RGB.

Si juntamos todo, el fragmento de Python se verá de la siguiente manera (con el widget de visualización de imágenes IPython de 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)

Esta es la imagen de miniatura resultante: