Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.
Este tutorial basado en Python utiliza el SDK para Python (Boto3) y un bloc de notas Amazon Studio Classic. SageMaker Para completar esta demostración correctamente, asegúrese de tener los permisos AWS Identity and Access Management (IAM) necesarios para usar Geospatial y Studio Classic. SageMaker SageMaker geospatial requiere que tenga un usuario, grupo o rol que pueda acceder a Studio Classic. También debe tener una función de ejecución de SageMaker IA que especifique el director del servicio SageMaker geoespacial sagemaker-geospatial.amazonaws.com
en su política de confianza.
Para obtener más información sobre estos requisitos, consulte las funciones de SageMaker IAM geoespacial.
En este tutorial, se muestra cómo utilizar la API SageMaker geoespacial para realizar las siguientes tareas:
-
Encontrar las recopilaciones de datos ráster disponibles con
list_raster_data_collections
. -
Buscar una recopilación de datos ráster específica mediante
search_raster_data_collection
. -
Crear un trabajo de observación de la Tierra (EOJ) mediante
start_earth_observation_job
.
Utilizar list_raster_data_collections
para encontrar las colecciones de datos disponibles
SageMaker geospatial admite múltiples recopilaciones de datos ráster. Para obtener más información sobre las recopilaciones de datos disponibles, consulte Recopilaciones de datos.
Esta demostración utiliza datos satelitales recopilados de Sentinel-2 Satélites GeoTIFF
Para buscar en un área de interés (AOI), necesita el ARN asociado a los datos del satélite Sentinel-2. Para encontrar las recopilaciones de datos disponibles y las que están asociadas a las ARNs suyas Región de AWS, utilice la operación de la list_raster_data_collections
API.
Como la respuesta se puede paginar, debe usar la operación get_paginator
para devolver todos los datos relevantes:
import boto3
import sagemaker
import sagemaker_geospatial_map
import json
## SageMaker Geospatial is currently only avaialable in US-WEST-2
session = boto3.Session(region_name='us-west-2')
execution_role = sagemaker.get_execution_role()
## Creates a SageMaker Geospatial client instance
geospatial_client = session.client(service_name="sagemaker-geospatial")
# Creates a resusable Paginator for the list_raster_data_collections API operation
paginator = geospatial_client.get_paginator("list_raster_data_collections")
# Create a PageIterator from the paginator class
page_iterator = paginator.paginate()
# Use the iterator to iterate throught the results of list_raster_data_collections
results = []
for page in page_iterator:
results.append(page['RasterDataCollectionSummaries'])
print(results)
Este es un ejemplo de respuesta en JSON de la operación de la API list_raster_data_collections
. Está truncado para incluir solo la recopilación de datos (Sentinel-2) que se usa en este ejemplo de código. Para obtener más información sobre una recopilación de datos ráster específica, utilice get_raster_data_collection
:
{
"Arn": "arn:aws:sagemaker-geospatial:us-west-2:378778860802:raster-data-collection/public/nmqj48dcu3g7ayw8",
"Description": "Sentinel-2a and Sentinel-2b imagery, processed to Level 2A (Surface Reflectance) and converted to Cloud-Optimized GeoTIFFs",
"DescriptionPageUrl": "https://registry.opendata.aws/sentinel-2-l2a-cogs",
"Name": "Sentinel 2 L2A COGs",
"SupportedFilters": [
{
"Maximum": 100,
"Minimum": 0,
"Name": "EoCloudCover",
"Type": "number"
},
{
"Maximum": 90,
"Minimum": 0,
"Name": "ViewOffNadir",
"Type": "number"
},
{
"Name": "Platform",
"Type": "string"
}
],
"Tags": {},
"Type": "PUBLIC"
}
Tras ejecutar el ejemplo de código anterior, obtendrá el ARN de la recopilación de datos ráster de Sentinel-2, arn:aws:sagemaker-geospatial:us-west-2:378778860802:raster-data-collection/public/nmqj48dcu3g7ayw8
. En la siguiente sección, puede consultar la recopilación de datos de Sentinel-2 mediante la API search_raster_data_collection
.
Buscando el Sentinel-2 recopilación de datos ráster mediante search_raster_data_collection
En la sección anterior, list_raster_data_collections
solía obtener el ARN del Sentinel-2 recopilación de datos. Ahora puede usar ese ARN para buscar en la recopilación de datos en un área de interés (AOI) determinada, un rango de tiempo, propiedades y las bandas UV disponibles.
Para llamar a la search_raster_data_collection
API, debe pasar un Python Diccionario del RasterDataCollectionQuery
parámetro. En este ejemplo se utilizan AreaOfInterest
, TimeRangeFilter
, PropertyFilters
y BandFilter
. Para mayor facilidad, puede especificar el diccionario de Python utilizando la variable search_rdc_query
para contener los parámetros de la consulta de búsqueda:
search_rdc_query = {
"AreaOfInterest": {
"AreaOfInterestGeometry": {
"PolygonGeometry": {
"Coordinates": [
[
# coordinates are input as longitute followed by latitude
[-114.529, 36.142]
,
[-114.373, 36.142]
,
[-114.373, 36.411]
,
[-114.529, 36.411]
,
[-114.529, 36.142]
,
]
]
}
}
},
"TimeRangeFilter": {
"StartTime": "2022-01-01T00:00:00Z"
,
"EndTime": "2022-07-10T23:59:59Z"
},
"PropertyFilters": {
"Properties": [
{
"Property": {
"EoCloudCover": {
"LowerBound": 0,
"UpperBound": 1
}
}
}
],
"LogicalOperator": "AND"
},
"BandFilter": [
"visual"
]
}
En este ejemplo, consulta un AreaOfInterest
que incluye el lago Meadvisual
.
Tras crear los parámetros de la consulta, puede utilizar la API search_raster_data_collection
para realizar la solicitud.
El siguiente ejemplo de código implementa una solicitud de la API search_raster_data_collection
. Esta API no admite la paginación mediante la API get_paginator
. Para asegurarse de que se ha recopilado la respuesta completa de la API, el ejemplo de código utiliza un bucle while
para comprobar si NextToken
existe. A continuación, el ejemplo de código .extend()
se utiliza para añadir la imagen de satélite URLs y otros metadatos de respuesta alitems_list
.
Para obtener más información al respectosearch_raster_data_collection
, consulte SearchRasterDataCollectionla referencia de la API de Amazon SageMaker AI.
search_rdc_response = sm_geo_client.search_raster_data_collection(
Arn='arn:aws:sagemaker-geospatial:us-west-2:378778860802:raster-data-collection/public/nmqj48dcu3g7ayw8',
RasterDataCollectionQuery=search_rdc_query
)
## items_list is the response from the API request.
items_list = []
## Use the python .get() method to check that the 'NextToken' exists, if null returns None breaking the while loop
while search_rdc_response.get('NextToken'):
items_list.extend(search_rdc_response['Items'])
search_rdc_response = sm_geo_client.search_raster_data_collection(
Arn='arn:aws:sagemaker-geospatial:us-west-2:378778860802:raster-data-collection/public/nmqj48dcu3g7ayw8',
RasterDataCollectionQuery=search_rdc_query, NextToken=search_rdc_response['NextToken']
)
## Print the number of observation return based on the query
print (len(items_list))
El siguiente ejemplo es una respuesta JSON de su consulta. Se ha truncado para mayor claridad. En el par clave-valor Assets
, solo se devuelve el "BandFilter": ["visual"]
especificado en la solicitud:
{
'Assets': {
'visual': {
'Href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/15/T/UH/2022/6/S2A_15TUH_20220623_0_L2A/TCI.tif'
}
},
'DateTime': datetime.datetime(2022, 6, 23, 17, 22, 5, 926000, tzinfo = tzlocal()),
'Geometry': {
'Coordinates': [
[
[-114.529, 36.142]
,
[-114.373, 36.142]
,
[-114.373, 36.411]
,
[-114.529, 36.411]
,
[-114.529, 36.142]
,
]
],
'Type': 'Polygon'
},
'Id': 'S2A_15TUH_20220623_0_L2A',
'Properties': {
'EoCloudCover': 0.046519,
'Platform': 'sentinel-2a'
}
}
Ahora que tiene los resultados de la consulta, en la siguiente sección puede visualizarlos utilizando matplotlib
. Esto sirve para comprobar que los resultados provengan de la región geográfica correcta.
Visualización de su search_raster_data_collection
con matplotlib
Antes de empezar el trabajo de observación de la Tierra (EOJ), puede visualizar el resultado de nuestra consulta con matplotlib
. El siguiente ejemplo de código toma el primer elemento, items_list[0]["Assets"]["visual"]["Href"]
, de la variable items_list
creada en el ejemplo de código anterior e imprime una imagen con matplotlib
.
# Visualize an example image.
import os
from urllib import request
import tifffile
import matplotlib.pyplot as plt
image_dir = "./images/lake_mead"
os.makedirs(image_dir, exist_ok=True)
image_dir = "./images/lake_mead"
os.makedirs(image_dir, exist_ok=True)
image_url = items_list[0]["Assets"]["visual"]["Href"]
img_id = image_url.split("/")[-2]
path_to_image = image_dir + "/" + img_id + "_TCI.tif"
response = request.urlretrieve(image_url, path_to_image)
print("Downloaded image: " + img_id)
tci = tifffile.imread(path_to_image)
plt.figure(figsize=(6, 6))
plt.imshow(tci)
plt.show()
Tras comprobar que los resultados se encuentran en la región geográfica correcta, puede iniciar el trabajo de observación de la Tierra (EOJ) en el siguiente paso. El EOJ se utiliza para identificar los cuerpos de agua a partir de las imágenes de satélite mediante un proceso denominado segmentación del terreno.
Inicio de un trabajo de observación de la Tierra (EOJ) que consiste en segmentar el terreno a partir de una serie de imágenes de satélite
SageMaker geospatial proporciona varios modelos previamente entrenados que puede usar para procesar datos geoespaciales de colecciones de datos ráster. Para obtener más información sobre los modelos previamente entrenados y las operaciones personalizadas disponibles, consulte Tipos de operaciones.
Para calcular el cambio en la superficie del agua, es necesario identificar qué píxeles de las imágenes corresponden al agua. La segmentación de la cobertura terrestre es un modelo de segmentación semántica compatible con la API start_earth_observation_job
. Los modelos de segmentación semántica asocian una etiqueta a cada píxel de cada imagen. En los resultados, a cada píxel se le asigna una etiqueta que se basa en el mapa de clases del modelo. Este es el mapa de clases del modelo de segmentación de terrenos:
{
0: "No_data",
1: "Saturated_or_defective",
2: "Dark_area_pixels",
3: "Cloud_shadows",
4: "Vegetation",
5: "Not_vegetated",
6: "Water",
7: "Unclassified",
8: "Cloud_medium_probability",
9: "Cloud_high_probability",
10: "Thin_cirrus",
11: "Snow_ice"
}
Para iniciar un trabajo de observación de la Tierra, utilice la API start_earth_observation_job
. Cuando envíe su solicitud, debe especificar lo siguiente:
-
InputConfig
(diccionario): se utiliza para especificar las coordenadas del área en la que desea buscar y otros metadatos asociados a la búsqueda. -
JobConfig
(diccionario): se usa para especificar el tipo de operación de EOJ que se realizó con los datos. En este ejemplo se utilizaLandCoverSegmentationConfig
. -
ExecutionRoleArn
(string): el ARN del rol de ejecución de SageMaker IA con los permisos necesarios para ejecutar el trabajo. -
Name
(cadena): un nombre para el trabajo de observación de la Tierra.
El InputConfig
es un Python diccionario. Utilice la siguiente variable eoj_input_config
para almacenar los parámetros de la consulta de búsqueda. Utilice esta variable cuando realice la solicitud a la API start_earth_observation_job
. w.
# Perform land cover segmentation on images returned from the Sentinel-2 dataset.
eoj_input_config = {
"RasterDataCollectionQuery": {
"RasterDataCollectionArn": "arn:aws:sagemaker-geospatial:us-west-2:378778860802:raster-data-collection/public/nmqj48dcu3g7ayw8",
"AreaOfInterest": {
"AreaOfInterestGeometry": {
"PolygonGeometry": {
"Coordinates":[
[
[-114.529, 36.142]
,
[-114.373, 36.142]
,
[-114.373, 36.411]
,
[-114.529, 36.411]
,
[-114.529, 36.142]
,
]
]
}
}
},
"TimeRangeFilter": {
"StartTime": "2021-01-01T00:00:00Z"
,
"EndTime": "2022-07-10T23:59:59Z"
,
},
"PropertyFilters": {
"Properties": [{"Property": {"EoCloudCover": {"LowerBound": 0, "UpperBound": 1}}}],
"LogicalOperator": "AND",
},
}
}
El JobConfig
es un Python diccionario que se utiliza para especificar la operación EOJ que desea que se realice en sus datos:
eoj_config = {"LandCoverSegmentationConfig": {}}
Con los elementos del diccionario ahora especificados, puede enviar su solicitud a la API start_earth_observation_job
mediante el siguiente ejemplo de código:
# Gets the execution role arn associated with current notebook instance
execution_role_arn = sagemaker.get_execution_role()
# Starts an earth observation job
response = sm_geo_client.start_earth_observation_job(
Name="lake-mead-landcover"
,
InputConfig=eoj_input_config,
JobConfig=eoj_config,
ExecutionRoleArn=execution_role_arn,
)
print(response)
Al iniciar un trabajo de observación de la Tierra, se devuelve un ARN junto con otros metadatos.
Para obtener una lista de todos los trabajos de observación de la Tierra en curso y actuales, utilice la API list_earth_observation_jobs
. Para supervisar el estado de un único trabajo de observación de la Tierra, use la API get_earth_observation_job
. Para realizar esta solicitud, use el ARN creado después de enviar su solicitud de EOJ. Para obtener más información, consulta GetEarthObservationJobla referencia de la API de Amazon SageMaker AI.
Para encontrar lo que ARNs está asociado a su operación, EOJs utilice la list_earth_observation_jobs
API. Para obtener más información, consulta ListEarthObservationJobsla referencia de la API de Amazon SageMaker AI.
# List all jobs in the account
sg_client.list_earth_observation_jobs()["EarthObservationJobSummaries"]
A continuación, se muestra un ejemplo de respuesta JSON:
{
'Arn': 'arn:aws:sagemaker-geospatial:us-west-2:111122223333:earth-observation-job/futg3vuq935t',
'CreationTime': datetime.datetime(2023, 10, 19, 4, 33, 54, 21481, tzinfo = tzlocal()),
'DurationInSeconds': 3493,
'Name': 'lake-mead-landcover'
,
'OperationType': 'LAND_COVER_SEGMENTATION',
'Status': 'COMPLETED',
'Tags': {}
}, {
'Arn': 'arn:aws:sagemaker-geospatial:us-west-2:111122223333:earth-observation-job/wu8j9x42zw3d',
'CreationTime': datetime.datetime(2023, 10, 20, 0, 3, 27, 270920, tzinfo = tzlocal()),
'DurationInSeconds': 1,
'Name': 'mt-shasta-landcover'
,
'OperationType': 'LAND_COVER_SEGMENTATION',
'Status': 'INITIALIZING',
'Tags': {}
}
Cuando el estado de su puesto de EOJ cambie aCOMPLETED
, pase a la siguiente sección para calcular el cambio en Lake Mead's área de superficie.
Calcular el cambio en el lago Mead área de superficie
Para calcular el cambio en la superficie del lago Mead, exporte primero los resultados del EOJ a Amazon S3 mediante export_earth_observation_job
:
sagemaker_session = sagemaker.Session()
s3_bucket_name = sagemaker_session.default_bucket() # Replace with your own bucket if needed
s3_bucket = session.resource("s3").Bucket(s3_bucket_name)
prefix = "export-lake-mead-eoj"
# Replace with the S3 prefix desired
export_bucket_and_key = f"s3://{s3_bucket_name}/{prefix}/"
eoj_output_config = {"S3Data": {"S3Uri": export_bucket_and_key}}
export_response = sm_geo_client.export_earth_observation_job(
Arn="arn:aws:sagemaker-geospatial:us-west-2:111122223333:earth-observation-job/7xgwzijebynp
",
ExecutionRoleArn=execution_role_arn,
OutputConfig=eoj_output_config,
ExportSourceImages=False,
)
Para ver el estado de su trabajo de exportación, utilice get_earth_observation_job
:
export_job_details = sm_geo_client.get_earth_observation_job(Arn=export_response["Arn"])
Para calcular los cambios en el nivel del agua del lago Mead, descarga las máscaras de cobertura terrestre en el SageMaker cuaderno local y descarga las imágenes originales de nuestra consulta anterior. En el mapa de clases del modelo de segmentación del suelo, el índice de clases del agua es 6.
Para extraer la máscara de agua de un Sentinel-2 imagen, sigue estos pasos. Primero, cuente el número de píxeles marcados como agua (índice de clase 6) en la imagen. En segundo lugar, multiplique el recuento por el área que cubre cada píxel. Las bandas pueden diferir en su resolución espacial. Para el modelo de segmentación de la cobertura terrestre, todas las bandas se muestrean hacia abajo hasta una resolución espacial igual a 60 metros.
import os
from glob import glob
import cv2
import numpy as np
import tifffile
import matplotlib.pyplot as plt
from urllib.parse import urlparse
from botocore import UNSIGNED
from botocore.config import Config
# Download land cover masks
mask_dir = "./masks/lake_mead"
os.makedirs(mask_dir, exist_ok=True)
image_paths = []
for s3_object in s3_bucket.objects.filter(Prefix=prefix).all():
path, filename = os.path.split(s3_object.key)
if "output" in path:
mask_name = mask_dir + "/" + filename
s3_bucket.download_file(s3_object.key, mask_name)
print("Downloaded mask: " + mask_name)
# Download source images for visualization
for tci_url in tci_urls:
url_parts = urlparse(tci_url)
img_id = url_parts.path.split("/")[-2]
tci_download_path = image_dir + "/" + img_id + "_TCI.tif"
cogs_bucket = session.resource(
"s3", config=Config(signature_version=UNSIGNED, region_name="us-west-2")
).Bucket(url_parts.hostname.split(".")[0])
cogs_bucket.download_file(url_parts.path[1:], tci_download_path)
print("Downloaded image: " + img_id)
print("Downloads complete.")
image_files = glob("images/lake_mead/*.tif")
mask_files = glob("masks/lake_mead/*.tif")
image_files.sort(key=lambda x: x.split("SQA_")[1])
mask_files.sort(key=lambda x: x.split("SQA_")[1])
overlay_dir = "./masks/lake_mead_overlay"
os.makedirs(overlay_dir, exist_ok=True)
lake_areas = []
mask_dates = []
for image_file, mask_file in zip(image_files, mask_files):
image_id = image_file.split("/")[-1].split("_TCI")[0]
mask_id = mask_file.split("/")[-1].split(".tif")[0]
mask_date = mask_id.split("_")[2]
mask_dates.append(mask_date)
assert image_id == mask_id
image = tifffile.imread(image_file)
image_ds = cv2.resize(image, (1830, 1830), interpolation=cv2.INTER_LINEAR)
mask = tifffile.imread(mask_file)
water_mask = np.isin(mask, [6]).astype(np.uint8) # water has a class index 6
lake_mask = water_mask[1000:, :1100]
lake_area = lake_mask.sum() * 60 * 60 / (1000 * 1000) # calculate the surface area
lake_areas.append(lake_area)
contour, _ = cv2.findContours(water_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
combined = cv2.drawContours(image_ds, contour, -1, (255, 0, 0), 4)
lake_crop = combined[1000:, :1100]
cv2.putText(lake_crop, f"{mask_date}", (10,50), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 0, 0), 3, cv2.LINE_AA)
cv2.putText(lake_crop, f"{lake_area} [sq km]", (10,100), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 0, 0), 3, cv2.LINE_AA)
overlay_file = overlay_dir + '/' + mask_date + '.png'
cv2.imwrite(overlay_file, cv2.cvtColor(lake_crop, cv2.COLOR_RGB2BGR))
# Plot water surface area vs. time.
plt.figure(figsize=(20,10))
plt.title('Lake Mead surface area for the 2021.02 - 2022.07 period.', fontsize=20)
plt.xticks(rotation=45)
plt.ylabel('Water surface area [sq km]', fontsize=14)
plt.plot(mask_dates, lake_areas, marker='o')
plt.grid('on')
plt.ylim(240, 320)
for i, v in enumerate(lake_areas):
plt.text(i, v+2, "%d" %v, ha='center')
plt.show()
Con matplotlib
, puede visualizar los resultados con un gráfico. El gráfico muestra que el área de superficie del lago Mead disminuyó entre enero de 2021 y julio de 2022.
![Un gráfico de barras que muestra que la superficie del lago Mead disminuyó entre enero de 2021 y julio de 2022.](images/lake-mead-decrease.png)