Självstudie: Använda API:er för Microsoft Planetary Computer Pro för att mata in och visualisera data

STAC-samlingar (SpatioTemporal Asset Catalog) används i en GeoCatalog för att indexera och lagra relaterade spatiotemporal-tillgångar. I den här kompletta handledningen skapar du en ny STAC-samling, inför Sentinel-2-bilder i samlingen och hämtar dessa bilder via GeoCatalogs API:er.

I den här handledningen kommer du att:

  • Skapar din egen STAC-samling i en Planetary Computer Pro GeoCatalog
  • Mata in satellitbilder i samlingen från Europeiska rymdorganisationen
  • Konfigurera samlingen så att bilderna i samlingen kan visualiseras i Planetary Computer Pro:s webbgränssnitt
  • Fråga efter data från STAC-samlingen med Planetary Computer Pros STAC API

Den här handledningen visar och förklarar funktioner genom kodfragment. För en interaktiv upplevelse i stil med en anteckningsbok, ladda ned den här handledningen som en Jupyter-anteckningsbok.

Tip

Den här handledningen visar metoden för REST API:t. Du kan också använda Planetary Computer Pro Python SDK (pip install azure-planetarycomputer) för en förenklad klientupplevelse. Se de enskilda snabbstartsguiderna för SDK-exempel:

Förutsättningar

Innan du kör den här handledningen behöver du en Planetary Computer Pro GeoCatalog som är distribuerad i din Azure-prenumeration. Du behöver också en miljö för att köra den här notebook-filen och installera nödvändiga paket. Vi föreslår att du kör den här självstudien via en Azure Machine Learning Virtual Machine eller Visual Studio Code's notebookintegrering i en virtuell Pythonmiljö. Den här anteckningsboken bör dock köras varhelst du kan köra Jupyter-anteckningsböcker, förutsatt att följande krav uppfylls:

  • Python 3.10 eller senare
  • Azure CLI är installerat och du har kört az login för att logga in på ditt Azure-konto
  • Nödvändiga krav som anges i avsnittet Självstudiealternativ är installerade

Öppna en Jupyter-anteckningsbok i Azure Machine Learning eller VS Code

Logga in på Azure med Azure CLI

Följande kommando loggar in dig i Azure med hjälp av Azure CLI. Kör kommandot och följ anvisningarna för att logga in.

!az login

Välj självstudiealternativ

Innan du kör den här självstudiehandledningen behöver du åtkomst med behörighet som deltagare till en befintlig GeoCatalog-instans. Ange URL:en för din GeoCatalog-instans i variabeln geocatalog_url. I den här självstudien skapar du en samling för Sentinel-2-bilder från Europeiska rymdorganisationen (ESA) som för närvarande lagras i Microsofts Planetary Computer Data Catalog.

# URL for your given GeoCatalog
geocatalog_url = (
    "<GEOCATALOG_URL>"
)
geocatalog_url = geocatalog_url.rstrip("/")  # Remove trailing slash if present

api_version = "2026-04-15"

# User selections for demo

# Collection within the Planetary Computer
pc_collection = "sentinel-2-l2a"

# Bounding box for AOI
bbox_aoi = [-22.455626, 63.834083, -22.395201, 63.880750]

# Date range to search for imagery
param_date_range = "2024-02-04/2024-02-11"

# Maximum number of items to ingest
param_max_items = 6

Importera de paket som krävs

Innan du kan skapa en STAC-samling måste du importera några Python-paket och definiera hjälpfunktioner för att hämta den nödvändiga åtkomsttoken.

pip install pystac-client azure-identity requests pillow
# Import the required packages
import json
import random
import string
import time
from datetime import datetime, timedelta, timezone
from io import BytesIO
from typing import Any, Optional, Dict

import requests
from azure.identity import AzureCliCredential
from IPython.display import Markdown as md
from IPython.display import clear_output
from PIL import Image
from pystac_client import Client

# Function to get a bearer token for the  Planetary Computer Pro API
MPC_APP_ID = "https://geocatalog.spatio.azure.com"

_access_token = None
def getBearerToken():
    global _access_token
    if not _access_token or datetime.fromtimestamp(_access_token.expires_on) < datetime.now() + timedelta(minutes=5):
        credential = AzureCliCredential()
        _access_token = credential.get_token(f"{MPC_APP_ID}/.default")

    return {"Authorization": f"Bearer {_access_token.token}"}

# Method to print error messages when checking response status
def raise_for_status(r: requests.Response) -> None:
    try:
        r.raise_for_status()
    except requests.exceptions.HTTPError as e:
        try:
            print(json.dumps(r.json(), indent=2))
        except:
            print(r.content)
        finally:
            raise

Skapa en STAC-samling

Definiera en STAC-samlings-JSON

Därefter definierar du en STAC-samling som ett JSON-objekt. I den här handledningen använder du den befintliga STAC-samlings-JSON för samlingen Sentinel-2-l2a i Microsofts Planetary Computer. Din samling tilldelas ett slumpmässigt ID och en rubrik så att den inte står i konflikt med andra befintliga samlingar.

# Load example STAC collection JSON

response = requests.get(
    f"https://planetarycomputer.microsoft.com/api/stac/v1/collections/{pc_collection}"
)
raise_for_status(response)
stac_collection = response.json()

collection_id = pc_collection + "-tutorial-" + str(random.randint(0, 1000))

# Generate a unique name for the test collection
stac_collection["id"] = collection_id
stac_collection["title"] = collection_id

# Determine the storage account and container for the assets
pc_storage_account = stac_collection.pop("msft:storage_account")
pc_storage_container = stac_collection.pop("msft:container")
pc_collection_asset_container = (
    f"https://{pc_storage_account}.blob.core.windows.net/{pc_storage_container}"
)

# View your STAC collection JSON
stac_collection

När du skapar en samling i GeoCatalog kan en samlings-JSON inte ha några tillgångar på samlingsnivå (till exempel en samlingsminiatyr) som är associerade med samlingen, så ta först bort de befintliga tillgångarna (oroa dig inte att du lägger till miniatyrbilden senare).

# Save the thumbnail url
thumbnail_url = stac_collection['assets']['thumbnail']['href']

# Remove the assets field from the JSON (you'll see how to add this back later)
print("Removed the following items from the STAC Collection JSON:")
stac_collection.pop('assets')
# Create a STAC collection by posting to the STAC collections API

collections_endpoint = f"{geocatalog_url}/stac/collections"

response = requests.post(
    collections_endpoint,
    json=stac_collection,
    headers=getBearerToken(),
    params={"api-version": api_version}
)

if response.status_code==201:
    print("STAC Collection created named:",stac_collection['title'])
else:
    raise_for_status(response)

Öppna geoCatalog-webbgränssnittet så bör du se din nya samling under fliken Samlingar.

Komma åt samlingsminiatyr

Nu vill du lägga till en miniatyrbild i vår samling som ska visas tillsammans med vår samling. I den här demonstrationen använder du miniatyrbilden från den befintliga Sentinel-2-samlingen i Microsofts Planetary Computer.

# Read thumbnail for your collection

thumbnail_response = requests.get(thumbnail_url)
raise_for_status(thumbnail_response)
img = Image.open(BytesIO(thumbnail_response.content))
img

Lägg till miniatyrbild i din Planetary Computer Pro GeoCatalog

När du har läst miniatyrbilden kan du lägga till den i vår samling genom att publicera den på din GeoCatalogs API-slutpunkt för samlingens tillgångar tillsammans med den nödvändiga tillgången i JSON-format.

# Define the GeoCatalog collections API endpoint
collection_assets_endpoint = f"{geocatalog_url}/stac/collections/{collection_id}/assets"

# Read the example thumbnail from this collection from the Planetary Computer
thumbnail = {"file": ("lulc.png", thumbnail_response.content)}

# Define the STAC collection asset type - thumbnail in this case
asset = {
    "data": '{"key": "thumbnail", "href":"", "type": "image/png", '
    '"roles":  ["test_asset"], "title": "test_asset"}'
}

# Post the thumbnail to the GeoCatalog collections asset endpoint
response = requests.post(
    collection_assets_endpoint,
    data=asset,
    files=thumbnail,
    headers=getBearerToken(),
    params={"api-version": api_version}
)

if response.status_code==201:
    print("STAC Collection thumbnail updated for:",stac_collection['title'])
else:
    raise_for_status(response)

Läs ny samling från din Planetary Computer Pro GeoCatalog

Uppdatera webbläsaren så bör du kunna se miniatyrbilden. Du kan också hämta kollektionens JSON programmatiskt genom att göra följande anrop till kollektions-API-slutpunkten:

# Request the collection JSON from your GeoCatalog
collection_endpoint = f"{geocatalog_url}/stac/collections/{stac_collection['id']}"

response = requests.get(
    collection_endpoint,
    json={'collection_id':stac_collection['id']},
    headers=getBearerToken(),
    params={"api-version": api_version}
)

if response.status_code==200:
    print("STAC Collection successfully read:",stac_collection['title'])
else:
    raise_for_status(response)

response.json()
print(f"""
You successfully created a new STAC Collection in GeoCatalog named {collection_id}.
You can view your collection by visiting the GeoCatalog Explorer: {geocatalog_url}/collections
""")

Mata in STAC-objekt och tillgångar

När du har skapat den här samlingen är du redo att mata in nya STAC-objekt i din STAC-samling med hjälp av GeoCatalogs Objekt-API! Utför den här processen genom att:

  1. Hämta en SAS-token från Microsofts Planetary Computer
  2. Registrera den token som en inmatningskälla i GeoCatalog
  3. Publicera STAC-objekt från samlingen till GeoCatalogs objekt-API
  4. Kontrollera att objekten har matats in framgångsrikt
ingestion_sources_endpoint = f"{geocatalog_url}/inma/ingestion-sources"
ingestion_source_endpoint = lambda id: f"{geocatalog_url}/inma/ingestion-sources/{id}"


def find_ingestion_source(container_url: str) -> Optional[Dict[str, Any]]:

    response = requests.get(
        ingestion_sources_endpoint,
        headers=getBearerToken(),
        params={"api-version": api_version},
    )

    for source in response.json()["value"]:
        ingestion_source_id = source["id"]

        response = requests.get(
            ingestion_source_endpoint(ingestion_source_id),
            headers=getBearerToken(),
            params={"api-version": api_version},
        )
        raise_for_status(response)

        response = response.json()

        if response["connectionInfo"]["containerUrl"] == container_url:
            return response


def create_ingestion_source(container_url: str, sas_token: str):
    response = requests.post(
        ingestion_sources_endpoint,
        json={
            "kind": "SasToken",
            "connectionInfo": {
                "containerUrl": container_url,
                "sasToken": sas_token,
            },
        },
        headers=getBearerToken(),
        params={"api-version": api_version},
    )
    raise_for_status(response)


def remove_ingestion_source(ingestion_source_id: str):
    response = requests.delete(
        ingestion_source_endpoint(ingestion_source_id),
        headers=getBearerToken(),
        params={"api-version": api_version},
    )
    raise_for_status(response)

Ställa en fråga till den planetariska datorn

Först måste du fråga Planetary Computer för att söka efter Sentinel-2-bilder som matchar våra specifika krav. I det här fallet letar du efter Sentinel-2-bilder i planetdatorn som matchar följande kriterier:

  • Samling – Bilder från samlingen Sentinel-2-l2a
  • Tidsintervall – insamlat mellan 4 februari och 11 februari 2024
  • Intresseområde – Bilder som samlats in över södra Island (definieras som en avgränsningsruta)

Genom att utföra den här sökningen kan du se att matchande STAC-objekt hittas i planetdatorn.

# Search criteria
print("Using the below parameters to search the Planetary Computer:\n")
print("Collection:", pc_collection)
print("Bounding box for area of interest:",bbox_aoi)
print("Date range:",param_date_range)
print("Max number of items:",param_max_items)
# Query the Planetary Computer

# Connect to the Planetary Computer
catalog = Client.open("https://planetarycomputer.microsoft.com/api/stac/v1")

search = catalog.search(collections=[pc_collection], bbox=bbox_aoi, datetime=param_date_range)
total_items = search.item_collection()

items = total_items[:param_max_items]
print("Total number of matching items:",len(total_items))
print("Total number of items for ingest base on user selected parameter:",len(items))

if total_items==0:
    print("No items matched your user specified parameters used at the top of this demo. Update these parameters")
# Print an example STAC item returned by the Planetary Computer
items[0]

Registrera en inmatningskälla

Innan du kan mata in dessa STAC-objekt och deras relaterade tillgångar (bilder) i en GeoCatalog-samling måste du avgöra om du behöver registrera en ny inmatningskälla. Inmatningskällor används av GeoCatalog för att spåra vilka lagringsplatser (Azure Blob Storage-containrar) som den har åtkomst till.

Registrering av en inmatningskälla utförs genom att ge GeoCatalog platsen för lagringscontainern och en SAS-token med läsbehörighet för att få åtkomst till containern. Om STAC-objekt eller deras relaterade tillgångar finns i en lagringscontainer och din GeoCatalog inte har fått åtkomst till den, kommer inmatningen att misslyckas.

För att starta den här processen begär du först en SAS-token från planetdatorn som ger oss läsåtkomst till containern där Sentinel-2-avbildningarna finns.

# Request API token from the Planetary Computer

pc_token = requests.get("https://planetarycomputer.microsoft.com/api/sas/v1/token/{}".format(pc_collection)).json()
print(f"Planetary Computer API Token will expire {pc_token['msft:expiry']}")

Försök sedan att registrera den här Azure Blob Storage-containern och tillhörande SAS-token som en inmatningskälla med GeoCatalog. Det är möjligt att det redan finns en källa för dataimport för den här lagringscontainern. I så fall hittar du ID:t för den befintliga inmatningskällan.

Varning

Om en duplicerad inmatningskälla hittas med en token som upphör att gälla under de närmaste 15 minuterna tas den bort och ersätts. Om du tar bort en inmatningskälla som för närvarande används av pågående inmatningar kan dessa inmatningar störas.

existing_ingestion_source: Optional[Dict[str, Any]] = find_ingestion_source(pc_collection_asset_container)

if existing_ingestion_source:
    connection_info = existing_ingestion_source["connectionInfo"]
    expiration = datetime.fromisoformat(connection_info["expiration"].split('.')[0]) # works in all Python 3.X versions
    expiration = expiration.replace(tzinfo=timezone.utc) # set timezone to UTC
    if expiration < datetime.now(tz=timezone.utc) + timedelta(minutes=15):
        print(f"Recreating existing ingestion source for {pc_collection_asset_container}")
        remove_ingestion_source(existing_ingestion_source["id"])
        create_ingestion_source(pc_collection_asset_container, pc_token["token"])
    else:
        print(f"Using existing ingestion source for {pc_collection_asset_container} with expiration {expiration}")
else:
    print(f"Creating ingestion source for {pc_collection_asset_container}")
    create_ingestion_source(pc_collection_asset_container, pc_token["token"])

Mata in STAC-objekt med geoCatalogs objekt-API

Nu när du har registrerat en inmatningskälla eller verifierat att det finns en källa matar du in STAC-objekten som du hittade i planetdatorn med geoCatalogs objekt-API. Gör detta genom att publicera varje objekt till objekt-API:et som skapar en ny inmatningsåtgärd i GeoCatalog.

# Ingest items

items_endpoint = f"{geocatalog_url}/stac/collections/{collection_id}/items"

operation_ids = []

for item in items:

    item_json = item.to_dict()
    item_json['collection'] = collection_id

    # Remove non-static assets
    del(item_json['assets']['rendered_preview'])
    del(item_json['assets']['preview'])
    del(item_json['assets']['tilejson'])

    response = requests.post(
        items_endpoint,
        json=item_json,
        headers=getBearerToken(),
        params={"api-version": api_version}
    )

    operation_ids.append(response.json()['id'])
    print(f"Ingesting item {item_json['id']} with operation id {response.json()['id']}")

Eftersom Inmatning av Sentinel-2-objekt kan ta lite tid kan du köra den här koden för att kontrollera statusen för dina inmatningsåtgärder med hjälp av GeoCatalogs operations-API.

# Check the status of the operations
operations_endpoint = f"{geocatalog_url}/inma/operations"
# Loop through all the operations ids until the status of each operation ids is "Finished"
pending=True

start = time.time()

while pending:
    # Count the number of operation ids that are finished vs unfinished
    num_running = 0
    num_finished = 0
    num_failed = 0
    clear_output(wait=True)
    for operation_id in operation_ids:
        response = requests.get(
            f"{operations_endpoint}/{operation_id}",
            headers=getBearerToken(),
            params={"api-version": api_version},
        )
        raise_for_status(response)
        status = response.json()["status"]
        print(f"Operation id {operation_id} status: {status}")
        if status == "Running":
            num_running+=1
        elif status == "Failed":
            num_failed+=1
        elif status == "Succeeded":
            num_finished+=1
    
    num_running
    stop=time.time()
    # Print the summary of num finished, num running and num failed
    
    print("Ingesting Imagery:")
    print(f"\tFinished: {num_finished}\n\tRunning: {num_running}\n\tFailed: {num_failed}")
    print("Time Elapsed (seconds):",str(stop-start))
    
    if num_running == 0:
        pending=False
        print(f"Ingestion Complete!\n\t{num_finished} items ingested.\n\t{num_failed} items failed.")

    else:
        print(f"Waiting for {num_running} operations to finish")
        time.sleep(5)

Du bör kunna uppdatera webbläsaren och klicka på fliken Objekt för att se de nyligen uppladdade objekten.

Samlingshantering

Nu när du har matat in dessa STAC-objekt och deras associerade tillgångar (bilder) i STAC-samlingen måste du ange din GeoCatalog med några andra konfigurationsfiler innan du kan visualisera dessa objekt i GeoCatalog-webbgränssnittet.

Samlingsåtergivningskonfiguration

Ladda först ned en renderingskonfigurationsfil för den här samlingen från Planetary Computer. Den här konfigurationsfilen kan läsas av GeoCatalog för att återge bilder på olika sätt i Utforskaren. Detta beror på att STAC-objekt kan innehålla många olika tillgångar (bilder) som kan kombineras för att skapa helt nya bilder av ett visst område som markerar synliga eller icke-synliga funktioner. Till exempel har Sentinel-2 STAC-objekt över 12 olika bilder från olika delar av det elektromagnetiska spektrumet. Den här återgivningskonfigurationen instruerar GeoCatalog om hur du kombinerar dessa bilder så att de kan visa bilder i naturlig färg eller falsk färg (färg IR).

# Read render JSON from Planetary Computer

render_json = requests.get("https://planetarycomputer.microsoft.com/api/data/v1/mosaic/info?collection={}".format(pc_collection)).json()
render_json['renderOptions']

När du har läst den här konfigurationen för återgivningsalternativ från planetdatorn kan du aktivera dessa återgivningsalternativ för samlingen genom att publicera den här konfigurationen till slutpunkten för återgivningsalternativ.

# Post render options config to GeoCatalog render-options API

render_config_endpoint = f"{geocatalog_url}/stac/collections/{collection_id}/configurations/render-options"

for render_option in render_json['renderOptions']:

    # Rename render configs such that they can be stored by GeoCatalog
    render_option['id'] = render_option['name'].translate(str.maketrans('', '', string.punctuation)).lower().replace(" ","-")[:30]

    # Post render definition
    response = requests.post(
        render_config_endpoint,
        json=render_option,
        headers=getBearerToken(),
        params={"api-version": api_version}
    )

Mosaikdefinitioner

På samma sätt som renderningskonfigurationen som beskrivs ovan kan vi i GeoCatalogs Utforskare ange en eller flera mosaikdefinitioner för samlingen. Med dessa mosaikdefinitioner kan vi instruera GeoCatalogs Utforskare om hur du filtrerar vilka objekt som visas i Utforskaren. En grundläggande återgivningskonfiguration (visas i nästa cell) instruerar till exempel GeoCatalog att visa den senaste bilden för ett visst område. Med mer avancerade renderingskonfigurationer kan vi återge olika vyer, till exempel den minst molniga avbildningen för en viss plats som togs i oktober 2023.

# Post mosaic definition

mosiacs_config_endpoint = f"{geocatalog_url}/stac/collections/{collection_id}/configurations/mosaics"

response = requests.post(
    mosiacs_config_endpoint,
    json={"id": "mos1",
          "name": "Most recent available",
          "description": "Most recent available imagery in this collection",
          "cql": []
    },
    headers=getBearerToken(),
    params={"api-version": api_version}
)

Öppna GeoCatalog-webbgränssnittet

Grattis! Du har skapat en samling, lagt till STAC-objekt och tillgångar och uppdaterat samlingen så att den innehåller de nödvändiga konfigurationsfilerna så att den kan visas via Utforskaren i Webbgränssnittet geoCatalog.

Gå tillbaka till GeoCatalog Explorer i webbgränssnittet för att visa din samling!

Frågeinsamling via STAC API

Nu när du har visat din samling i GeoCatalog Explorer går du igenom hur du använder GeoCatalogs STAC-API:er för att söka efter och hämta STAC-objekt och tillgångar för ytterligare analys.

Den här processen börjar med att publicera en sökning till din GeoCatalogs STAC API. Mer specifikt söker du efter bilder i din samling som ligger inom den ursprungliga avgränsningsrutan som du använde för att extrahera bilder från Planetary Computer.

Föga förvånande returnerar den här frågan alla STAC-objekt som du tidigare placerade i samlingen.

stac_search_endpoint = f"{geocatalog_url}/stac/search"

response = requests.post(
    stac_search_endpoint,
    json={"collections":[collection_id],
          "bbox":bbox_aoi
    },
    headers=getBearerToken(),
    params={"api-version": api_version, "sign": "true"}
)

matching_items = response.json()['features']
print(len(matching_items))

I din tidigare fråga angav du även en annan parameter: sign:true. Detta instruerar GeoCatalog att returnera en signerad href (objekt href + SAS-token) som gör att du kan läsa de angivna tillgångarna från Azure Blob Storage.

# Download one of the assets bands, band 09
asset_href = matching_items[0]['assets']['B09']['href']
print(asset_href)

response = requests.get(asset_href)
img = Image.open(BytesIO(response.content))
img

Rensa resurser

Ta bort objekt

Nu har du skapat en GeoCatalog-samling, lagt till objekt och tillgångar i samlingen och hämtat dessa objekt och tillgångar med geoCatalogs STAC API. I den sista fasen av den här självstudien ska du ta bort de här objekten och ta bort samlingen.

# Delete all items

for item in matching_items:
    response = requests.delete(
        f"{items_endpoint}/{item['id']}",
        headers=getBearerToken(),
        params={"api-version": api_version}
    )

Du kan bekräfta att alla objekt har tagits bort genom att köra nästa kommando. Observera att det kan ta en minut eller två att helt ta bort objekt och deras associerade tillgångar.

# Confirm that all the items have been deleted
response = requests.post(
    stac_search_endpoint,
    json={"collections":[stac_collection['id']],
          "bbox": bbox_aoi
    },
    headers=getBearerToken(),
    params={"api-version": api_version, "sign": "true"}
)

matching_items = response.json()['features']
print(len(matching_items))

Ta bort samling

Nu som ett sista steg kanske du vill ta bort samlingen helt från din GeoCatalog-instans.

# Delete the collection
response = requests.delete(
    f"{collections_endpoint}/{collection_id}",
    headers=getBearerToken(),
    params={"api-version": api_version}
)

raise_for_status(response)
print(f"STAC Collection deleted: {collection_id}")

Nästa steg

I denna heltäckande handledning gick du igenom processen att skapa en ny STAC-samling, importera Sentinel-2-bilder till samlingen och utföra frågor på dessa bilder via GeoCatalogs API:er. Om du vill veta mer om vart och ett av dessa ämnen kan du utforska dessa andra material: