Acesse a coleta de dados raster do Sentinel-2 e crie um trabalho de observação da terra para realizar a segmentação da terra - Amazon SageMaker

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Acesse a coleta de dados raster do Sentinel-2 e crie um trabalho de observação da terra para realizar a segmentação da terra

Este tutorial baseado em Python usa o for SDK Python (Boto3) e um notebook Amazon Studio Classic. SageMaker Para concluir esta demonstração com sucesso, verifique se você tem as permissões AWS Identity and Access Management (IAM) necessárias para usar SageMaker geospatial e o Studio Classic. SageMaker geospatial exige que você tenha um usuário, grupo ou função que possa acessar o Studio Classic. Você também deve ter uma função de SageMaker execução que especifique o principal do serviço SageMaker geoespacial, sagemaker-geospatial.amazonaws.com em sua política de confiança.

Para saber mais sobre esses requisitos, consulte IAMFunções SageMaker geoespaciais.

Este tutorial mostra como usar a SageMaker geoespacial API para concluir as seguintes tarefas:

  • Encontre as coleções de dados raster disponíveis com list_raster_data_collections.

  • Pesquise uma coleção de dados raster especificada usando search_raster_data_collection.

  • Crie um trabalho de observação da Terra (EOJ) usandostart_earth_observation_job.

Usando list_raster_data_collections para encontrar coleções de dados disponíveis

SageMaker geospatial suporta várias coleções de dados raster. Para saber mais sobre as coleções de dados disponíveis, consulte Coleções de dados.

Esta demonstração usa dados de satélite coletados de Sentinel-2 Satélites TIFF geográficos otimizados para nuvem. Esses satélites fornecem cobertura global da superfície terrestre da terra a cada cinco dias. Além de coletar imagens da superfície da terra, os satélites Sentinel-2 também coletam dados em uma variedade de bandas espectrais.

Para pesquisar uma área de interesse (AOI), você precisa do ARN que está associado aos dados do satélite Sentinel-2. Para encontrar as coleções de dados disponíveis e suas associadas ARNs à sua Região da AWS, use a list_raster_data_collections API operação.

Como a resposta pode ser paginada, você deve usar a operação get_paginator para retornar todos os dados 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)

Esse é um exemplo de JSON resposta da list_raster_data_collections API operação. É truncado para incluir somente a coleta de dados (Sentinel-2) que é usado neste exemplo de código. Para obter mais detalhes sobre uma coleta de dados raster específica, use 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" }

Depois de executar a amostra de código anterior, você obtém a coleção ARN de dados raster do Sentinel-2,. arn:aws:sagemaker-geospatial:us-west-2:378778860802:raster-data-collection/public/nmqj48dcu3g7ayw8 Na próxima seção, você pode consultar a coleta de dados do Sentinel-2 usando o. search_raster_data_collection API

Pesquisando o Sentinel-2 coleta de dados raster usando search_raster_data_collection

Na seção anterior, você list_raster_data_collections costumava obter o ARN para Sentinel-2 coleta de dados. Agora você pode usar isso ARN para pesquisar a coleta de dados em uma determinada área de interesse (AOI), intervalo de tempo, propriedades e as bandas UV disponíveis.

Para ligar para o search_raster_data_collectionAPI, você deve passar por um Python dicionário para o RasterDataCollectionQuery parâmetro. Este exemplo usa AreaOfInterest, TimeRangeFilter, PropertyFilters e BandFilter. Para facilitar, você pode especificar o dicionário Python usando a variável search_rdc_query para armazenar os parâmetros de consulta de pesquisa:

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

Neste exemplo, você consulta um AreaOfInterest que inclui Lake Mead, em Utah. Além disso, o Sentinel-2 suporta vários tipos de bandas de imagem. Para medir a mudança na superfície da água, você só precisa da faixa visual.

Depois de criar os parâmetros de consulta, você pode usar o search_raster_data_collection API para fazer a solicitação.

O exemplo de código a seguir implementa uma search_raster_data_collection API solicitação. Isso API não suporta paginação usando o. get_paginator API Para garantir que a API resposta completa tenha sido coletada, a amostra de código usa um while loop para verificar se NextToken ela existe. Em seguida, a amostra de código é usada .extend() para anexar a imagem de satélite URLs e outros metadados de resposta ao. items_list

Para saber mais sobre osearch_raster_data_collection, consulte SearchRasterDataCollectionna SageMaker APIReferência da Amazon.

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

A seguir está uma JSON resposta à sua consulta. Foi truncado para maior clareza. Somente o "BandFilter": ["visual"] especificado na solicitação é retornado no par de valores-chave Assets:

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

Agora que você tem os resultados da consulta, na próxima seção, você pode visualizar os resultados usando o matplotlib. Isso serve para verificar se os resultados são da região geográfica correta.

Visualizando seu search_raster_data_collection usando matplotlib

Antes de iniciar o trabalho de observação da Terra (EOJ), você pode visualizar um resultado de nossa consulta com matplotlib. A amostra de código a seguir pega o primeiro item, items_list[0]["Assets"]["visual"]["Href"], da variável items_list criada na amostra de código anterior e imprime uma imagem usando 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()

Depois de verificar se os resultados estão na região geográfica correta, você pode iniciar o Earth Observation Job (EOJ) na próxima etapa. Você usa o EOJ para identificar os corpos d'água a partir das imagens de satélite usando um processo chamado segmentação de terras.

Iniciando um trabalho de observação da Terra (EOJ) que realiza a segmentação da terra em uma série de imagens de satélite

SageMaker geospatial fornece vários modelos pré-treinados que você pode usar para processar dados geoespaciais de coleções de dados raster. Para saber mais sobre os modelos pré-treinados disponíveis e as operações personalizadas, consulte Tipos de operações.

Para calcular a mudança na área da superfície da água, você precisa identificar quais pixels nas imagens correspondem à água. A segmentação da cobertura da terra é um modelo de segmentação semântica suportado pelo. start_earth_observation_job API Os modelos de segmentação de semântica associam um rótulo a cada pixel em cada imagem. Nos resultados, cada pixel recebe um rótulo baseado no mapa de classes do modelo. A seguir está o mapa de classes para o modelo de segmentação de terras:

{ 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 um trabalho de observação da Terra, use start_earth_observation_job API o. Ao enviar sua solicitação, você deve especificar o seguinte:

  • InputConfig (dict) – Usado para especificar as coordenadas da área que você deseja pesquisar e outros metadados associados à sua pesquisa.

  • JobConfig(dict) — Usado para especificar o tipo de EOJ operação que você executou nos dados. Este exemplo usa LandCoverSegmentationConfig.

  • ExecutionRoleArn(string) — A ARN da função de SageMaker execução com as permissões necessárias para executar o trabalho.

  • Name (string) – Um nome para o trabalho de observação da terra.

O InputConfig é um Python dicionário. Use a variável eoj_input_config a seguir para manter os parâmetros de consulta de pesquisa. Use essa variável ao fazer a start_earth_observation_job API solicitação. 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", }, } }

O JobConfig é um Python dicionário usado para especificar a EOJ operação que você deseja realizar em seus dados:

eoj_config = {"LandCoverSegmentationConfig": {}}

Com os elementos do dicionário agora especificados, você pode enviar sua start_earth_observation_job API solicitação usando o seguinte exemplo 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)

O início de um trabalho de observação da Terra retorna um ARN junto com outros metadados.

Para obter uma lista de todos os trabalhos de observação da Terra em andamento e atuais, use list_earth_observation_jobs API o. Para monitorar o status de um único trabalho de observação da Terra, use get_earth_observation_job API o. Para fazer essa solicitação, use o ARN criado após enviar sua EOJ solicitação. Para saber mais, consulte GetEarthObservationJobna SageMaker APIReferência da Amazon.

Para encontrar o ARNs associado ao seu, EOJs use a list_earth_observation_jobs API operação. Para saber mais, consulte ListEarthObservationJobsna SageMaker APIReferência da Amazon.

# List all jobs in the account sg_client.list_earth_observation_jobs()["EarthObservationJobSummaries"]

Veja a seguir um exemplo de JSON resposta:

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

Depois que o status de seu EOJ trabalho mudar paraCOMPLETED, vá para a próxima seção para calcular a mudança em Lake Mead's área de superfície.

Calculando a mudança no lago Mead área de superfície

Para calcular a mudança na área de superfície do Lago Mead, primeiro exporte os resultados do EOJ para o Amazon S3 usando: 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 o status da exportação, use get_earth_observation_job:

export_job_details = sm_geo_client.get_earth_observation_job(Arn=export_response["Arn"])

Para calcular as mudanças no nível da água do Lago Mead, baixe as máscaras de cobertura da terra para a instância local do SageMaker notebook e baixe as imagens de origem da nossa consulta anterior. No mapa de classes do modelo de segmentação de terras, o índice de classes da água é 6.

Para extrair a máscara de água de um Sentinel-2 imagem, siga estas etapas. Primeiro, conte o número de pixels marcados como água (índice de classe 6) na imagem. Segundo, multiplique a contagem pela área que cada pixel cobre. As bandas podem diferir em sua resolução espacial. Para o modelo de segmentação da cobertura do solo, todas as faixas são obtidas como amostra para uma resolução 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()

Usando matplotlib, você pode visualizar os resultados com um gráfico. O gráfico mostra que a área da superfície do lago Mead diminuiu de janeiro de 2021 a julho de 2022.

Um gráfico de barras mostrando a área da superfície do Lago Mead diminuiu de janeiro de 2021 a julho de 2022