Partilhar via


Criar um item STAC (SpatioTemporal Asset Catalog)

Saiba como criar um item STAC (SpatioTemporal Asset Catalog) para um ativo de dados geoespaciais raster. Cada ativo de dados geoespaciais carregado em um Microsoft Planetary Computer Pro GeoCatalog deve ter um Item compatível com STAC associado.

Neste guia, você:

  • Instale as bibliotecas Python necessárias usando PIP.
  • Exiba e inspecione dados GOES-18 usando o código Python fornecido.
  • Extraia metadados do nome do arquivo usando expressões regulares.
  • Crie STAC itens a partir de arquivos GeoTIFF Cloud-Optimized usando o rio-stac.
  • Aprimore o item STAC com metadados extraídos do nome do arquivo.
  • Adicione o item STAC a uma coleção STAC pai.
  • Valide e salve o catálogo, a coleção e os itens do STAC.
  • Adicione os itens STAC ao Microsoft Planetary Computer Pro.

Este tutorial mostra e explica os recursos por meio de trechos de código, para uma experiência interativa no estilo de notebook, baixe este tutorial como um bloco de anotações Jupyter.

Pré-requisitos

Para concluir este arranque rápido, necessita de:

Principais características do STAC

O SpatioTemporal Asset Catalog (STAC) é um padrão aberto para estruturação e compartilhamento de dados geoespaciais. Ele fornece uma linguagem e um formato comuns para descrever ativos geoespaciais, facilitando a descoberta, o acesso e o uso desses recursos em diferentes plataformas e aplicativos. As principais características da norma STAC são as seguintes:

  • Interoperabilidade: O esquema padronizado baseado em JSON garante fácil integração e compreensão entre ferramentas e sistemas.
  • Extensibilidade: Campos principais flexíveis com extensões personalizadas para necessidades específicas.
  • Descoberta: a estrutura consistente melhora a pesquisa e a descoberta de ativos geoespaciais.
  • Acessibilidade: links diretos para ativos de dados facilitam a recuperação e a integração perfeitas.
  • Automação: Permite processamento e análise automatizados com metadados padronizados.

Benefícios do STAC para padronização de metadados

  • Consistência entre tipos de dados: estrutura unificada para diversos tipos de dados geoespaciais.
  • Colaboração aprimorada: simplifica o compartilhamento e a colaboração com um formato comum de metadados.
  • Integração de dados aprimorada: facilita a integração de conjuntos de dados de várias fontes.
  • Gerenciamento de dados simplificado: ferramentas automatizadas reduzem o esforço manual na manutenção de metadados.
  • Preparação para o futuro: A natureza extensível adapta-se a novos tipos de dados e tecnologias.

O Microsoft Planetary Computer Pro (MC Pro) usa STAC como seu principal padrão de indexação para fornecer interoperabilidade entre conjuntos de dados. Este tutorial mostra aos usuários como criar itens STAC do zero usando bibliotecas comuns de código aberto.

A especificação de item STAC detalha como os itens STAC são construídos e os metadados mínimos necessários que devem ser preenchidos. O STAC é um padrão flexível, permitindo que os usuários decidam quais dados desejam incluir como parte dos metadados. Os metadados que podem ser usados para preencher um item STAC podem ser incluídos no ativo de dados, em um arquivo sidecar (.XML, . JSON, .TXT etc.), ou mesmo em locais como o nome do arquivo. Os usuários devem considerar os tipos de metadados que os usuários podem querer pesquisar e classificar no futuro ao decidir quais metadados incluir.

Este tutorial usa exemplos de imagens do Cloud Optimized GeoTIFF (COG) do conjunto de dados de Temperatura da Superfície da Terra (LST) dos satélites Satélite Ambiental Operacional Geoestacionário R (GOES-R) da Agência Nacional Oceânica e Atmosférica (NOAA). Esses dados estão incluídos no Planetary Computer aberto como arquivos COG, mas não possuem metadados STAC. Os satélites GOES produzem muitos produtos de dados. Mais detalhes podem ser encontrados no Guia do Usuário e Definição de Produto da SérieGOES-R.

O processo usado neste tutorial pode ser generalizado para qualquer tipo de dados em que os campos de metadados principais são enumerados usando várias bibliotecas de código aberto.

Instalar bibliotecas Python

Para começar, instalamos as bibliotecas Python necessárias usando PIP:

  • rasterio: Este pacote é usado para ler e escrever dados raster geoespaciais. Ele fornece ferramentas para trabalhar com formatos de dados raster, como GeoTIFF.

  • pystac: Este pacote é usado para trabalhar com o padrão STAC. Ele fornece ferramentas para criar, ler e manipular metadados STAC.

  • rio-stac: Este pacote integra rasterio com pystac para criar STAC Items dos dados raster. Ele simplifica o processo de geração de metadados STAC para conjuntos de dados raster.

  • matplotlib: Esta biblioteca é usada para criar visualizações e gráficos. No contexto de dados geoespaciais, ele ajuda a renderizar e exibir imagens rasterizadas, permitindo que os usuários inspecionem visualmente os dados antes de criar metadados STAC.

  • azure-storage-blob: Esta biblioteca de cliente do Armazenamento do Azure fornece acesso aos serviços de Armazenamento de Blob do Azure. Ele permite a interação direta com dados geoespaciais armazenados na nuvem, permitindo que os usuários leiam e trabalhem com arquivos armazenados em contêineres de Blob do Azure sem baixá-los primeiro.

!pip install rasterio pystac rio_stac matplotlib azure-storage-blob 

A próxima seção do código exibe alguns dados do GOES-18 do Computador Planetário aberto. Selecionamos o conjunto de dados GOES-R Advanced Baseline Imager Level 2 Land Surface Temperature - CONUS e um arquivo arbitrário do dia 208 de 2023.

# Import Necessary Libraries 
import requests
from azure.storage.blob import ContainerClient
import matplotlib.pyplot as plt
from rasterio.io import MemoryFile
import os
from urllib.parse import urlparse

# Function to get the SAS token
def get_sas_token(endpoint):
    response = requests.get(endpoint)
    if response.status_code == 200:
        data = response.json()
        return data.get("token")
    else:
        raise Exception(f"Failed to get SAS token: {response.status_code} - {response.text}")

# Define Azure Blob Storage parameters
storage_account_name = "goeseuwest"
container_name = "noaa-goes-cogs"
blob_domain = f"https://{storage_account_name}.blob.core.windows.net"
sas_endpoint = f"https://planetarycomputer.microsoft.com/api/sas/v1/token/{storage_account_name}/{container_name}/"


# Get the SAS token
sas_token = get_sas_token(sas_endpoint)

# Construct the container URL with the SAS token
container_url = f"{blob_domain}/{container_name}?{sas_token}"

# Create a ContainerClient
container_client = ContainerClient.from_container_url(container_url)

# Define data you want, this can be changed for other datasets that are in storage in the open Planetary Computer
satellite = "goes-18"      # The specific GOES satellite (GOES-18, also known as GOES-West)
product = "ABI-L2-LSTC"    # The data product type (Advanced Baseline Imager Level 2 Land Surface Temperature - CONUS)
year = "2023"              # The year the data was collected
day_of_year = "208"        # The day of year (DOY) - day 208 corresponds to July 27, 2023

# Construct the directory path
directory_path = f"{satellite}/{product}/{year}/{day_of_year}/"

# Get just the first blob by using next() and limiting the iterator

first_blob = next(container_client.list_blobs(name_starts_with=directory_path))

# Function to read and display a .tif file from a URL
def display_tif_from_url(url, title):
    response = requests.get(url, stream=True)
    if response.status_code == 200:
        with MemoryFile(response.content) as memfile:
            with memfile.open() as dataset:
                plt.figure(figsize=(10, 10))
                plt.imshow(dataset.read(1), cmap='gray')
                plt.title(title)
                plt.colorbar()
                plt.show()
    else:
        raise Exception(f"Failed to read .tif file: {response.status_code} - {response.text}")

# Create the URL for the blob using the container_url components
file_url = f"{blob_domain}/{container_name}/{first_blob.name}?{sas_token}"

# Extract the filename safely from the URL without the SAS token
parsed_url = urlparse(file_url)
path = parsed_url.path  # Gets just the path portion of the URL
filename = os.path.basename(path)  # Get just the filename part

# Remove .tif extension if present
file_name = filename.replace('.tif', '')

print(f"Extracted File Name: {file_name}")

display_tif_from_url(file_url, file_name)

Uma visualização em escala de cinza de dados raster geoespaciais de um satélite GOES-18, mostrando padrões de temperatura da superfície terrestre em uma região.

Olhando para os dados e o nome do arquivo, já podemos ver as principais peças de metadados necessárias para construir o item STAC. O nome do arquivo contém informações sobre qual satélite capturou os dados e quando eles foram capturados.

Para o exemplo, o nome do arquivo é OR_ABI-L2-LSTC-M6_G18_s20232080101177_e20232080103550_c20232080104570_DQF, com base no guia do produto, isso significa:

Componentes detalhados

Campo Descrição Propósito
OU Ambiente do sistema operacional Especifica o ambiente do sistema no qual os dados foram coletados
ABI Instrumento Advanced Baseline Imager Identifica o instrumento utilizado para capturar os dados
L2 Produto de nível 2 (produto derivado) Indica que os dados são um produto derivado, processados a partir de observações brutas
LSTC Produto de Temperatura da Superfície Terrestre (Céu Limpo) Representa o tipo de produto específico, concentrando-se na temperatura da superfície terrestre em condições de céu limpo
M6 Verificação do modo 6 (verificação de disco completo) Descreve o modo de varrimento, cobrindo todo o disco da Terra
G18 Satélite GOES-18 (também conhecido como GOES-West) Identifica o satélite a partir do qual os dados foram recolhidos

Detalhes do tempo de observação

Início da Observação (s20232080201177)-

Campo Descrição Propósito
Ano 2023 Especifica o ano da observação
Dia do Ano 208 Indica o dia do ano em que a observação começou
Tempo / Hora 02:01:17 UTC Fornece a hora exata em que a observação começou em UTC
Décimos de Segundo 7 Adiciona precisão à hora de início da observação

Fim da observação (e20232080203550)-

Campo Descrição Propósito
Ano 2023 Especifica o ano da observação
Dia do Ano 208 Indica o dia do ano em que a observação terminou
Tempo / Hora 02:03:55 UTC Fornece a hora exata em que a observação terminou em UTC
Décimos de Segundo 0 Adiciona precisão ao tempo final da observação

Tempo de criação do arquivo (c20232080204563)-

Campo Descrição Propósito
Ano 2023 Especifica o ano em que o arquivo foi criado
Dia do Ano 208 Indica o dia do ano em que o arquivo foi criado
Tempo / Hora 02:04:56 UTC Fornece a hora exata em que o arquivo foi criado em UTC
Décimos de Segundo 3 Adiciona precisão ao tempo de criação do arquivo

Informações Adicionais:

Campo Descrição Propósito
QDQ Sinalizador de Qualidade de Dados, indicando informações de qualidade para os dados correspondentes Fornece informações sobre a qualidade dos dados
.tif Extensão do arquivo Indica o formato de arquivo dos dados

O código a seguir extrai esses metadados do nome do arquivo usando expressões regulares (regex).

import re
from datetime import datetime, timedelta

def extract_goes_metadata(filename):
    """
    Extracts key metadata from a NOAA GOES satellite filename using regular expressions.

    Args:
        filename (str): The filename to parse.

    Returns:
        dict: A dictionary containing the extracted metadata.
    """

    # Regular expression pattern to match the filename format
    pattern = re.compile(
        r"^(OR)_"  # System (OR)
        r"(ABI)-(L\d)-(LSTC)-(M\d)_"  # Instrument, Level, Product, Mode
        r"(G\d{2})_"  # Satellite (G18)
        r"s(\d{4})(\d{3})(\d{2})(\d{2})(\d{2})(\d)_"  # Start time
        r"e(\d{4})(\d{3})(\d{2})(\d{2})(\d{2})(\d)_"  # End time
        r"c(\d{4})(\d{3})(\d{2})(\d{2})(\d{2})(\d)_"  # Creation time
        r"([A-Z0-9]+)$"  # Data quality flag
    )

    match = pattern.match(filename)

    if not match:
        return None  # Or raise an exception if you prefer

    # Extract all fields from the regular expression match groups
    (
        system,          # Operational system environment
        instrument,      # Advanced Baseline Imager
        level,           # Product level (L2)
        product_type,    # Product type (LSTC - Land Surface Temperature)
        mode,            # Scanning mode (M6)
        satellite,       # Satellite identifier (G18)
        s_year, s_doy, s_hour, s_minute, s_second, s_tenth,  # Start time components
        e_year, e_doy, e_hour, e_minute, e_second, e_tenth,  # End time components
        c_year, c_doy, c_hour, c_minute, c_second, c_tenth,  # Creation time components
        data_quality_flag  # Quality flag indicator
    ) = match.groups()

    def parse_goes_time(year, doy, hour, minute, second, tenth):
        """Parses GOES time components into an ISO format string."""
        try:
            dt = datetime(int(year), 1, 1) + timedelta(
                days=int(doy) - 1,
                hours=int(hour),
                minutes=int(minute),
                seconds=int(second),
                microseconds=int(tenth) * 100000,
            )
            return dt
        except ValueError:
            return None

    # Parse the time components into datetime objects
    start_time = parse_goes_time(s_year, s_doy, s_hour, s_minute, s_second, s_tenth)
    end_time = parse_goes_time(e_year, e_doy, e_hour, e_minute, e_second, e_tenth)
    creation_time = parse_goes_time(c_year, c_doy, c_hour, c_minute, c_second, c_tenth)

    # Create a dictionary to organize all extracted metadata
    metadata = {
        "system": system,               # Operational system environment (e.g., "OR" for operational)
        "instrument": instrument,       # Instrument used to capture data (e.g., "ABI" for Advanced Baseline Imager)
        "level": level,                 # Processing level of the data (e.g., "L2" for Level 2)
        "product_type": product_type,   # Type of product (e.g., "LSTC" for Land Surface Temperature Clear Sky)
        "mode": mode,                   # Scanning mode (e.g., "M6" for Mode 6, full disk scan)
        "satellite": satellite,         # Satellite identifier (e.g., "G18" for GOES-18)
        "start_time": start_time,       # Observation start time as datetime object
        "end_time": end_time,           # Observation end time as datetime object
        "creation_time": creation_time, # File creation time as datetime object
        "data_quality_flag": data_quality_flag,  # Quality flag for the data (e.g., "DQF")
    }

    return metadata


# Example usage:
print(file_name)
metadata_from_filename = extract_goes_metadata(file_name)
print(metadata_from_filename)
OR_ABI-L2-LSTC-M6_G18_s20232080001177_e20232080003550_c20232080004568_DQF
{'system': 'OR', 'instrument': 'ABI', 'level': 'L2', 'product_type': 'LSTC', 'mode': 'M6', 'satellite': 'G18', 'start_time': datetime.datetime(2023, 7, 27, 0, 1, 17, 700000), 'end_time': datetime.datetime(2023, 7, 27, 0, 3, 55), 'creation_time': datetime.datetime(2023, 7, 27, 0, 4, 56, 800000), 'data_quality_flag': 'DQF'}

Criar Itens STAC a partir de arquivos GeoTIFF Cloud-Optimized

O bloco de código a seguir usa a rio-stac biblioteca para automatizar a criação de itens STAC a partir de Cloud-Optimized GeoTIFFs (COGs).

Quando apontado para um arquivo COG, rio-stac extrai e organiza automaticamente metadados essenciais, como limites espaciais, informações de projeção e propriedades raster em um formato STAC padronizado. A biblioteca lida com a tarefa complexa de ler os metadados técnicos incorporados do GeoTIFF e os converte em campos compatíveis com STAC, incluindo:

  • Geometria
  • Caixa delimitadora (bbox)
  • Detalhes da Projeção
  • Características do Raster
  • Extensões STAC

Essa automação reduz significativamente o trabalho manual necessário para criar itens STAC válidos e garante a consistência nos metadados

Observação

GeoCatalog tem limitações em caracteres que podem ser usados em IDs de item STAC e chaves de recurso. Certifique-se de que os seus IDs não contêm os seguintes caracteres: -, _, +, (, )e .. Talvez seja necessário modificar a item_id lógica de geração para substituir ou remover esses caracteres dos nomes dos arquivos.

from rio_stac import create_stac_item
from rasterio.io import MemoryFile
import json
from urllib.parse import urlparse, unquote

def create_stac_item_from_cog(url):
    """
    Create a basic STAC Item for GOES data using rio-stac with proper spatial handling
    
    Args:
        url (str): URL to the COG file
        
    Returns:
        pystac.Item: STAC Item with basic metadata and correct spatial information
    """
    
    # Extract the filename safely from the URL
    parsed_url = urlparse(url)
    path = parsed_url.path  # Gets just the path portion of the URL
    filename = os.path.basename(path)  # Get just the filename part
    
    # Remove .tif extension if present
    item_id = filename.replace('.tif', '')
    
    response = requests.get(url, stream=True)
    if response.status_code == 200:
        with MemoryFile(response.content) as memfile:
            with memfile.open() as dataset:
                # Create base STAC item from rasterio dataset calling create_stac_item from rio_stac
                stac_item = create_stac_item(
                    source=dataset,  # The rasterio dataset object representing the COG file
                    id=item_id,  # Generate a unique ID by extracting the filename without the .tif extension
                    asset_name='data',  # Name of the asset, indicating it contains the primary data
                    asset_href=url,  # URL to the COG file, used as the asset's location
                    with_proj=True,  # Include projection metadata (e.g., CRS, bounding box, etc.)
                    with_raster=True,  # Include raster-specific metadata (e.g., bands, resolution, etc.)
                    properties={
                        'datetime': None,  # Set datetime to None since explicit start/end times may be added later
                        # Add rasterio-specific metadata for the raster bands
                        'raster:bands': [
                            {
                                'nodata': dataset.nodata,  # Value representing no data in the raster
                                'data_type': dataset.dtypes[0],  # Data type of the raster (e.g., uint16)
                                'spatial_resolution': dataset.res[0]  # Spatial resolution of the raster in meters
                            }
                        ],
                        'file:size': len(response.content)  # Size of the file in bytes
                    },
                    extensions=[
                        'https://stac-extensions.github.io/file/v2.1.0/schema.json'  # Add the file extension schema for additional metadata
                    ]
                )
                
                return stac_item
    else:
        raise Exception(f"Failed to read .tif file: {response.status_code} - {response.text}")

# Example usage
sas_token = get_sas_token(sas_endpoint) # refresh the SAS token prior to creating STAC item
# Create file URL using the first_blob variable that's already defined
file_url = f"{blob_domain}/{container_name}/{first_blob.name}?{sas_token}"
# Create STAC item for the first blob
stac_item = create_stac_item_from_cog(file_url)

# Print the STAC item as JSON
print(json.dumps(stac_item.to_dict(), indent=2))
    {
      "type": "Feature",
      "stac_version": "1.0.0",
      "stac_extensions": [
        "https://stac-extensions.github.io/file/v2.1.0/schema.json",
        "https://stac-extensions.github.io/projection/v1.1.0/schema.json",
        "https://stac-extensions.github.io/raster/v1.1.0/schema.json"
      ],
      "id": "OR_ABI-L2-LSTC-M6_G18_s20232080001177_e20232080003550_c20232080004568_DQF",
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              -161.57885623466754,
              14.795666555826678
            ],
            [
              -112.42114380921453,
              14.79566655500485
            ],
            [
              -89.5501123912648,
              53.52729778421186
            ],
            [
              175.5501122574517,
              53.52729779865781
            ],
            [
              -161.57885623466754,
              14.795666555826678
            ]
          ]
        ]
      },
      "bbox": [
        -161.57885623466754,
        14.79566655500485,
        175.5501122574517,
        53.52729779865781
      ],
      "properties": {
        "datetime": "2025-03-26T14:46:05.484602Z",
        "raster:bands": [
          {
            "nodata": 65535.0,
            "data_type": "uint16",
            "spatial_resolution": 2004.017315487541
          }
        ],
        "file:size": 118674,
        "proj:epsg": null,
        "proj:geometry": {
          "type": "Polygon",
          "coordinates": [
            [
              [
                -2505021.6463773525,
                1583173.791653181
              ],
              [
                2505021.6423414997,
                1583173.791653181
              ],
              [
                2505021.6423414997,
                4589199.764884492
              ],
              [
                -2505021.6463773525,
                4589199.764884492
              ],
              [
                -2505021.6463773525,
                1583173.791653181
              ]
            ]
          ]
        },
        "proj:bbox": [
          -2505021.6463773525,
          1583173.791653181,
          2505021.6423414997,
          4589199.764884492
        ],
        "proj:shape": [
          1500,
          2500
        ],
        "proj:transform": [
          2004.017315487541,
          0.0,
          -2505021.6463773525,
          0.0,
          -2004.017315487541,
          4589199.764884492,
          0.0,
          0.0,
          1.0
        ],
        "proj:wkt2": "PROJCS[\"unnamed\",GEOGCS[\"unknown\",DATUM[\"unnamed\",SPHEROID[\"Spheroid\",6378137,298.2572221]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]]],PROJECTION[\"Geostationary_Satellite\"],PARAMETER[\"central_meridian\",-137],PARAMETER[\"satellite_height\",35786023],PARAMETER[\"false_easting\",0],PARAMETER[\"false_northing\",0],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH],EXTENSION[\"PROJ4\",\"+proj=geos +lon_0=-137 +h=35786023 +x_0=0 +y_0=0 +ellps=GRS80 +units=m +no_defs +sweep=x\"]]"
      },
      "links": [],
      "assets": {
        "data": {
          "href": "https://goeseuwest.blob.core.windows.net/noaa-goes-cogs/goes-18/ABI-L2-LSTC/2023/208/00/OR_ABI-L2-LSTC-M6_G18_s20232080001177_e20232080003550_c20232080004568_DQF.tif?st=2025-03-25T14%3A46%3A03Z&se=2025-03-26T15%3A31%3A03Z&sp=rl&sv=2024-05-04&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2025-03-26T12%3A41%3A49Z&ske=2025-04-02T12%3A41%3A49Z&sks=b&skv=2024-05-04&sig=BuMxN2NUTdrhzY7Dvpd/X4yfX8gnFpHOzANHQLkKE1k%3D",
          "type": "image/tiff; application=geotiff",
          "raster:bands": [
            {
              "data_type": "uint16",
              "scale": 1.0,
              "offset": 0.0,
              "sampling": "area",
              "nodata": 65535.0,
              "unit": "1",
              "statistics": {
                "mean": 2.780959413109756,
                "minimum": 0,
                "maximum": 3,
                "stddev": 0.710762086175375,
                "valid_percent": 100.0
              },
              "histogram": {
                "count": 11,
                "min": 0.0,
                "max": 3.0,
                "buckets": [
                  26655,
                  0,
                  0,
                  25243,
                  0,
                  0,
                  7492,
                  0,
                  0,
                  570370
                ]
              }
            }
          ],
          "roles": []
        }
      }
    }

Item STAC JSON do rio-stac

A biblioteca rio-stac lê o arquivo GOES COG e extrai metadados de chave automaticamente.

Além disso, com base no tipo de metadados incluídos, o rio-stac adicionou as extensões STAC relevantes. As extensões STAC aprimoram a especificação principal adicionando metadados padronizados e específicos do domínio.

  • A extensão de arquivo fornece metadados de arquivo essenciais, como tamanho e somas de verificação.
  • A Extensão de Projeção captura informações de referência espacial, incluindo sistemas de coordenadas e caixas delimitadoras.
  • A Extensão Raster padroniza propriedades específicas para dados rasterizados, como informações de banda e resolução espacial.

As tabelas a seguir fornecem uma explicação de todos os metadados que o rio-stac encontrou.

Campos principais

Campo Descrição Propósito
tipo Sempre "Recurso" Identifica o tipo como um recurso GeoJSON
stac_version 1.0.0 Especifica a versão padrão do STAC
identificação Identificador exclusivo Contém informações sobre satélite, produto e hora
stac_extensions Lista de URLs do esquema Define campos de metadados extras

Informação Geográfica

Campo Descrição Propósito
geometria Polígono GeoJSON Define a pegada digital nas coordenadas WGS84
bbox Coordenadas da caixa delimitadora Fornece extensão espacial simples para filtragem rápida
proj:geometria Polígono específico da projeção Pegada nas coordenadas de projeção nativas
Proj:Bbox Limites de projeção nativos Extensão espacial no sistema de coordenadas do satélite
proj:forma [1500, 2500] Dimensões da imagem em pixels
proj:transformar Transformação afim Mapeia pixel para coordenar o espaço
Proj:WKT2 Well-Known Text Definição completa da projeção
Proj:EPSG null Não existe um código EPSG padrão para esta projeção de mapa

Informação Temporal

Campo Descrição Propósito
datetime Data e hora de criação Quando este item STAC foi criado

Informação Raster

Campo Descrição Propósito
raster:bandas Matriz de objetos de banda Descreve as propriedades de dados raster
tipo_de_dado "Uint16" Tipos de dados de pixel
resolução espacial 2004.02m Distância da amostra à terra
→ escala/deslocamento Fatores de conversão Transforma valores de pixel em unidades físicas (Kelvin)
→ sem dados 65535.0 Valor que representa ausência de dados
→ estatísticas Síntese estatística Fornece informações de distribuição de dados
→ histograma Distribuição de valor Visualiza a distribuição de dados

Informações sobre ativos

Campo Descrição Propósito
ativos.dados Principal ativo de dados Aponta para o arquivo de dados real
→ href URL Localização do Cloud-Optimized GeoTIFF
→ tipo Tipo de suporte Identifica o formato de arquivo

Metadados de arquivo

Campo Descrição Propósito
arquivo:tamanho 943.250 bytes Tamanho do ficheiro de dados

Adicionando os metadados do nome do arquivo

Em seguida, adicionamos os dados que encontramos no nome do arquivo para concluir o preenchimento dos metadados para este item STAC.

Uma coisa a notar é que todas as datas e horas dos itens STAC devem estar em conformidade com a ISO 8601. A biblioteca PySTAC tem uma função datetime_to_str que garante que os dados sejam formatados corretamente.

import pystac

def enhance_stac_item_with_metadata(stac_item, metadata_from_filename):
    """
    Enhances a STAC Item with additional metadata from GOES filename.
    
    Args:
        stac_item (pystac.Item): Existing STAC Item created by rio-stac
        metadata_from_filename (dict): Metadata extracted from filename
        
    Returns:
        pystac.Item: Enhanced STAC Item
    """
    # Add satellite/sensor properties to the STAC item
    stac_item.properties.update({
        'platform': f"GOES-{metadata_from_filename['satellite'][1:]}",
        'instruments': [metadata_from_filename['instrument']],
        'constellation': 'GOES'
    })
    
    # Add temporal properties to the STAC item, use pystac to ensure time conforms to ISO 8601
    stac_item.datetime = None  # Clear the default datetime
    stac_item.properties.update({
        'start_datetime': pystac.utils.datetime_to_str(metadata_from_filename['start_time']),
        'end_datetime': pystac.utils.datetime_to_str(metadata_from_filename['end_time']),
        'created': pystac.utils.datetime_to_str(metadata_from_filename['creation_time'])
    })
    
    # Add GOES-specific properties to the STAC item
    stac_item.properties.update({
        'goes:system': metadata_from_filename['system'],
        'goes:level': metadata_from_filename['level'],
        'goes:product_type': metadata_from_filename['product_type'],
        'goes:mode': metadata_from_filename['mode'],
        'goes:processing_level': metadata_from_filename['level'],
        'goes:data_quality_flag': metadata_from_filename['data_quality_flag']
    })
    
    return stac_item


# Example usage in new cell
stac_item = enhance_stac_item_with_metadata(stac_item, metadata_from_filename)
print(json.dumps(stac_item.to_dict(), indent=2))

O item STAC:

    {
      "type": "Feature",
      "stac_version": "1.0.0",
      "stac_extensions": [
        "https://stac-extensions.github.io/file/v2.1.0/schema.json",
        "https://stac-extensions.github.io/projection/v1.1.0/schema.json",
        "https://stac-extensions.github.io/raster/v1.1.0/schema.json"
      ],
      "id": "OR_ABI-L2-LSTC-M6_G18_s20232080001177_e20232080003550_c20232080004568_DQF",
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              -161.57885623466754,
              14.795666555826678
            ],
            [
              -112.42114380921453,
              14.79566655500485
            ],
            [
              -89.5501123912648,
              53.52729778421186
            ],
            [
              175.5501122574517,
              53.52729779865781
            ],
            [
              -161.57885623466754,
              14.795666555826678
            ]
          ]
        ]
      },
      "bbox": [
        -161.57885623466754,
        14.79566655500485,
        175.5501122574517,
        53.52729779865781
      ],
      "properties": {
        "datetime": null,
        "raster:bands": [
          {
            "nodata": 65535.0,
            "data_type": "uint16",
            "spatial_resolution": 2004.017315487541
          }
        ],
        "file:size": 118674,
        "proj:epsg": null,
        "proj:geometry": {
          "type": "Polygon",
          "coordinates": [
            [
              [
                -2505021.6463773525,
                1583173.791653181
              ],
              [
                2505021.6423414997,
                1583173.791653181
              ],
              [
                2505021.6423414997,
                4589199.764884492
              ],
              [
                -2505021.6463773525,
                4589199.764884492
              ],
              [
                -2505021.6463773525,
                1583173.791653181
              ]
            ]
          ]
        },
        "proj:bbox": [
          -2505021.6463773525,
          1583173.791653181,
          2505021.6423414997,
          4589199.764884492
        ],
        "proj:shape": [
          1500,
          2500
        ],
        "proj:transform": [
          2004.017315487541,
          0.0,
          -2505021.6463773525,
          0.0,
          -2004.017315487541,
          4589199.764884492,
          0.0,
          0.0,
          1.0
        ],
        "proj:wkt2": "PROJCS[\"unnamed\",GEOGCS[\"unknown\",DATUM[\"unnamed\",SPHEROID[\"Spheroid\",6378137,298.2572221]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]]],PROJECTION[\"Geostationary_Satellite\"],PARAMETER[\"central_meridian\",-137],PARAMETER[\"satellite_height\",35786023],PARAMETER[\"false_easting\",0],PARAMETER[\"false_northing\",0],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH],EXTENSION[\"PROJ4\",\"+proj=geos +lon_0=-137 +h=35786023 +x_0=0 +y_0=0 +ellps=GRS80 +units=m +no_defs +sweep=x\"]]",
        "platform": "GOES-18",
        "instruments": [
          "ABI"
        ],
        "constellation": "GOES",
        "start_datetime": "2023-07-27T00:01:17.700000Z",
        "end_datetime": "2023-07-27T00:03:55Z",
        "created": "2023-07-27T00:04:56.800000Z",
        "goes:system": "OR",
        "goes:level": "L2",
        "goes:product_type": "LSTC",
        "goes:mode": "M6",
        "goes:processing_level": "L2",
        "goes:data_quality_flag": "DQF"
      },
      "links": [],
      "assets": {
        "data": {
          "href": "https://goeseuwest.blob.core.windows.net/noaa-goes-cogs/goes-18/ABI-L2-LSTC/2023/208/00/OR_ABI-L2-LSTC-M6_G18_s20232080001177_e20232080003550_c20232080004568_DQF.tif?st=2025-03-25T14%3A46%3A03Z&se=2025-03-26T15%3A31%3A03Z&sp=rl&sv=2024-05-04&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2025-03-26T12%3A41%3A49Z&ske=2025-04-02T12%3A41%3A49Z&sks=b&skv=2024-05-04&sig=BuMxN2NUTdrhzY7Dvpd/X4yfX8gnFpHOzANHQLkKE1k%3D",
          "type": "image/tiff; application=geotiff",
          "raster:bands": [
            {
              "data_type": "uint16",
              "scale": 1.0,
              "offset": 0.0,
              "sampling": "area",
              "nodata": 65535.0,
              "unit": "1",
              "statistics": {
                "mean": 2.780959413109756,
                "minimum": 0,
                "maximum": 3,
                "stddev": 0.710762086175375,
                "valid_percent": 100.0
              },
              "histogram": {
                "count": 11,
                "min": 0.0,
                "max": 3.0,
                "buckets": [
                  26655,
                  0,
                  0,
                  25243,
                  0,
                  0,
                  7492,
                  0,
                  0,
                  570370
                ]
              }
            }
          ],
          "roles": []
        }
      }
    }

Adicionar o item STAC a uma coleção

O MC Pro requer que todos os Itens STAC tenham uma referência ao ID de Coleção STAC principal na qual são integrados. Para este tutorial, o ID da coleção STAC é o nome do satélite e do produto de dados.

Com o PySTAC, é fácil usar alguns dos metadados coletados dos arquivos de origem para preencher os campos-chave para a Coleção STAC e usar as funções de validação integradas.

O código a seguir cria uma coleção STAC pai para abrigar os dados GOES. Em seguida, o código salva essas informações em arquivos usados para criar a coleção STAC do Microsoft Planetary Computer Pro e ingerir itens STAC no Planetary Computer Pro.

# Define collection properties
collection_id = f"{satellite}-{product}"
collection_title = f"{satellite.upper()} {product} Collection" 
collection_desc = f"Collection of {satellite} {product} Earth observation data"

# Create spatial extent
bbox = [-180, -60, 10, 60]  # placeholder, replace with actual data at a later date
spatial_extent = pystac.SpatialExtent([bbox])

# Create temporal extent, use current date time or replace with existing datetimes in stac_item
start_datetime = datetime.now()
if hasattr(metadata_from_filename, 'get'): 
    if metadata_from_filename.get('start_time'):
        start_datetime = metadata_from_filename.get('start_time')

temporal_extent = pystac.TemporalExtent([[start_datetime, None]])
extent = pystac.Extent(spatial=spatial_extent, temporal=temporal_extent)

# Create the STAC Collection
collection = pystac.Collection(
    id=collection_id,
    description=collection_desc,
    extent=extent,
    title=collection_title,
    license="public-domain",
)

# Add keywords and provider
collection.keywords = ["GOES", "satellite", "weather", "NOAA", satellite, product]
collection.providers = [
    pystac.Provider(
        name="NOAA",
        roles=["producer", "licensor"],
        url="https://www.noaa.gov/"
    )
]

# Create output directories
output_dir = "stac_catalog"
collection_dir = os.path.join(output_dir, collection_id)
items_dir = os.path.join(collection_dir, "items")
os.makedirs(items_dir, exist_ok=True)

# Important: Save the collection first to generate proper file paths
collection_path = os.path.join(collection_dir, "collection.json")
collection.set_self_href(collection_path)

# Extract filename for the item
original_filename = first_blob.name.split('/')[-1]
base_filename = original_filename.replace('.tif', '')
item_path = os.path.join(items_dir, f"{base_filename}.json")

# Set the item's proper href
stac_item.set_self_href(item_path)

# Now associate the item with the collection (after setting hrefs)
collection.add_item(stac_item)

# Create a catalog to contain the collection
catalog = pystac.Catalog(
    id="goes-data-catalog",
    description="GOES Satellite Data Catalog",
    title="GOES Data"
)
catalog_path = os.path.join(output_dir, "catalog.json")
catalog.set_self_href(catalog_path)
catalog.add_child(collection)

# Validate the collection and contained items
print("Validating collection and items...")
try:
    collection.validate_all()
    print("✅ Collection and items validated successfully")
    
    # Save everything to disk
    catalog.normalize_and_save(catalog_path, pystac.CatalogType.SELF_CONTAINED)
    print(f"✅ STAC catalog saved at: {catalog_path}")
    print(f"✅ STAC collection saved at: {collection_path}")
    print(f"✅ STAC item saved at: {item_path}")
    
except Exception as e:
    print(f"❌ Validation error: {str(e)}")
Validating collection and items...
✅ Collection and items validated successfully
✅ STAC catalog saved at: stac_catalog/catalog.json
✅ STAC collection saved at: stac_catalog/goes-18-ABI-L2-LSTC/collection.json
✅ STAC item saved at: stac_catalog/goes-18-ABI-L2-LSTC/items/OR_ABI-L2-LSTC-M6_G18_s20232080001177_e20232080003550_c20232080004568_DQF.json

Próximos passos

Agora que você criou alguns itens STAC, é hora de ingerir os dados no Microsoft Planetary Computer Pro.

Para ingestão de um único item:

Para ingestão a granel:

Também oferecemos a ferramenta STAC Forge , que fornece maior automação usando modelos em torno de dados.