如果您需要比代码编辑器界面或 “earthengine”命令行工具的 upload 命令更灵活地将图片上传到 Google Earth Engine (EE),可以使用名为“清单”的 JSON 文件描述图片上传,并使用命令行工具的 upload image --manifest 命令。
如需查看已完成示例,请参阅此 Colab 笔记本,其中演示了如何使用清单将图片图块作为单个素材资源上传。
一次性设置
- 清单上传仅适用于位于 Google Cloud Storage 中的文件。 如需开始使用 Google Cloud Storage,请创建 Google Cloud 项目(如果您还没有)。请注意,设置时需要指定用于结算的信用卡。EE 本身目前不收取任何费用,但在将文件上传到 EE 之前,将其转移到 Google Cloud Storage 会产生少量费用。对于典型的上传数据大小(数十或数百 GB),费用会非常低。
- 在项目中,启用 Cloud Storage API 并创建存储桶。
- 安装 Earth Engine Python 客户端。它包含
earthengine命令行工具,我们将使用该工具上传数据。 - 对于自动上传,您可能需要使用与项目关联的 Google Cloud 服务账号。您无需使用服务账号进行测试,但有时间的话,请开始熟悉如何使用服务账号。
如果将非常大的源文件(100 GB 或更大)拆分为多个图块,则上传速度可能会更快。
资产 ID 和名称
对于云项目拥有的资产,请使用以下资产名称命名惯例:projects/some-project-id/assets/some-asset-id。
了解旧版项目和用户拥有的资产的资产名称
对于较旧的旧版项目,清单中的资产名称需要与 Earth Engine 中其他位置显示的资产 ID 略有不同。如需上传资产 ID 以 users/some_user 或 projects/some_project 开头的资产,清单中的资产名称必须在 ID 前面加上字符串 projects/earthengine-legacy/assets/。例如,应使用名称 projects/earthengine-legacy/assets/users/username/my_geotiff 上传 EE 资产 ID users/username/my_geotiff。
是的,这意味着像 projects/some_projects/some_asset 这样的 ID 会转换为提及 projects 两次的名称:projects/earthengine-legacy/assets/projects/some_projects/some_asset。
这虽然令人困惑,但却是符合 Google Cloud API 标准所必需的。
使用清单
以下代码块中显示了一个基本清单。它会从名为 gs://earthengine-test 的 Google Cloud Storage 存储桶上传名为 small.tif 的文件。
{
"name": "projects/some-project-id/assets/some-asset-id",
"tilesets": [
{
"sources": [
{
"uris": [
"gs://earthengine-test/small.tif"
]
}
]
}
]
}如需使用该脚本,请将其保存到名为 manifest.json 的文件中,然后运行:
earthengine upload image --manifest /path/to/manifest.json
(文件 gs://earthengine-test/small.tif 存在且可公开读取,您可以将其用于测试。)
Tileset
JSON 的清单结构有些复杂,但这是必要的,因为这样才能提供足够的灵活性,以应对常见的上传难题:如何描述将多个源文件中的像素组合成单个素材资源的所有可能方式。具体而言,有两种独立的文件分组方式:
- 马赛克。有时,多个文件代表多个图块(例如,每个图块是一个 1x1 度的正方形)。此类文件必须拼接(合并在一起)到 EE 资产中的同一波段。
- 分离式表带。有时,多个文件代表多个波段。此类文件必须堆叠在一起,作为 EE 资产中的波段。
(可能需要同时使用这两种方式,但这种情况很少见。)
为了描述这些选项,清单引入了图块集的概念。单个图块集对应于单个 GDAL 来源。 因此,单个图块集中的所有来源都必须具有相同的 GDAL 结构(波段的数量和类型、投影、转换、缺失值)。由于 GDAL 来源可以有多个波段,因此一个图块集可能包含多个 EE 波段的数据。
对于马赛克提取,清单将如下所示:
{
"name": "projects/some-project-id/assets/some-asset-id",
"tilesets": [
{
"sources": [
{
"uris": [
"gs://bucket/N30W22.tif"
]
},
{
"uris": [
"gs://bucket/N31W22.tif"
]
}
]
}
]
}对于单独的频段,清单将如下所示(您还需要添加 bands 部分,如下所述):
{
"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"
]
}
]
}
]
}请注意,在单独波段的情况下,我们必须为每个图块集指定不同的图块集 ID,为清晰起见。图块集 ID 可以是任意字符串,这些字符串不会保留在上传的素材资源中。图块集 ID 仅在提取过程中用于区分堆叠的图块集。
频段
第二个重要概念是将源文件与 EE 资产波段进行匹配。
这是通过清单的 bands 部分完成的。
bands 部分可以省略,在这种情况下,系统会先根据第一个图块集中的文件创建波段,然后根据下一个图块集中的文件创建波段,依此类推。
默认情况下,波段名称为“b1”“b2”等。如需替换默认波段名称,请在末尾添加“bands”部分,如下所示:
{
"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
}
]
}EE 波段的数量必须与所有图块集中的波段总数相同。
如果您不想提取文件中的所有波段,可以使用 tilesetBandIndex 字段来指明应提取哪些 GDAL 波段。
第一个波段的 tilesetBandIndex 为 0。
示例:
假设源文件有四个波段:“tmin”“tmin_error”“tmax”“tmax_error”。我们只想提取“tmin”和“tmax”。相关清单部分将如下所示:
{
"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"
}
]
}口罩带
频段屏蔽由清单的 maskBands 组件控制。
支持三种可能的掩膜配置(但始终假定掩膜波段是特定文件中的最后一个波段)。
- 同一文件中所有数据波段的掩膜。
- 来自所有其他文件的所有数据波段的掩膜。
- 遮盖部分数据频段。
1. 最常见的情况是单个 GeoTIFF,其最后一个波段用作其他波段的遮罩。此方法仅适用于 Byte 类型的 GeoTIFF。使用以下清单:
{
"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. 如需将一个遮罩 GeoTIFF 用作另一个 GeoTIFF 中所有波段的遮罩,请使用以下清单:
{
"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. 如需将 GeoTIFF 用作另一个文件中特定波段的遮罩,请使用以下清单(与上一个情况的区别在于设置了 maskBands 中的 bandIds 字段):
{
"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"]
}
]
}在最后一个示例中,我们使用了 data_tileset 图块集中的两个波段,但仅对其中一个波段 (data_band) 应用了遮罩,如唯一提供的 maskBands 列表对象的 bandIds 字段所指定。
请注意,只有 maskBands 中提及的图块集的最后一个波段用作遮罩波段。
金字塔式销售政策
当 Earth Engine 在提取期间构建图片金字塔时,它必须反复将 2x2 像素网格缩减为单个像素,并以某种方式转换像素值。默认情况下,系统会计算像素值的平均值,在大多数情况下,当栅格波段表示或多或少连续的数据时,这样做是正确的。不过,在以下两种情况下,依赖默认值会产生不正确的结果,此时必须设置波段定义中的 pyramidingPolicy 字段(如果未设置,则默认其值为“MEAN”)。
对于光栅图像的分类(例如土地覆盖分类),最合理的像素金字塔化方法是取四个值中的多数值来生成下一个值。这可以通过使用“MODE”金字塔政策来实现:
{
"name": "projects/earthengine-legacy/assets/users/username/some_folder/some_id",
"tilesets": [
{
"sources": [
{
"uris": [
"gs://bucket/landcover.tif"
]
}
]
}
],
"bands": [
{
"id": "landcover",
"pyramidingPolicy": "MODE"
}
]
}对于“MEAN”和“MODE”都不适用的栅格波段(例如,位打包像素),应使用“SAMPLE”金字塔政策。“SAMPLE”始终采用每个 2x2 网格中左上角像素的值。以下示例将“MEAN”金字塔政策分配给表示连续变量(“NDVI”)的波段,并将“SAMPLE”分配给数据的“QA”波段。
{
"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"
}
]
}开始时间和结束时间
所有资产都应指定开始时间和结束时间,以便为数据提供更多背景信息,尤其是在将资产纳入集合时。这些字段并非必填字段,但我们强烈建议您尽可能使用它们。
开始时间和结束时间通常是指观测时间,而不是源文件的生成时间。
为简单起见,结束时间被视为不包含在内的边界。例如,对于正好跨越一天的资产,请使用连续两天的午夜(例如 1980-01-31T00:00:00 和 1980-02-01T00:00:00)作为开始时间和结束时间。如果资产没有时长,请将结束时间设置为与开始时间相同。 将清单中的时间表示为 ISO 8601 字符串。我们建议您假设结束时间不包含在内(例如,对于每日资产,结束时间为第二天的午夜),以简化日期值。
示例:
{
"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"
}清单结构参考
以下 JSON 结构包含所有可能的图片上传清单字段。 如需查看字段定义,请参阅下文中的清单字段定义部分。
{ "name": <string>, "tilesets": [ { "dataType": <string>, "id": <string>, "crs": <string>, "sources": [ { "uris": [ <stringn>> ], "affineTransform": { "scaleX": <double>, "shearX": <double>, "translateX": <double>, "shearY": <double>, "scaleY": <double>, "translateY": <double> } } ] } ], "bands": [ { "id": <string>, "tilesetId": <string>, "tilesetBandIndex": <int32>, "missingData": { "values": [<doublen>>] }, "pyramindingPolicy": <string> } ], "maskBands": [ { "tilesetId": <string>, "bandIds": [ <stringn>> ] } ], "footprint": { "points": [ { "x": <double>, "y": <doublen>> } ], "bandId": <string> }, "missingData": { "values": [<double>] }, "pyramidingPolicy": <string>, "uriPrefix": <string>, "startTime": { "seconds": <integer> }, "endTime": { "seconds": <integer> }, "properties": { <unspecified> } }
清单字段定义
name
string
要创建的素材资源的名称。
name 的格式为“projects/*/assets/**”(例如,“projects/earthengine-legacy/assets/users/USER/ASSET”)。
tilesets
list
用于定义图块集属性的字典列表。
如需了解详情,请参阅以下 tilesets 字典元素字段。
tilesets[i].dataType
string
指定数据的数值数据类型。默认值为 GDAL 报告的类型,在这种情况下,无需定义。
| 数据类型 | 值 |
|---|---|
| 未指定 | "DATA_TYPE_UNSPECIFIED" |
| 8 位有符号整数 | "INT8" |
| 8 位无符号整数 | "UINT8" |
| 16 位有符号整数 | "INT16" |
| 16 位无符号整数 | "UINT16" |
| 32 位有符号整数 | "INT32" |
| 32 位无符号整数 | "UINT32" |
| 32 位浮点数 | "FLOAT32" |
| 64 位浮点数 | "FLOAT64" |
tilesets[i].id
string
图块集的 ID。在资源清单中指定的图块集中必须是唯一的。此 ID 会在处理步骤中被舍弃;它仅用于将图块集关联到波段。空字符串是有效 ID。
tilesets[i].crs
string
像素网格的坐标参考系统,尽可能指定为标准代码(例如 EPSG 代码),否则指定为 WKT 格式。
tilesets[i].sources
list
一个字典列表,用于定义图片文件及其附属文件的属性。如需了解详情,请参阅以下 sources 字典元素字段。
tilesets[i].sources[j].uris
list
要注入的数据的 URI 列表。仅支持 Google Cloud Storage URI。每个 URI 都必须采用以下格式指定:gs://bucket-id/object-id。
主对象应是列表中的第一个元素,边车列在后面。每个 URI 都以 ImageManifest.uriPrefix 为前缀(如果已设置)。
tilesets[i].sources[j].affineTransform
dictionary
可选的仿射变换。仅当 uris 中的数据(包括任何边车)不足以放置像素时,才应指定。
以字典形式提供,包含以下键:“scaleX”“shearX”“translateX”“shearY”“scaleY”“translateY”。
如需了解详情,请参阅此参考文档。
键和值示例:
{
"scaleX": 0.1,
"shearX": 0.0,
"translateX": -180.0,
"shearY": 0.0,
"scaleY": -0.1,
"translateY": 90.0
}腕带
list
一个字典列表,用于定义来自图块集的单个波段的属性。
请注意,素材资源的波段顺序与 bands 的顺序相同。
如需了解详情,请参阅以下 bands 字典元素字段。
bands[i].id
string
频段的 ID(名称)。
bands[i].tilesetId
string
与波段对应的图块集的 ID。
bands[i].tilesetBandIndex
int32
图块集中与波段对应的波段索引(从零开始)。
bands[i].missingData.values
list
表示波段中无数据的值(双精度类型)列表。
bands[i].pyramidingPolicy
string
金字塔式政策。如需了解详情,请参阅此链接。选项包括:
- “MEAN”(默认)
- "MODE"
- “SAMPLE”
maskBands
list
一个字典列表,用于定义源自图块集的单个遮罩波段的属性。
最多可提供 1 个遮罩波段。
如需了解详情,请参阅以下 maskBands 字典元素字段。
maskBands[i].tilesetId
string
与遮罩波段对应的图块集的 ID。图块集的最后一个波段始终用作遮罩波段。
maskBands[i].bandIds
list of strings
掩膜波段适用的波段 ID 列表。如果留空,则掩膜波段会应用于素材资源中的所有波段。每个波段只能有一个对应的掩膜波段。
足迹
dictionary
一个字典,用于定义图片中所有有效像素的足迹属性。
如果留空,则默认覆盖区为整个图片。如需了解详情,请参阅以下 footprint 字典元素字段。
footprint.points
list
定义图片中所有有效像素的足迹的点列表。点由一个字典定义,其中“x”和“y”键具有浮点值。一系列点用于描述一个环,该环构成一个简单多边形的外部,该多边形必须包含图片的所有有效像素的中心。此元素必须是线性环:最后一个点必须与第一个点相同。坐标位于 bandId 指定的波段的投影中。
注意:请使用非整数坐标(例如每个像素的中心),因为如果像素(1x1 矩形)与覆盖区相交,则 footprint 会被视为包含该像素。为避免意外选择相邻像素,请勿使用整数值坐标,因为这些坐标是像素之间的边界。沿像素中心绘制足迹可防止包含意外像素,当预期像素与地图边界(例如对向子午线或极点)相邻时,这可能会导致错误。
例如,对于具有所有四个有效像素的 2x2 图片,以下是一个可能的环:
[
{
"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
其 CRS 定义了足迹坐标的波段的 ID。 如果为空,则使用第一个波段。
missingData.values
list
一个值列表(双精度类型),表示图片的所有波段中均无数据。适用于未指定自己的 missingData 的所有频段。
pyramidingPolicy
string
金字塔式政策。如果未指定,则默认应用“MEAN”政策。适用于所有未指定自己的频段。 如需了解详情,请参阅此链接。选项包括:
- “MEAN”(默认)
- "MODE"
- “SAMPLE”
uriPrefix
string
一个可选前缀,会附加到清单中定义的所有 uris 之前。
startTime
integer
与资产关联的时间戳(如果有)。这通常对应于卫星图像的拍摄时间。对于对应于某个时间间隔(例如一个月或一年的平均值)的资源,此时间戳对应于该时间间隔的开始时间。指定为自纪元 (1970-01-01) 以来的秒数和(可选)纳秒数。假定采用世界协调时间 (UTC) 时区。
endTime
integer
对于对应于某个时间间隔的资产(例如一个月或一年的平均值),此时间戳对应于该时间间隔的结束时间(不含)。指定为自公元纪年 (1970-01-01) 以来的秒数和(可选)纳秒数。假定采用世界协调时间 (UTC) 时区。
属性
dictionary
由键值对组成的任意平面字典。键必须是字符串,值可以是数字或字符串。用户上传的素材资源尚不支持列表值。
限制
JSON 清单大小
JSON 清单文件大小上限为 10 MB。如果您有许多文件要上传,请考虑如何减少描述数据集所需的字符数。例如,使用 uriPrefix 字段可避免为 uris 列表中的每个 URI 提供 Google Cloud 存储桶路径。如果需要进一步缩减大小,请尝试缩短文件名。
图片文件格式
每个图片文件都必须是 TIFF 图片。如果清单中未指定 CRS,则文件必须是具有嵌入式 CRS 的 GeoTIFF。
TIFF 文件可以使用 DEFLATE、JPEG-XL/JXL、LERC、LERC_DEFLATE、LERC_ZSTD、LZMA、LZW、WEBP 或 ZSTD 进行压缩。
为获得最佳大文件上传体验,建议您:
- 最佳选择:ZSTD 在速度和压缩率之间实现了良好的平衡。
- 避免:LZMA 虽然压缩效果好,但速度可能非常慢。
- 未压缩的文件:会导致文件较大,上传时间较长。
- 有损压缩(例如 JPEG):可能会改变像素值。除非您了解对数据的潜在影响,否则请使用无损压缩(例如 DEFLATE、LZMA、LZW、ZSTD)。