Se você precisar de mais flexibilidade ao fazer upload de imagens no Google Earth Engine (EE) do que a interface do Code Editor ou o comando upload
da ferramenta de linha de comando "earthengine", faça o upload de uma imagem usando um arquivo JSON conhecido como "manifesto" e o comando upload image --manifest
da ferramenta de linha de comando.
Confira um exemplo completo em este notebook do Colab que demonstra o upload de blocos de imagem como um único recurso usando um manifesto.
Configuração única
- Os uploads de manifestos só funcionam com arquivos localizados no Google Cloud Storage. Para começar a usar o Google Cloud Storage, crie um projeto do Google Cloud, se você ainda não tiver um. A configuração exige a especificação de um cartão de crédito para faturamento. A EE não está cobrando ninguém no momento, mas transferir arquivos para o Google Cloud Storage antes de fazer upload deles para a EE vai ter um pequeno custo. Para tamanhos de dados de upload típicos (dezenas ou centenas de gigabytes), o custo será bastante baixo.
- No projeto, ative a API Cloud Storage e crie um bucket.
- Instale o cliente Python do Earth Engine. Ele inclui a ferramenta de linha de comando
earthengine
, que será usada para fazer upload de dados. - Para uploads automatizados, use uma conta de serviço do Google Cloud associada ao seu projeto. Você não precisa de uma conta de serviço para testar, mas quando tiver um momento, comece a se familiarizar com o uso delas.
Arquivos de origem muito grandes (100 GB ou mais) podem ser enviados mais rapidamente se forem divididos em vários blocos.
IDs e nomes dos recursos
Para recursos pertencentes a um projeto do Cloud, use esta convenção para nomes de recursos:
projects/some-project-id/assets/some-asset-id
.
Saiba mais sobre os nomes de recursos de projetos legados e de recursos de propriedade do usuário
Para projetos legados mais antigos, o nome do recurso no manifesto precisa ser um pouco diferente do ID do recurso visível em outros lugares no Earth Engine. Para fazer upload de recursos com IDs que começam com
users/some_user
ou projects/some_project
, o nome do recurso no
manifesto precisa ter a string projects/earthengine-legacy/assets/
adicionada ao
ID. Por exemplo, o ID do recurso EE users/username/my_geotiff
precisa ser enviado
usando o nome projects/earthengine-legacy/assets/users/username/my_geotiff
.
Sim, isso significa que IDs como projects/some_projects/some_asset
são
convertidos em nomes em que projects
é mencionado duas vezes:
projects/earthengine-legacy/assets/projects/some_projects/some_asset
.
Isso é confuso, mas necessário para se conformar aos padrões da API Google Cloud.
Como usar manifestos
Um manifesto básico é mostrado no bloco de código a seguir. Ele faz upload de um arquivo chamado small.tif
de um bucket do Google Cloud Storage chamado gs://earthengine-test
.
{ "name": "projects/some-project-id/assets/some-asset-id", "tilesets": [ { "sources": [ { "uris": [ "gs://earthengine-test/small.tif" ] } ] } ] }
Para usá-lo, salve-o em um arquivo chamado manifest.json
e execute:
earthengine upload image --manifest /path/to/manifest.json
O arquivo gs://earthengine-test/small.tif
existe e é
legível publicamente. Você pode usá-lo para testes.
Conjuntos de blocos
A estrutura de manifesto um tanto complicada do JSON é necessária para dar flexibilidade suficiente para resolver um desafio comum de upload: como descrever todas as maneiras possíveis de combinar pixels de vários arquivos de origem em um único recurso. Especificamente, há duas maneiras independentes de agrupar arquivos:
- Mosaicos. Às vezes, vários arquivos representam vários blocos (por exemplo, cada bloco é um quadrado de 1x1 grau). Esses arquivos precisam ser mosaicos (fundidos) na mesma faixa em um recurso de EE.
- Bandas separadas. Às vezes, vários arquivos representam várias bandas. Esses arquivos precisam ser empilhados como faixas em um recurso de EE.
Talvez seja necessário usar as duas maneiras ao mesmo tempo, mas isso é raro.
Para descrever essas opções, os manifestos introduzem o conceito de um tileset. Um único tileset corresponde a uma única origem do GDAL. Por isso, todas as origens em um único conjunto de blocos precisam ter a mesma estrutura do GDAL (número e tipo de faixas, projeção, transformação, valor ausente). Como uma fonte do GDAL pode ter várias bandas, um conjunto de blocos pode conter dados de várias bandas de EE.
Para a aquisição de mosaico, o manifesto será assim:
{ "name": "projects/some-project-id/assets/some-asset-id", "tilesets": [ { "sources": [ { "uris": [ "gs://bucket/N30W22.tif" ] }, { "uris": [ "gs://bucket/N31W22.tif" ] } ] } ] }
Para bandas separadas, o manifesto vai ficar
assim. Você também precisa adicionar uma seção bands
,
conforme explicado abaixo:
{ "name": "projects/some-project-id/assets/some-asset-id", "bands": ..., "tilesets": [ { "id": "tileset_for_band1", "sources": [ { "uris": [ "gs://bucket/band1.tif" ] } ] }, { "id": "tileset_for_band2", "sources": [ { "uris": [ "gs://bucket/band2.tif" ] } ] } ] }
No caso de faixas separadas, precisamos atribuir um ID diferente a cada bloco para maior clareza. O ID do bloco de telhas pode ser uma string arbitrária. Essas strings não são mantidas no recurso enviado. Os IDs de conjunto de blocos são usados apenas na transferência para distinguir os conjuntos de blocos empilhados.
Bandas
O segundo conceito importante é a correspondência de arquivos de origem com as faixas de recursos de EE.
Isso é feito usando a seção bands
do manifesto.
A seção bands
pode ser omitida. Nesse caso, as faixas são criadas primeiro a partir dos arquivos do primeiro conjunto de blocos, depois do próximo e assim por diante.
Por padrão, os intervalos são nomeados "b1", "b2" etc. Para substituir os nomes de banda padrão, inclua
uma seção "bands" no final, como esta:
{ "name": "projects/earthengine-legacy/assets/users/username/some_folder/some_id", "tilesets": [ { "sources": [ { "uris": [ "gs://bucket/rgb.tif" ] } ] } ], "bands": [ { "id": "R", "tilesetBandIndex": 0 }, { "id": "G", "tilesetBandIndex": 1 }, { "id": "B", "tilesetBandIndex": 2 } ] }
O número de bandas de EE precisa ser igual ao número total de bandas em todos os conjuntos de blocos.
Se você não quiser transferir todas as bandas de um arquivo, use o campo tilesetBandIndex
para indicar quais das bandas do GDAL devem ser transferidas.
A primeira faixa tem um tilesetBandIndex de 0.
Exemplo:
Suponha que o arquivo de origem tenha quatro faixas: "tmin", "tmin_error", "tmax" e "tmax_error". Queremos apenas processar "tmin" e "tmax". As seções relevantes do manifesto vão ficar assim:
{ "name": "projects/earthengine-legacy/assets/users/username/some_folder/some_id", "tilesets": [ { "id": "temperature", "sources": [ { "uris": [ "gs://bucket/temperature.tif" ] } ] } ], "bands": [ { "id": "tmin", "tilesetBandIndex": 0, "tilesetId": "temperature" }, { "id": "tmax", "tilesetBandIndex": 2, "tilesetId": "temperature" } ] }
Máscaras de banda
O mascaramento de banda é controlado pelo componente maskBands
do manifesto.
Três configurações de máscara possíveis são compatíveis, mas a banda de máscara é sempre considerada
a última banda em um determinado arquivo.
- Use a máscara para todas as faixas de dados no mesmo arquivo.
- Mascarar todas as faixas de dados provenientes de outros arquivos.
- Mascarar algumas faixas de dados.
1. O caso mais comum é um único GeoTIFF em que a última banda é usada como máscara para as outras bandas. Isso só funciona para GeoTIFFs do tipo Byte. Use o seguinte manifesto:
{ "name": "projects/earthengine-legacy/assets/users/username/some_folder/some_id", "tilesets": [ { "id": "data_tileset", "sources": [ { "uris": [ "gs://bucket/data_file.tif" ] } ] } ], "bands": [ { "id": "data_band", "tilesetId": "data_tileset" }, { "id": "qa_band", "tilesetId": "data_tileset" } ], "maskBands": [ { "tilesetId": "data_tileset" } ] }
2. Para usar uma máscara GeoTIFF como uma máscara para todas as bandas em outro GeoTIFF, use o seguinte manifesto:
{ "name": "projects/earthengine-legacy/assets/users/username/some_folder/some_id", "tilesets": [ { "id": "data_tileset", "sources": [ { "uris": [ "gs://bucket/data_file.tif" ] } ] }, { "id": "mask_tileset", "sources": [ { "uris": [ "gs://bucket/mask_file.tif" ] } ] } ], "bands": [ { "id": "data_band", "tilesetId": "data_tileset" }, { "id": "qa_band", "tilesetId": "data_tileset" } ], "maskBands": [ { "tilesetId": "mask_tileset" } ] }
3. Para usar um GeoTIFF como uma máscara para uma banda específica em outro arquivo, use o seguinte manifesto (a diferença em relação ao caso anterior é que o campo bandIds
em maskBands
está definido):
{ "name": "projects/earthengine-legacy/assets/users/username/some_folder/some_id", "tilesets": [ { "id": "data_tileset", "sources": [ { "uris": [ "gs://bucket/data_file.tif" ] } ] }, { "id": "mask_tileset", "sources": [ { "uris": [ "gs://bucket/mask_file.tif" ] } ] } ], "bands": [ { "id": "data_band", "tilesetId": "data_tileset" }, { "id": "qa_band", "tilesetId": "data_tileset" } ], "maskBands": [ { "tilesetId": "mask_tileset", "bandIds": ["data_band"] } ] }
No último exemplo, estamos trabalhando com duas faixas do conjunto de blocos data_tileset
, mas estamos aplicando uma máscara apenas a uma das faixas (data_band
), conforme indicado pelo campo bandIds
do único objeto de lista maskBands
fornecido.
Somente a última faixa do conjunto de blocos mencionada em maskBands
é usada como
a faixa de máscara.
Política de pirâmide
Quando o Earth Engine constrói
pirâmides de imagens
durante a transferência, ele precisa reduzir repetidamente as grades de 2 x 2 pixels em um único pixel,
transformando o valor do pixel de alguma forma. Por padrão, os valores de pixel são calculados em média, o que
é a coisa certa a fazer na maioria dos casos, quando a banda raster representa dados mais ou menos
contínuos. No entanto, há duas situações em que a utilização do padrão
vai produzir resultados incorretos. Nesse caso, o campo pyramidingPolicy
na
definição da banda precisa ser definido. Se não for definido, o valor será "MEAN"
por padrão.
Para a classificação de imagens raster (por exemplo, para a classificação de cobertura de terras), a maneira mais lógica de piramidar pixels é usar a maioria dos quatro valores para produzir o próximo. Isso é feito usando a política de pirâmide "MODE":
{ "name": "projects/earthengine-legacy/assets/users/username/some_folder/some_id", "tilesets": [ { "sources": [ { "uris": [ "gs://bucket/landcover.tif" ] } ] } ], "bands": [ { "id": "landcover", "pyramidingPolicy": "MODE" } ] }
Para bandas raster em que nem "MEAN" nem "MODE" fazem sentido (por exemplo, pixels compactados), use a política de acúmulo de "SAMPLE". "SAMPLE" sempre recebe o valor do pixel superior esquerdo de cada grade 2x2. O exemplo a seguir atribui a política de acúmulo "MEAN" a uma banda que representa uma variável contínua ("NDVI") e "SAMPLE" à banda "QA" dos dados.
{ "name": "projects/earthengine-legacy/assets/users/username/some_folder/some_id", "tilesets": [ { "sources": [ { "uris": [ "gs://bucket/ndvi.tif" ] } ] } ], "bands": [ { "id": "NDVI", "tilesetBandIndex": 0, "pyramidingPolicy": "MEAN" }, { "id": "QA", "tilesetBandIndex": 1, "pyramidingPolicy": "SAMPLE" } ] }
Horário de início e término
Todos os recursos precisam especificar o horário de início e término para dar mais contexto aos dados, especialmente se eles forem incluídos em coleções. Esses campos não são obrigatórios, mas é altamente recomendável usá-los sempre que possível.
O horário de início e término geralmente significa o horário da observação, não o horário em que o arquivo de origem foi produzido.
O horário de término é tratado como um limite exclusivo para simplificar. Por exemplo, para recursos que abrangem exatamente um dia, use a meia-noite de dois dias consecutivos (por exemplo, 1980-01-31T00:00:00 e 1980-02-01T00:00:00) para a hora de início e término. Se o recurso não tiver duração, defina o horário de término como o mesmo que o de início. Representar horários em manifestos como strings ISO 8601. Recomendamos que você suponha que o horário de término seja exclusivo (por exemplo, meia-noite do dia seguinte para recursos diários) para simplificar os valores de data.
Exemplo:
{ "name": "projects/some-project-id/assets/some-asset-id", "tilesets": [ { "sources": [ { "uris": [ "gs://bucket/img_20190612.tif" ] } ] } ], "startTime": "1980-01-31T00:00:00Z", "endTime": "1980-02-01T00:00:00Z" }
Referência da estrutura do manifesto
A estrutura JSON a seguir inclui todos os campos possíveis do manifesto de upload de imagens. Encontre definições de campos na seção "Definições de campos do manifesto" a seguir.
{ "name": <string>, "tilesets": [ { "dataType": <string>, "id": <string>, "crs": <string>, "sources": [ { "uris": [ <string> ], "affineTransform": { "scaleX": <double>, "shearX": <double>, "translateX": <double>, "shearY": <double>, "scaleY": <double>, "translateY": <double> } } ] } ], "bands": [ { "id": <string>, "tilesetId": <string>, "tilesetBandIndex": <int32>, "missingData": { "values": [<double>] }, "pyramindingPolicy": <string> } ], "maskBands": [ { "tilesetId": <string>, "bandIds": [ <string> ] } ], "footprint": { "points": [ { "x": <double>, "y": <double> } ], "bandId": <string> }, "missingData": { "values": [<double>] }, "pyramidingPolicy": <string>, "uriPrefix": <string>, "startTime": { "seconds": <integer> }, "endTime": { "seconds": <integer> }, "properties": { <unspecified> } }
Definições de campos do manifesto
nome
string
O nome do recurso a ser criado.
name
tem o formato "projects/*/assets/**", por exemplo, "projects/earthengine-legacy/assets/users/USER/ASSET".
conjuntos de blocos
list
Uma lista de dicionários que definem propriedades para conjuntos de blocos.
Consulte os campos de elemento do dicionário tilesets
a seguir
para mais informações.
tilesets[i].dataType
string
Especifica o tipo de dados numéricos. O padrão é o tipo que o GDAL informa. Nesse caso, não é necessário definir.
Tipo de dado | Valor |
---|---|
Não especificado | "DATA_TYPE_UNSPECIFIED" |
Inteiro assinado de 8 bits | "INT8" |
Número inteiro não assinado de 8 bits | "UINT8" |
Inteiro assinado de 16 bits | "INT16" |
Número inteiro não assinado de 16 bits | "UINT16" |
Inteiro assinado de 32 bits | "INT32" |
Número inteiro sem assinatura de 32 bits | "UINT32" |
Flutuante de 32 bits | "FLOAT32" |
Ponto flutuante de 64 bits | "FLOAT64" |
tilesets[i].id
string
O ID do bloco de telhas. Precisa ser exclusivo entre os tilesets especificados no manifesto de recursos. Esse ID é descartado durante a etapa de processamento e é usado apenas para vincular um conjunto de blocos a uma faixa. A string vazia é um ID válido.
tilesets[i].crs
string
O sistema de referência de coordenadas da grade de pixels, especificado como um código padrão, sempre que possível (por exemplo, código EPSG), ou no formato WKT.
tilesets[i].sources
list
Uma lista de dicionários que definem as propriedades de um arquivo de imagem e
os sidecars dele. Consulte os campos de elemento do dicionário sources
a seguir
para mais informações.
tilesets[i].sources[j].uris
list
Uma lista dos URIs dos dados a serem transferidos. Somente URIs do Google Cloud Storage
são aceitos. Cada URI precisa ser especificado no seguinte formato:
gs://bucket-id/object-id
.
O objeto principal precisa ser o primeiro elemento da lista, e os sidecars
precisam ser listados depois. Cada URI é prefixado com
ImageManifest.uriPrefix
, se definido.
tilesets[i].sources[j].affineTransform
dictionary
Uma transformação afín opcional. Só deve ser especificado se os dados de
uris
(incluindo sidecars) não forem suficientes para colocar os pixels.
Fornecido como um dicionário com as seguintes chaves:
"scaleX", "shearX", "translateX", "shearY", "scaleY", "translateY".
Consulte
esta referência para mais informações.
Exemplos de chaves e valores:
{ "scaleX": 0.1, "shearX": 0.0, "translateX": -180.0, "shearY": 0.0, "scaleY": -0.1, "translateY": 90.0 }
bandas
list
Uma lista de dicionários que definem as propriedades de uma única banda proveniente de um conjunto de telhas.
A ordem das faixas do recurso é a mesma de bands
.
Consulte os campos de elemento do dicionário bands
a seguir para mais informações.
bands[i].id
string
O ID (nome) da banda.
bands[i].tilesetId
string
O ID do conjunto de blocos correspondente à faixa.
bands[i].tilesetBandIndex
int32
O índice de banda com base em zero do conjunto detileset correspondente à banda.
bands[i].missingData.values
list
Uma lista de valores (tipo duplo) que não representam dados na faixa.
bands[i].pyramidingPolicy
string
A política de pirâmide. Consulte este link para mais informações. As opções incluem:
- "MÉDIA" (padrão)
- "MODO"
- "SAMPLE"
maskBands
list
Uma lista de dicionários que definem as propriedades de uma única banda de máscara proveniente de um conjunto de telhas.
É possível fornecer no máximo uma faixa de máscara.
Consulte os campos de elemento do dicionário maskBands
a seguir para mais informações.
maskBands[i].tilesetId
string
O ID do conjunto de telhas correspondente à faixa de máscara. A última faixa do conjunto de blocos é sempre usada como a faixa de máscara.
maskBands[i].bandIds
list of strings
Lista dos IDs das faixas a que a faixa de máscara se aplica. Se estiver vazio, a faixa de máscara será aplicada a todas as faixas no recurso. Cada banda só pode ter uma banda de máscara correspondente.
pegada
dictionary
Um dicionário que define as propriedades da pegada de todos os pixels válidos em uma imagem.
Se estiver vazio, o espaço ocupado padrão será a imagem inteira. Consulte os campos de elemento do dicionário footprint
a seguir para mais informações.
footprint.points
list
Uma lista de pontos que definem a pegada de todos os pixels válidos em uma imagem. Um ponto
é definido por um dicionário com chaves "x" e "y" que têm valores flutuantes. Uma lista de
pontos é usada para descrever um anel que forma o exterior de um polígono simples que precisa conter
os centros de todos os pixels válidos da imagem. Precisa ser um anel linear: o último ponto precisa ser igual ao primeiro. As coordenadas estão na projeção da
banda especificada por bandId
.
Observação: use coordenadas não inteiras, como o centro de cada pixel, porque
footprint
é usado para incluir um pixel se ele (um retângulo 1x1)
cruzar a pegada. Para evitar a seleção acidental de pixels
vizinhos, não use coordenadas com valores inteiros, porque elas são os
limites entre os pixels. Desenhar a pegada ao longo dos centros de pixel
evita a inclusão de pixels indesejados, o que pode causar erros quando os pixels pretendidos
estão adjacentes a um limite do mapa, como o antimeridiano ou um pólo.
Por exemplo, para uma imagem de 2 x 2 com os quatro pixels válidos, o seguinte é um anel possível:
[ { "x": 0.5, "y": 0.5 }, { "x": 0.5, "y": 1.5 }, { "x": 1.5, "y": 1.5 }, { "x": 1.5, "y": 0.5 }, { "x": 0.5, "y": 0.5 } ]
footprint.bandId
string
O ID da faixa cujo CRS define as coordenadas da pegada. Se estiver vazio, a primeira faixa será usada.
missingData.values
list
Uma lista de valores (tipo duplo) que não representam dados em todas as bandas da imagem. Aplicável a
todas as bandas que não especificam o próprio missingData
.
pyramidingPolicy
string
A política de pirâmide. Se não for especificado, a política "MEAN" será aplicada por padrão. Aplicável a todas as faixas que não especificam as próprias. Consulte este link para mais informações. As opções incluem:
- "MÉDIA" (padrão)
- "MODO"
- "SAMPLE"
uriPrefix
string
Um prefixo opcional adicionado a todos os uris
definidos no manifesto.
startTime
integer
O carimbo de data/hora associado ao recurso, se houver. Isso geralmente corresponde ao momento em que uma imagem de satélite foi tirada. Para recursos que correspondem a um intervalo de tempo, como valores médios em um mês ou ano, esse carimbo de data/hora corresponde ao início desse intervalo. Especificado como segundos e (opcionalmente) nanossegundos desde o início da época (1970-01-01). Supõe-se que esteja no fuso horário UTC.
endTime
integer
Para recursos que correspondem a um intervalo de tempo, como valores médios ao longo de um mês ou ano, esse carimbo de data/hora corresponde ao fim desse intervalo (exclusivo). Especificado como segundos e (opcionalmente) nanossegundos desde o início da época (1970-01-01). Supõe-se que esteja no fuso horário UTC.
properties
dictionary
Um dicionário plano arbitrário de pares de chave-valor. As chaves precisam ser strings, e os valores podem ser números ou strings. Os valores de lista ainda não são compatíveis com recursos enviados pelo usuário.
Limitações
Tamanho do manifesto JSON
O limite de tamanho do arquivo de manifesto JSON é de 10 MB. Se você tiver muitos arquivos para fazer upload,
considere maneiras de reduzir o número de caracteres necessários para descrever o conjunto de dados. Por exemplo,
use o campo uriPrefix
para eliminar
a necessidade de fornecer o caminho do bucket do Google Cloud para cada URI na
uris
. Se for necessário reduzir ainda mais o tamanho, tente encurtar os nomes dos arquivos.
Formato do arquivo de imagem
Cada arquivo de imagem precisa ser TIFF. Se o CRS não for especificado no manifesto, o arquivo precisará ser um GeoTIFF com um CRS incorporado.
Os arquivos TIFF podem ser compactados com DEFLATE, JPEG-XL/JXL, LERC, LERC_DEFLATE, LERC_ZSTD, LZMA, LZW, WEBP ou ZSTD.
Recomendações para a melhor experiência de upload de arquivos grandes:
- Melhor escolha:o ZSTD oferece um bom equilíbrio entre velocidade e compactação.
- Evite:a LZMA pode ser muito lenta, apesar da boa compactação.
- Arquivos descompactados:resultam em arquivos maiores e em tempos de upload mais longos.
- Compressão com perdas (por exemplo, JPEG: pode alterar os valores dos pixels. Use compactação sem perdas (por exemplo, DEFLATE, LZMA, LZW, ZSTD) a menos que você entenda o possível impacto nos seus dados.