Accesso alla raccolta dei dati raster di Sentinel-2 e creazione di un processo di osservazione della terra per eseguire la segmentazione del suolo - Amazon SageMaker AI

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Accesso alla raccolta dei dati raster di Sentinel-2 e creazione di un processo di osservazione della terra per eseguire la segmentazione del suolo

Questo tutorial basato su Python utilizza l'SDK per Python (Boto3) e un notebook Amazon Studio Classic. SageMaker Per completare correttamente questa demo, assicurati di disporre delle autorizzazioni AWS Identity and Access Management (IAM) necessarie per utilizzare geospatial e Studio Classic. SageMaker SageMaker geospatial richiede la presenza di un utente, gruppo o ruolo che possa accedere a Studio Classic. È inoltre necessario disporre di un ruolo di esecuzione dell' SageMaker IA che specifichi il responsabile del servizio SageMaker geospaziale nella sua politica di fiducia. sagemaker-geospatial.amazonaws.com

Per ulteriori informazioni su questi requisiti, consulta SageMaker i ruoli IAM geospaziali.

Questo tutorial mostra come utilizzare l'API SageMaker geospaziale per completare le seguenti attività:

  • Trovare le raccolte dei dati raster disponibili con list_raster_data_collections.

  • Cercare una raccolta dei dati raster specificata utilizzando search_raster_data_collection.

  • Creare un processo di osservazione della terra (EOJ) utilizzando start_earth_observation_job.

Utilizzare list_raster_data_collections per trovare le raccolte dei dati disponibili

SageMaker geospatial supporta più raccolte di dati raster. Per ulteriori informazioni sulle raccolte dei dati disponibili, consulta Raccolte dati.

Questa demo utilizza dati satellitari raccolti da Sentinel-2 Satelliti GeoTIFF ottimizzati per il cloud. Questi satelliti forniscono una copertura globale della superficie terrestre ogni cinque giorni. Oltre a raccogliere immagini della superficie terrestre, i satelliti Sentinel-2 raccolgono anche dati su diverse bande spettrali.

Per cercare un'area di interesse (AOI), hai bisogno dell'ARN associato ai dati satellitari Sentinel-2. Per trovare le raccolte di dati disponibili e quelle associate ARNs nel tuo Regione AWS, utilizza l'operazione API. list_raster_data_collections

Poiché la risposta può essere impaginata, devi utilizzare l'operazione get_paginator affinché restituisca tutti i dati pertinenti:

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)

Questo è un esempio di risposta JSON dall'operazione API list_raster_data_collections. Viene troncato per includere solo la raccolta di dati (Sentinel-2) utilizzato in questo esempio di codice. Per ulteriori dettagli su una specifica raccolta dei dati raster, usa 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" }

Dopo aver eseguito l'esempio di codice precedente, otterrai l'ARN della raccolta dei dati raster Sentinel-2, arn:aws:sagemaker-geospatial:us-west-2:378778860802:raster-data-collection/public/nmqj48dcu3g7ayw8. Nella sezione successiva, puoi eseguire query sulla raccolta dei dati Sentinel-2 utilizzando l'API search_raster_data_collection.

Sto cercando il Sentinel-2 raccolta di dati raster utilizzando search_raster_data_collection

Nella sezione precedente, si otteneva list_raster_data_collections l'ARN per il Sentinel-2 raccolta dati. Ora puoi usare quell'ARN per cercare la raccolta dei dati su una determinata area di interesse (AOI), intervallo temporale, proprietà e bande UV disponibili.

Per chiamare l'search_raster_data_collectionAPI devi inserire un Python dictionary al RasterDataCollectionQuery parametro. Questo esempio utilizza AreaOfInterest, TimeRangeFilter, PropertyFilters e BandFilter. Per semplicità, puoi specificare il dizionario Python usando la variabile search_rdc_query per contenere i parametri di query della ricerca:

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

In questo esempio, esegui una query su un oggetto AreaOfInterest che include Lago Mead nello Utah. Inoltre, Sentinel-2 supporta diversi tipi di bande di immagini. Per misurare la variazione della superficie dell'acqua, è sufficiente la banda visual.

Dopo aver creato i parametri di query, puoi utilizzare l'API search_raster_data_collection per effettuare la richiesta.

Il seguente esempio di codice implementa una richiesta API search_raster_data_collection. Questa API non supporta l'impaginazione tramite l'API get_paginator. Per assicurarsi che sia stata restituita la risposta API completa, l'esempio di codice utilizza un ciclo while per verificarne l'NextTokenesistenza. L'esempio di codice viene quindi utilizzato .extend() per aggiungere l'immagine satellitare URLs e altri metadati di risposta a. items_list

Per ulteriori informazionisearch_raster_data_collection, consulta SearchRasterDataCollectionAmazon SageMaker AI API Reference.

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

Di seguito è riportato un esempio di risposta JSON alla tua query. La risposta è stata troncata per maggiore chiarezza. Nella coppia chiave-valore Assets viene restituito solo il "BandFilter": ["visual"] specificato nella richiesta:

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

Ora che hai i risultati della tua query, puoi visualizzarli nella sezione successiva utilizzando matplotlib. Questo serve a verificare che i risultati provengano dalla regione geografica corretta.

Visualizzazione di search_raster_data_collection utilizzando matplotlib

Prima di iniziare il processo di osservazione della terra (EOJ), puoi visualizzare un risultato della query conmatplotlib. Il seguente esempio di codice prende il primo elemento, items_list[0]["Assets"]["visual"]["Href"], dalla variabile items_list creata nell'esempio di codice precedente e stampa un'immagine utilizzando 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()

Dopo aver verificato che i risultati siano nella regione geografica corretta, puoi avviare il processo di osservazione della terra (EOJ) nella fase successiva. Si utilizza il processo EOJ per identificare i corpi idrici dalle immagini satellitari utilizzando un processo chiamato segmentazione del suolo.

Avvio di un processo di osservazione della terra (EOJ) che esegue la segmentazione del suolo su una serie di immagini satellitari

SageMaker geospatial fornisce diversi modelli pre-addestrati che puoi utilizzare per elaborare dati geospaziali da raccolte di dati raster. Per ulteriori informazioni sui modelli preaddestrati disponibili e sulle operazioni personalizzate, consulta Tipi di operazioni.

Per calcolare la variazione della superficie dell'acqua, devi identificare quali pixel delle immagini corrispondono all'acqua. La segmentazione della copertura del suolo è un modello di segmentazione semantica supportato dall'API start_earth_observation_job. I modelli di segmentazione semantica associano un'etichetta a ogni pixel di ogni immagine. Nei risultati, a ogni pixel viene assegnata un'etichetta basata sulla mappatura delle classi del modello. Di seguito è riportata la mappatura delle classi per il modello di segmentazione del suolo:

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

Per avviare un processo di osservazione della terra, usa l'API start_earth_observation_job. Quando invii la richiesta, devi specificare quanto segue:

  • InputConfig(dict): utilizzato per specificare le coordinate dell'area in cui desideri cercare e altri metadati associati alla tua ricerca.

  • JobConfig(dict): utilizzato per specificare il tipo di operazione EOJ eseguita sui dati. Questo esempio usa LandCoverSegmentationConfig.

  • ExecutionRoleArn(stringa) — L'ARN del ruolo di esecuzione SageMaker AI con le autorizzazioni necessarie per eseguire il processo.

  • Name(string): un nome per il processo di osservazione della terra.

Il InputConfig è un Python dizionario. Utilizza la seguente variabile eoj_input_config per contenere i parametri di query della ricerca. Usa questa variabile quando effettui la richiesta API start_earth_observation_job.

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

Il JobConfig è un Python dizionario utilizzato per specificare l'operazione EOJ da eseguire sui dati:

eoj_config = {"LandCoverSegmentationConfig": {}}

Con gli elementi del dizionario ora specificati, puoi inviare la tua richiesta API start_earth_observation_job utilizzando il seguente esempio di codice:

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

L'avvio di un processo di osservazione della terra restituisce un ARN insieme ad altri metadati.

Per ottenere un elenco di tutti i processi di osservazione della terra in corso e correnti, utilizza l'API list_earth_observation_jobs. Per monitorare lo stato di un singolo processo di osservazione della Terra, utilizza l'API get_earth_observation_job. Per effettuare questa richiesta, utilizza l'ARN creato dopo aver inviato la richiesta EOJ. Per ulteriori informazioni, GetEarthObservationJobconsulta Amazon SageMaker AI API Reference.

Per trovare le informazioni ARNs associate alla tua, EOJs utilizza l'operazione list_earth_observation_jobs API. Per ulteriori informazioni, ListEarthObservationJobsconsulta Amazon SageMaker AI API Reference.

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

Di seguito è riportato un esempio di risposta 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': {} }

Dopo che lo stato del tuo job EOJ diventaCOMPLETED, passa alla sezione successiva per calcolare la modifica in Lake Mead's superficie.

Calcolo della variazione del lago Mead superficie

Per calcolare la variazione della superficie del lago Mead, esporta innanzitutto i risultati del processo EOJ su Amazon S3 utilizzando 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, )

Per visualizzare lo stato del tuo processo di esportazione, utilizza get_earth_observation_job:

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

Per calcolare le variazioni del livello dell'acqua del Lago Mead, scarica le maschere di copertura del terreno sull'istanza SageMaker notebook locale e scarica le immagini di origine della nostra query precedente. Nella mappatura delle classi per il modello di segmentazione del suolo, l'indice di classe dell'acqua è 6.

Per estrarre la maschera d'acqua da un Sentinel-2 immagine, segui questi passaggi. Innanzitutto, conta nell'immagine il numero di pixel contrassegnati come acqua (indice di classe 6). In secondo luogo, moltiplica il conteggio per l'area coperta da ciascun pixel. Le bande possono differire in termini di risoluzione spaziale. Per il modello di segmentazione della copertura del suolo, tutte le bande vengono sottocampionate con una risoluzione spaziale pari a 60 metri.

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

Utilizzando matplotlib, puoi visualizzare i risultati su un grafico. Il grafico mostra che la superficie del lago Mead è diminuito da gennaio 2021 a luglio 2022.

Un istogramma che mostra che la superficie del lago Mead è diminuita da gennaio 2021 a luglio 2022