¿Cómo acceder de manera eficiente a los archivos con GDAL desde un bucket de S3 usando VSIS3?

18

Por lo tanto, GDAL ha agregado recientemente una nueva característica que permite la lectura aleatoria de archivos de cubo S3. Estoy buscando recortar imágenes GDAL de múltiples mosaicos de una imagen sin tener que descargar todo el archivo. Solo he visto documentación muy escasa sobre cómo configurar y acceder a un bucket S3 a través de GDAL y estoy un poco confundido sobre cómo comenzar. ¿Alguien tendría la amabilidad de proporcionar un ejemplo / tutorial extremadamente breve sobre cómo se haría para configurar el sistema de archivos virtual para GDAL para lograr este objetivo? ¡Ptos de bonificación si su solución permite que se realice una secuencia de comandos a través de Python!

Para aclarar: ya lo hemos hecho en Python. El problema con Python es que tienes que descargar toda la imagen para operarla con ella. La versión más nueva de GDAL tiene soporte para montar el cubo S3 de modo que si necesitamos recortar una pequeña porción de la imagen, podamos operar directamente en esa porción más pequeña. Por desgracia, como la característica solo se lanzó en la rama estable en enero, no he encontrado ninguna documentación al respecto. Por lo tanto, la solución debería usar el sistema VSI3 en la versión más reciente de GDAL o usar el sistema de manera inteligente para evitar que el usuario necesite descargar la imagen completa a una unidad EBS para operarla.

Es decir, se otorgará la recompensa por la respuesta que utiliza las API de VSI que se encuentran en las versiones más recientes de GDAL para que no sea necesario leer todo el archivo en la memoria o el disco. Además, los cubos que usamos no siempre son públicos, por lo que muchos de los trucos HTTP que se publican no funcionarán en muchas de nuestras situaciones.

Skylion
fuente
No hay experiencia con S3 / buckets, pero esta publicación puede ser de interés: enlace . Usado de manera similar (?)
cm1
@ cm1 Gracias, esa documentación ha sido la mejor ayuda hasta ahora.
Skylion
Alegra oírlo. Creo que esta es una gran pregunta que has hecho y la estoy observando de cerca. ¡Espero que usted / otros resuelvan y publiquen una buena solución aquí!
cm1

Respuestas:

18

Descubrí que cuando algo no está particularmente bien documentado en GDAL, mirar a través de sus pruebas puede ser útil.

El /vsis3módulo de prueba tiene algunos ejemplos simples, aunque no tiene ningún ejemplo de leer fragmentos en realidad.

He improvisado el siguiente código basado en el módulo de prueba, pero no puedo probarlo porque GDAL / vsis3 requiere credenciales y no tengo una cuenta de AWS.

"""This should read from the Sentinal-2 public dataset
   More info - http://sentinel-pds.s3-website.eu-central-1.amazonaws.com"""

from osgeo import gdal
import numpy as np

# These only need to be set if they're not already in the environment,
# ~/.aws/config, or you're running on an EC2 instance with an IAM role.
gdal.SetConfigOption('AWS_REGION', 'eu-central-1')
gdal.SetConfigOption('AWS_SECRET_ACCESS_KEY', 'MY_AWS_SECRET_ACCESS_KEY')
gdal.SetConfigOption('AWS_ACCESS_KEY_ID', 'MY_AWS_ACCESS_KEY_ID')
gdal.SetConfigOption('AWS_SESSION_TOKEN', 'MY_AWS_SESSION_TOKEN')

# 'sentinel-pds' is the S3 bucket name
path = '/vsis3/sentinel-pds/tiles/10/S/DG/2015/12/7/0/B01.jp2'
ds = gdal.Open(path)

band = ds.GetRasterBand(1)

xoff, yoff, xcount, ycount = (0, 0, 10, 10)
np_array = band.ReadAsArray(xoff, yoff, xcount, ycount)
usuario2856
fuente
2
Woot funciona como un encanto! Aquí hay un ejemplo de recorte de la línea de comandos por cierto: gdal_translate --config AWS_REGION "some_region" --config AWS_ACCESS_KEY_ID "KEY_ID" --config AWS_SECRET_ACCESS_KEY "ACCESS_KEY" \ -srcwin 000 000 1000 1000 \ "/vile3/bucket3/vile3/bucket3/bucket3/ from_s3.tif
Skylion
¿Cómo son esos valores que escondiste? Creo que KEY_ID es una cadena de texto corta, como un nombre de usuario. ¿Qué es ACCESS_KEY? Parece que es lo que hay en un archivo pem pero tiene alrededor de 1000 caracteres, por lo que debe ser otra cosa.
Solx
Esas serán solo cadenas con números y letras como un nombre de usuario y contraseña. Puede obtener esas cadenas configurando roles de IAM en AWS
RutgerH
10

Ya que /vsis3/ está implementado en GDAL, también puede usarlo rasteriopara leer Windows de conjuntos de datos S3. Esto requiere que sus credenciales estén configuradas para boto o que use el controlador de sesión de rasterios AWS .

import rasterio

with rasterio.open('s3://landsat-pds/L8/139/045/LC81390452014295LGN00/LC81390452014295LGN00_B1.TIF') as ds:
    window = ds.read(window=((0, 100), (0, 100)))  # read a 100 by 100 window in the upper left corner.

Ver también rasterios windowed-rw y documentos VSI .

Kersten
fuente
1

Intente utilizar un archivo XML para almacenar la información de WMS, encontrará más detalles en la documentación de GDAL WMS .

Aquí hay un ejemplo de archivo WMS XML para recuperar datos de la API de Elevación de Mapzen:

<GDAL_WMS>
  <Service name="TMS">
    <ServerUrl>https://s3.amazonaws.com/elevation-tiles-prod/geotiff/${z}/${x}/${y}.tif</ServerUrl>
  </Service>
  <DataWindow>
    <UpperLeftX>-20037508.34</UpperLeftX>
    <UpperLeftY>20037508.34</UpperLeftY>
    <LowerRightX>20037508.34</LowerRightX>
    <LowerRightY>-20037508.34</LowerRightY>
    <TileLevel>14</TileLevel>
    <TileCountX>1</TileCountX>
    <TileCountY>1</TileCountY>
    <YOrigin>top</YOrigin>
  </DataWindow>
  <Projection>EPSG:3857</Projection>
  <BlockSizeX>512</BlockSizeX>
  <BlockSizeY>512</BlockSizeY>
  <BandsCount>1</BandsCount>
  <DataType>Int16</DataType>
  <ZeroBlockHttpCodes>403,404</ZeroBlockHttpCodes>
  <DataValues>
    <NoData>-32768</NoData>
  </DataValues>
  <Cache/>
</GDAL_WMS>

Luego puede recortar a un cuadro delimitador de la siguiente manera:

gdalwarp -of "GTiff" -te -13648825.0817 4552130.7825 -13627575.5878 4565507.2624 mapzen_wms.xml test.tif
Clhenrick
fuente
Si bien esta es una respuesta útil, ya almacenamos en caché los metadatos de manera similar, pero queremos saber cómo usar la API VSI para poder recortar rápidamente pequeñas porciones de imágenes grandes.
Skylion
No estoy seguro de si es porque el punto final de la API de Mapzen es un WMS en mosaico, pero el código anterior se ejecutó en menos de un minuto, ¿estás seguro de que la API de VSI será más rápida?
clhenrick
Estamos trabajando con MUY grandes rásteres y grandes conjuntos de datos de ráster, el cuello de botella es definitivamente IO. Además, los cubos que utilizamos son privados y requieren credenciales, lo que significa que usar la API S3 http no funcionará en nuestro caso. No es que tengamos que leer cada imagen, es que sabemos que tenemos que tirar una pequeña porción de una imagen muy grande.
Skylion
0

No sé mucho sobre los cubos S3, pero parece que es una unidad de almacenamiento en la nube con autenticación que utiliza los servicios http REST. es decir, podría usarse como un punto de montaje ordinario, con una uri asociada.

Si está buscando recortar partes de imágenes / ráster, entonces el archivo debe estar en un formato apropiado.

Eche un vistazo a la especificación TMS http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification

(Quizás netCDF también podría hacer el truco).

GDAL también lee y escribe formatos TMS. Básicamente es solo una estructura de directorio estándar con algunos archivos de metadatos.

Ahora, el truco es crear sobre la marcha la url con los parámetros de extensión geográfica a través del controlador TMS.

Eche un vistazo a la documentación del controlador OpenLayers TMS: http://dev.openlayers.org/docs/files/OpenLayers/Layer/TMS-js.html Para ver cómo maneja las solicitudes en función de la ubicación, el zoom y la extensión.

Por supuesto que se puede hacer en Python. Primero debe crear el URI apropiado del "punto de montaje" (o ruta) con viscurl (de acuerdo con la documentación) y luego, una vez montado, vaya al mosaico específico de acuerdo con la especificación TMS (que es una extensión de la ruta) .

Juan
fuente
Acabo de agregar algunas aclaraciones para diferenciarlo de solo usar la interfaz S3 en Python.
Skylion