Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.
Accédez à la collection de données matricielles Sentinel-2 et créez une tâche d'observation de la Terre pour effectuer la segmentation des terres
Ce didacticiel basé sur Python utilise le pour SDK Python (Boto3) et un bloc-notes Amazon SageMaker Studio Classic. Pour mener à bien cette démonstration, assurez-vous que vous disposez des autorisations requises AWS Identity and Access Management (IAM) pour utiliser SageMaker Geospatial et Studio Classic. SageMaker geospatial nécessite que vous disposiez d'un utilisateur, d'un groupe ou d'un rôle pouvant accéder à Studio Classic. Vous devez également avoir un rôle SageMaker d'exécution qui spécifie le principal du service SageMaker géospatial, sagemaker-geospatial.amazonaws.com
dans sa politique de confiance.
Pour en savoir plus sur ces exigences, consultez la section IAMRôles SageMaker géospatiaux.
Ce didacticiel explique comment utiliser la SageMaker géospatiale API pour effectuer les tâches suivantes :
-
Trouvez les collections de données raster disponibles avec
list_raster_data_collections
. -
Recherchez une collection de données raster spécifiée à l'aide de
search_raster_data_collection
. -
Créez une tâche d'observation de la Terre (EOJ) en utilisant
start_earth_observation_job
.
Utilisation list_raster_data_collections
pour trouver les collections de données disponibles
SageMaker geospatial prend en charge plusieurs collections de données matricielles. Pour en savoir plus sur les collections de données disponibles, voirCollections de données.
Cette démo utilise des données satellites collectées à partir de Sentinel-2 Satellites géographiques optimisés pour le cloud. TIFF
Pour effectuer une recherche dans une zone d'intérêt (AOI), vous avez besoin de la ARN zone associée aux données du satellite Sentinel-2. Pour rechercher les collections de données disponibles et les données associées ARNs dans votre Région AWS répertoire, utilisez l'list_raster_data_collections
APIopération.
Comme la réponse peut être paginée, vous devez utiliser l'get_paginator
opération pour renvoyer toutes les données pertinentes :
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)
Il s'agit d'un exemple de JSON réponse de l'list_raster_data_collections
APIopération. Il est tronqué pour inclure uniquement la collecte de données (Sentinel-2) qui est utilisé dans cet exemple de code. Pour plus de détails sur une collecte de données raster spécifique, utilisez 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" }
Après avoir exécuté l'exemple de code précédent, vous obtenez le résultat ARN de la collecte de données raster Sentinel-2,. arn:aws:sagemaker-geospatial:us-west-2:378778860802:raster-data-collection/public/nmqj48dcu3g7ayw8
Dans la section suivante, vous pouvez interroger la collecte de données Sentinel-2 à l'aide du. search_raster_data_collection
API
En recherchant le Sentinel-2 collecte de données matricielles à l'aide search_raster_data_collection
Dans la section précédente, vous avez utilisé list_raster_data_collections
ARN pour obtenir le Sentinel-2 collecte de données. Vous pouvez désormais l'utiliser ARN pour effectuer des recherches dans la collecte de données sur une zone d'intérêt (AOI), une plage de temps, des propriétés et les bandes UV disponibles.
Pour appeler le, search_raster_data_collection
API vous devez transmettre un Python dictionnaire du RasterDataCollectionQuery
paramètre. Cet exemple utilise AreaOfInterest
TimeRangeFilter
,PropertyFilters
, etBandFilter
. Pour plus de facilité, vous pouvez spécifier le dictionnaire Python à l'aide de la variable search_rdc_query
pour contenir les paramètres de la requête de recherche :
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"
] }
Dans cet exemple, vous recherchez une annonce AreaOfInterest
qui inclut Lake Meadvisual
bracelet.
Après avoir créé les paramètres de requête, vous pouvez utiliser le search_raster_data_collection
API pour effectuer la demande.
L'exemple de code suivant implémente une search_raster_data_collection
API demande. Cela API ne prend pas en charge la pagination à l'aide du get_paginator
API. Pour s'assurer que la API réponse complète a été collectée, l'exemple de code utilise une while
boucle pour vérifier qu'NextToken
elle existe. L'exemple de code est ensuite utilisé .extend()
pour ajouter l'image satellite URLs et les autres métadonnées de réponse auitems_list
.
Pour en savoir plus à ce sujetsearch_raster_data_collection
, consultez SearchRasterDataCollectionle Amazon SageMaker 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))
Ce qui suit est une JSON réponse à votre requête. Il a été tronqué pour des raisons de clarté. Seul le paramètre "BandFilter": ["visual"]
spécifié dans la demande est renvoyé dans la paire Assets
clé-valeur :
{ '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' } }
Maintenant que vous avez obtenu les résultats de votre requête, dans la section suivante, vous pouvez visualiser les résultats en utilisantmatplotlib
. Cela permet de vérifier que les résultats proviennent de la bonne région géographique.
Visualisation de votre utilisation search_raster_data_collection
matplotlib
Avant de commencer le travail d'observation de la Terre (EOJ), vous pouvez visualiser le résultat de notre requête avec matplotlib
. L'exemple de code suivant prend le premier élément de la items_list
variable créée dans l'exemple de code précédent et imprime une image à l'aide dematplotlib
. items_list[0]["Assets"]["visual"]["Href"]
# 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()
Après avoir vérifié que les résultats se situent dans la bonne région géographique, vous pouvez démarrer le Earth Observation Job (EOJ) à l'étape suivante. Vous utilisez le EOJ pour identifier les plans d'eau à partir des images satellites à l'aide d'un processus appelé segmentation des terres.
Démarrage d'une tâche d'observation de la Terre (EOJ) qui effectue une segmentation du sol sur une série d'images satellites
SageMaker geospatial fournit plusieurs modèles préentraînés que vous pouvez utiliser pour traiter les données géospatiales issues de collections de données matricielles. Pour en savoir plus sur les modèles préentraînés et les opérations personnalisées disponibles, consultezTypes d'opérations.
Pour calculer la variation de la surface de l'eau, vous devez identifier les pixels des images qui correspondent à l'eau. La segmentation de la couverture terrestre est un modèle de segmentation sémantique soutenu par le start_earth_observation_job
API. Les modèles de segmentation sémantique associent une étiquette à chaque pixel de chaque image. Dans les résultats, chaque pixel se voit attribuer une étiquette basée sur la carte de classes du modèle. Voici la carte des classes pour le modèle de segmentation des terres :
{ 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" }
Pour démarrer une tâche d'observation de la Terre, utilisez le start_earth_observation_job
API. Lorsque vous soumettez votre demande, vous devez spécifier les éléments suivants :
-
InputConfig
(dict) — Utilisé pour spécifier les coordonnées de la zone que vous souhaitez rechercher, ainsi que les autres métadonnées associées à votre recherche. -
JobConfig
(dict) — Utilisé pour spécifier le type d'EOJopération que vous avez effectuée sur les données. Cet exemple utiliseLandCoverSegmentationConfig
. -
ExecutionRoleArn
(string) — Le ARN rôle SageMaker d'exécution disposant des autorisations nécessaires pour exécuter la tâche. -
Name
(chaîne) : nom de la tâche d'observation de la Terre.
InputConfig
Il s'agit d'un Python dictionnaire. Utilisez la variable suivante eoj_input_config
pour contenir les paramètres de la requête de recherche. Utilisez cette variable lorsque vous faites la start_earth_observation_job
API demande. 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", }, } }
JobConfig
Il s'agit d'un Python dictionnaire utilisé pour spécifier l'EOJopération que vous souhaitez effectuer sur vos données :
eoj_config = {"LandCoverSegmentationConfig": {}}
Les éléments du dictionnaire étant désormais spécifiés, vous pouvez soumettre votre start_earth_observation_job
API demande à l'aide de l'exemple de code suivant :
# 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)
Le démarrage d'une tâche d'observation de la Terre renvoie un ARN ainsi que d'autres métadonnées.
Pour obtenir une liste de tous les emplois actuels et en cours dans le domaine de l'observation de la Terre, utilisez le list_earth_observation_jobs
API. Pour surveiller l'état d'une seule tâche d'observation de la Terre, utilisez le get_earth_observation_job
API. Pour effectuer cette demande, utilisez le fichier ARN créé après avoir soumis votre EOJ demande. Pour en savoir plus, consultez GetEarthObservationJoble Amazon SageMaker API Reference.
Pour trouver ce qui vous est ARNs associé, EOJs utilisez l'list_earth_observation_jobs
APIopération. Pour en savoir plus, consultez ListEarthObservationJobsle Amazon SageMaker API Reference.
# List all jobs in the account sg_client.list_earth_observation_jobs()["EarthObservationJobSummaries"]
Voici un exemple de JSON réponse :
{ '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': {} }
Une fois que le statut de votre EOJ travail est COMPLETED
passé à, passez à la section suivante pour calculer le changement dans Lake Mead's surface.
Calcul du changement dans le lac Mead superficie
Pour calculer l'évolution de la superficie du lac Mead, exportez d'abord les résultats EOJ vers Amazon S3 en utilisant 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, )
Pour connaître le statut de votre tâche d'exportation, utilisez get_earth_observation_job
:
export_job_details = sm_geo_client.get_earth_observation_job(Arn=export_response["Arn"])
Pour calculer les variations du niveau d'eau du lac Mead, téléchargez les masques de couverture terrestre sur l'instance de SageMaker bloc-notes locale et téléchargez les images sources de notre requête précédente. Dans la carte des classes du modèle de segmentation des terres, l'indice de classe de l'eau est 6.
Pour extraire le masque à eau d'un Sentinel-2 image, suivez ces étapes. Commencez par compter le nombre de pixels marqués comme de l'eau (indice de classe 6) dans l'image. Ensuite, multipliez le nombre par la zone couverte par chaque pixel. Les bandes peuvent avoir une résolution spatiale différente. Pour le modèle de segmentation de la couverture terrestre, toutes les bandes sont sous-échantillonnées à une résolution spatiale égale à 60 mètres.
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()
En utilisantmatplotlib
, vous pouvez visualiser les résultats sous forme de graphique. Le graphique montre que la superficie du lac Mead a diminué de janvier 2021 à juillet 2022.