Compartilhar via


Criar um item do Catálogo de Ativos SpatioTemporal (STAC)

Saiba como criar um item do Catálogo de Ativos SpatioTemporal (STAC) para um ativo de dados geoespaciais de 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 do 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 itens STAC a partir de arquivos GeoTIFF otimizados para nuvem usando rio-stac.
  • Melhore o item STAC com metadados extraídos do nome do arquivo.
  • Adicione o item STAC à coleção STAC principal.
  • Valide e salve o catálogo, a coleção e os itens do STAC.
  • Adicione os itens STAC ao Microsoft Planetry Computer Pro.

Este tutorial demonstra e explica as capacidades por meio de trechos de código, proporcionando uma experiência interativa no estilo de notebook. Baixe este tutorial como um notebook Jupyter.

Pré-requisitos

Para concluir este guia de início rápido, você precisa:

Principais recursos do STAC

O Catálogo de Ativos SpatioTemporal (STAC) é um padrão aberto para estruturar e compartilhar 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. Veja a seguir os principais recursos do padrão STAC:

  • Interoperabilidade: o esquema baseado em JSON padronizado garante fácil integração e compreensão entre ferramentas e sistemas.
  • Extensibilidade: campos de núcleo flexíveis com extensões personalizadas para necessidades específicas.
  • Capacidade de descoberta: a estrutura consistente aprimora 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: habilita o processamento e a análise automatizados com metadados padronizados.

Benefícios do STAC para padronizar 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 de metadados comum.
  • Integração de dados aprimorada: facilita a integração de conjuntos de dados de várias fontes.
  • Gerenciamento simplificado de dados: ferramentas automatizadas reduzem o esforço manual na manutenção de metadados.
  • Preparação para o futuro: A natureza extensível se adapta a novos tipos de dados e tecnologias.

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

A Especificação do 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. Metadados que podem ser usados para preencher um Item STAC podem ser incluídos no conjunto de dados, em um arquivo sidecar (.XML, .JSON, .TXT etc.) ou até 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.

Esse tutorial usa dados de imagens de amostra do Cloud Optimized GeoTIFF (COG) do conjunto de dados de temperatura da superfície terrestre (LST) dos satélites Geostationary Operational Environmental Satellite R (GOES-R) da Agência Nacional Oceânica e Atmosférica (NOAA). Esses dados são incluídos nos arquivos abertos do Computador Planetário como COG, mas não têm metadados STAC. Os satélites GOES produzem muitos produtos de dados. Mais detalhes podem ser encontrados no Guia de Definição de Produto e Usuários da SérieGOES-R.

O processo usado neste tutorial pode ser generalizado para qualquer tipo de dados em que os campos de metadados de chave são enumerados usando várias bibliotecas de software livre.

Instalar bibliotecas do Python

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

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

  • pystac: esse 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 Itens STAC a partir de dados raster. Simplifica o processo de geração de metadados STAC para conjuntos de dados de raster.

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

  • azure-storage-blob: Esta biblioteca de cliente de Armazenamento do Azure oferece acesso aos serviços de Blob Storage do Azure. Ele permite 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 de código exibe alguns dados 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 de raster geoespaciais de um satélite GOES-18, mostrando padrões de temperatura da superfície terrestre em uma região.

Ao examinar os dados e o nome do arquivo, já podemos ver as principais partes de metadados necessárias para criar 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 usado para capturar os dados
L2 Produto de nível 2 (produto derivado) Indica que os dados são um produto derivado, processado a partir de observações brutas
LSTC Produto Temperatura da Superfície Terrestre (Céu Limpo) Representa o tipo de produto específico, concentrando-se na temperatura da superfície da terra sob condições claras do céu
M6 Modo 6 de varredura (varredura de disco completo) Descreve o modo de varredura, cobrindo todo o disco da Terra
G18 Satélite GOES-18 (também conhecido como GOES-West) Identifica o satélite do qual os dados foram coletados

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 foi iniciada
Hora 02:01:17 UTC Fornece a hora exata em que a observação foi iniciada 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
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 à hora de término da observação

Hora 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
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
DQF 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 de 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 biblioteca rio-stac para automatizar a criação de itens STAC a partir de GeoTIFFs otimizados para nuvem (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 de raster em um formato STAC padronizado. A biblioteca manipula a tarefa complexa de ler os metadados técnicos inseridos do GeoTIFF e converte-os em campos em conformidade com STAC, incluindo:

  • Geometria
  • Caixa delimitadora (bbox)
  • Detalhes da projeção
  • Características de raster
  • Extensões do 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

O GeoCatalog tem limitações em caracteres que podem ser usados em IDs de item STAC e chaves de ativo. Verifique se suas 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 de seus nomes de arquivo.

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 de rio-stac

A biblioteca rio-stac leu o arquivo GOES COG e extraiu metadados de chave automaticamente.

Além disso, com base no tipo de metadados incluído, 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.
  • 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 de dados de raster, como informações de banda e resolução espacial.

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

Campos principais

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

Informações espaciais

Campo Descrição Propósito
geometria Polígono GeoJSON Define a pegada de dados em coordenadas WGS84
bbox Coordenadas da caixa delimitadora Fornece extensão espacial simples para filtragem rápida
proj:geometry Polígono específico da projeção Pegada em coordenadas de projeção nativas
proj:bbox Limites de projeção nativos Extensão espacial no sistema de coordenadas do satélite
proj:shape [1500, 2500] Dimensões de imagem em pixels
proj:transform Transformação afim Mapas de pixels para coordenar o espaço
proj:wkt2 Texto Bem Conhecido Definição completa de projeção
proj:epsg nulo Nenhum código EPSG padrão existe para esta projeção de mapa

Informações temporais

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

Informações de Varredura

Campo Descrição Propósito
raster:bandas Conjunto de objetos de banda Descreve as propriedades de dados de raster
tipo_de_dado "uint16" Tipo de dados de pixel
→ resolução espacial 2004,02 m Distância de amostra no solo
→ escala/deslocamento Fatores de conversão Transforma valores de pixel em unidades físicas (Kelvin)
→ nodata 65535.0 Valor que não representa nenhum dado
estatísticas Resumo estatístico 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
assets.data Ativo de dados principal Aponta para o arquivo de dados real
→ href URL Localização do Cloud-Optimized GeoTIFF
→ tipo Tipo de mídia Identifica o formato do arquivo

Metadados de arquivo

Campo Descrição Propósito
arquivo:tamanho 943.250 bytes Tamanho do arquivo 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 deste Item STAC.

Algo a ser destacado é que todas as datas e horas para itens STAC devem estar em conformidade com o 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 exige que todos os itens STAC tenham uma referência ao ID da coleção STAC pai na qual foram ingeridos. Para este tutorial, a 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 de chave da Coleção STAC e usar as funções de validação internas.

O código a seguir cria uma Coleção STAC principal para armazenar 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 Planetry 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óximas etapas

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

Para ingestão de item único:

Para ingestão em massa:

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