Python >> Tutoriel Python >  >> Python Tag >> Array

Earth Engine :le moyen le plus simple de passer d'une image EE à un tableau pour une utilisation dans sklearn ?

Idéalement, il y aurait un moyen de convertir des objets d'image EE en tableaux NumPy lisibles par sklearn directement à l'aide de l'API Python EE.

ee.Image.sampleRectangle() fait ça.

Cependant, il existe une limite de 262144 pixels pouvant être transférés. La limite de transfert de données interactives est en place pour protéger votre système contre le blocage (il est facile de demander des téraoctets de données sans s'en rendre compte).

Ainsi, dans le cas d'une grande surface, vos options consistent à exporter des images vers Google Drive ou Google Cloud Storage, puis à importer vers l'API Earth Engine Python. L'utilisation de Google Colab rend cela facile - EE est installé par défaut et il y a une intégration avec GDrive et GCS. Les méthodes d'exportation de tâches par lots Earth Engine sont mieux équipées pour traiter les données volumineuses (divisent les exportations volumineuses en fichiers GeoTIFF de taille gérable).

Même si ee.Image.sampleRectangle() peut ne pas être utile pour votre application, voici une démo au cas où cela aiderait les autres.

Le script Python suivant transfère trois bandes Landsat 8 pour une région rectangulaire au client Python et convertit les tableaux EE en tableaux numpy, puis empile les tableaux et affiche le tableau 3D sous la forme d'une représentation d'image RVB de la région.

Bloc-notes IPython

import ee
import numpy as np
import matplotlib.pyplot as plt

ee.Authenticate()
ee.Initialize()


# Define an image.
img = ee.Image('LANDSAT/LC08/C01/T1_SR/LC08_038029_20180810') \
  .select(['B4', 'B5', 'B6'])

# Define an area of interest.
aoi = ee.Geometry.Polygon(
  [[[-110.8, 44.7],
    [-110.8, 44.6],
    [-110.6, 44.6],
    [-110.6, 44.7]]], None, False)

# Get 2-d pixel array for AOI - returns feature with 2-D pixel array as property per band.
band_arrs = img.sampleRectangle(region=aoi)

# Get individual band arrays.
band_arr_b4 = band_arrs.get('B4')
band_arr_b5 = band_arrs.get('B5')
band_arr_b6 = band_arrs.get('B6')

# Transfer the arrays from server to client and cast as np array.
np_arr_b4 = np.array(band_arr_b4.getInfo())
np_arr_b5 = np.array(band_arr_b5.getInfo())
np_arr_b6 = np.array(band_arr_b6.getInfo())
print(np_arr_b4.shape)
print(np_arr_b5.shape)
print(np_arr_b6.shape)

# Expand the dimensions of the images so they can be concatenated into 3-D.
np_arr_b4 = np.expand_dims(np_arr_b4, 2)
np_arr_b5 = np.expand_dims(np_arr_b5, 2)
np_arr_b6 = np.expand_dims(np_arr_b6, 2)
print(np_arr_b4.shape)
print(np_arr_b5.shape)
print(np_arr_b6.shape)

# Stack the individual bands to make a 3-D array.
rgb_img = np.concatenate((np_arr_b6, np_arr_b5, np_arr_b4), 2)
print(rgb_img.shape)

# Scale the data to [0, 255] to show as an RGB image.
rgb_img_test = (255*((rgb_img - 100)/3500)).astype('uint8')
plt.imshow(rgb_img_test)
plt.show()

Ce que j'ai fait, c'est télécharger les images au format tifs de GEE (quelque chose que vous devrez peut-être faire en morceaux compte tenu de la taille). J'ai utilisé le getDownloadURL() fonction car elle est plus rapide, même si j'ai lu que la méthode préférée consiste à utiliser 'Export.image.toDrive()'. Ensuite, avec mes bandes en tant que tifs séparés, je les empile ensemble en utilisant rasterio/GDAL en un seul tif. Je les garde dans le fichier zip de sortie pour économiser de l'espace.

    # This gets the path names of the individual band tifs in the zip folder and formats 
    # them into a format readable by rasterio.open()

    import rasterio
    import numpy as np
    from zipfile import Zipfile

    file_list = []
    stack_path = 'C:\Users\stack.tif'
    img_file = 'C:\Users\LC08_023036_20130429'

    with ZipFile(str(img_file.with_suffix('.zip')), 'r') as f:
        names = f.namelist()
        names = [str(img_file.with_suffix('.zip!')) + name for name in names]
        names = ['zip://' + name for name in names]
        for file in names:
            if file.endswith('.tif'):
                file_list.append(file)

    # Read each layer, convert to float, and write it to stack
    with rasterio.open(stack_path, 'w', **meta) as dst:
        for id, layer in enumerate(file_list, start=0):
            with rasterio.open(layer) as src1:
                dst.write_band(id + 1, src1.read(1).astype('float32'))

Lorsque j'utilise sklearn qui nécessite une matrice 2D, je la refaçonne simplement.

    with rasterio.open(str(stack_path), 'r') as ds:
        data = ds.read()
        data = data.transpose((1, -1, 0))  # Not sure why the rasterio.read output is originally (D, W, H)
        data[data == -999999] = np.nan  # NoData values that I noted in GEE
        data[np.isneginf(data)] = np.nan

    # Reshape into a 2D array, where rows = pixels and cols = features/bands
    data_vector = data.reshape([data.shape[0] * data.shape[1], data.shape[2]])

    # Remove NaNs
    data_vector = data_vector[~np.isnan(data_vector).any(axis=1)]

Bien que le téléchargement des fichiers soit fastidieux, si vous créez un pipeline d'empilement et de remodelage tif pour tous vos fichiers, le processus est grandement simplifié.


Prochain article
No