行业资讯
GEE云端调用GlobeLand30土地覆盖数据:从本地处理到时空分析实战
1. 项目缘起为什么我们需要一个整理好的GEE土地覆盖数据集如果你正在做国土空间规划、生态环境评估、或者任何与地表变化相关的研究手头有一个现成的、长时间序列的、可以直接在云端调用的土地覆盖数据集那感觉就像在沙漠里找到了绿洲。我最近在做一个关于中国城市扩张对周边农田影响的课题核心需求就是分析过去三十年全国尺度的土地覆盖变化。理论上中国有多套权威的土地覆盖产品比如GlobeLand30、FROM-GLC等它们都提供了1990年以来的30米分辨率数据精度和权威性都没得说。但实际操作起来问题就来了。这些数据通常以分幅的GeoTIFF文件形式发布动辄几十个GB甚至上百GB。下载、拼接、投影转换、格式统一……这套流程走下来不仅对本地计算资源是巨大考验更耗时耗力。往往数据还没处理完研究的热情就先被磨掉了一半。更重要的是当你想快速验证一个想法或者进行大范围的时空分析时这种基于本地文件的模式显得笨重且不灵活。就在这时Google Earth EngineGEE进入了视野。GEE是一个强大的云端地理空间数据处理平台它托管了海量的遥感数据集并提供了在云端进行并行计算的能力。理想情况下如果这些权威的土地覆盖数据集能直接在GEE中调用我们就能跳过繁琐的数据准备阶段直接进入分析环节效率会有质的飞跃。然而现实是骨感的。虽然GEE数据目录里有一些全球土地覆盖产品但针对中国区域、长时间序列、且基于国内权威数据源的数据集并没有一个现成的、整理好的“产品”。你需要自己去寻找原始数据源理解其数据结构编写代码将其导入到GEE的资产Assets中并处理好时间、波段、属性等元数据。这个过程对于GEE新手甚至是有一定经验但非地信专业的研究者来说门槛相当高。正是基于这个普遍的痛点我决定动手整理。这个项目的目标非常明确将中国1990-2022年逐年30米土地覆盖数据集以广泛使用的GlobeLand30为例整理并发布为GEE可调用的资产并提供清晰、完整的调用代码示例。让后来者无论是学生、研究员还是工程师都能通过复制粘贴几行代码立刻获取并分析这套宝贵的数据把时间和精力真正花在科学问题上而不是数据工程的泥潭里。2. 数据基石理解GlobeLand30及其在GEE中的呈现逻辑在开始写代码之前我们必须先吃透我们要处理的数据本身。我选择以GlobeLand30全球30米地表覆盖数据作为核心数据源进行整理这是目前国内最主流、应用最广泛的30米土地覆盖产品之一。它由我国牵头制作涵盖了1990、2000、2010、2020等基准年份部分版本有逐年数据包含耕地、森林、草地、灌木地、湿地、水体、苔原、人造地表、裸地、冰川和永久积雪等10个一级类型。2.1 GlobeLand30的数据特点与挑战GlobeLand30的官方数据以分幅的GeoTIFF文件提供通常按经纬度网格如10°×10°分块。对于中国全境大概需要下载几十个文件。在GEE中直接使用这些原始文件是不现实的我们需要将它们“搬”到云端。这里有几个关键点需要处理数据拼接GEE的ImageCollection可以看作是一个云端影像栈。我们需要将每一年的所有分幅数据在GEE内拼接成一幅覆盖中国区域的完整影像。GEE的mosaic()方法可以自动处理重叠区域通常我们选择后传入的像素值覆盖先传入的或者指定合并规则。波段与属性原始的GlobeLand30 TIFF文件通常只有一个波段像素值即土地覆盖分类代码如10代表耕地20代表森林。在导入GEE时我们需要将这个波段命名例如‘landcover’并为整个影像设置关键属性最核心的就是‘system:time_start’。GEE的强大之处在于其时间序列分析能力为影像设置正确的获取时间是后续按时间筛选的基础。例如1990年的数据其system:time_start应设置为ee.Date(‘1990-01-01’)。投影与尺度GlobeLand30采用地理坐标系WGS84。在GEE中处理时需要注意输出时的投影和尺度scale设置特别是在进行统计如reduceRegion时明确的尺度参数如scale: 30能保证统计结果的准确性。数据量与管理将多年份、全国范围的数据导入个人GEE资产会占用你的资产配额。虽然GEE提供免费的存储额度但对于超大数据集仍需合理规划。一种高效的方式是每年数据存储为一个Image资产而不是一个包含所有年份的ImageCollection资产这样在代码中按需组合成ImageCollection更加灵活。2.2 在GEE中构建数据集的策略我的整理策略如下按年份组织为1990、2000、2010、2020等每个年份创建一个独立的GEEImage资产命名为GlobeLand30_1990GlobeLand30_2000等。统一属性为每个Image设置一致的波段名‘landcover’和土地覆盖分类代码的‘class_values’、‘class_palette’用于可视化属性。代码化调用编写一个辅助函数用户只需指定年份函数内部就返回对应的Image或者将所有年份的Image组合成一个ImageCollection。这样用户无需关心数据存储在GEE的哪个具体路径只需调用一个干净的接口。注意由于数据版权和共享政策我无法直接将我处理好的GEE资产公开分享给所有人。本项目的核心产出是完整的、可复现的数据处理与导入GEE的代码流程以及调用这些数据进行分析的示例代码。你可以按照我的流程使用你已合法下载的GlobeLand30数据在你自己GEE账户中创建私有资产或者寻找已获得授权在GEE中共享的同类数据集。3. 从本地到云端数据预处理与GEE资产上传全流程假设你已经从GlobeLand30官网或其他合法渠道下载了1990-2020或2022各年份的中国区域分幅数据。接下来我们将一步步把它们变成GEE里的Image。3.1 本地预处理可选但推荐为了上传过程更顺畅可以在本地对数据做轻度预处理检查与合并确保同一年的所有分幅数据具有相同的坐标系WGS84、相同的分类体系。可以使用GDALgdal_merge.py或gdalwarp在本地先将它们拼接成一张中国区域的大图。这样做的好处是上传到GEE的文件数量大大减少管理更方便。命令示例如下gdalwarp -t_srs EPSG:4326 input1.tif input2.tif ... output_merged_1990.tif这条命令将多个输入文件合并并统一到WGS84坐标系。压缩使用LZW或DEFLATE等无损压缩方式压缩TIFF文件可以显著减小文件体积加快上传速度。重命名将处理好的文件按年份清晰命名如China_GlobeLand30_1990.tif。3.2 GEE资产上传的两种路径GEE提供了多种数据上传方式对于这种批量、大文件的操作我强烈推荐使用命令行工具earthengine。方法一使用GEE Python API上传适合自动化脚本首先确保你已安装GEE Python API (earthengine-api) 并完成了身份验证 (earthengine authenticate)。import ee import subprocess import os # 初始化GEE API ee.Initialize() # 设置本地数据文件夹和GEE资产路径 local_dir ‘/path/to/your/gl30_data/’ gee_asset_path ‘projects/your-project-name/assets/GlobeLand30/’ # 遍历本地文件 for filename in os.listdir(local_dir): if filename.endswith(‘.tif’) and ‘China’ in filename: # 从文件名提取年份例如 ‘China_GlobeLand30_1990.tif‘ - 1990 year filename.split(‘_’)[-1].split(‘.’)[0] local_file os.path.join(local_dir, filename) asset_id gee_asset_path ‘China_GL30_’ year # 构建earthengine上传命令 cmd [ ‘earthengine’, ‘upload’, ‘image’, ‘--asset_id’, asset_id, ‘--pyramiding_policy’, ‘MODE’, # 对分类数据金字塔采用众数采样 ‘--time_start’, f‘{year}-01-01’, # 设置影像时间属性 local_file ] # 执行上传命令 print(f‘Uploading {filename} to {asset_id}...’) subprocess.run(cmd) print(f‘Upload task started for {filename}. Check status with ‘earthengine task list‘.’)这段代码会自动遍历文件夹下的TIFF文件提取年份并为每个文件发起一个上传任务。--pyramiding_policy MODE参数至关重要它指定在生成金字塔多尺度预览时对分类数据采用“众数”算法避免出现无效的混合像元值。方法二直接使用earthengine命令行如果你更喜欢手动控制可以对每个文件执行类似命令earthengine upload image \ --asset_idprojects/your-project/assets/GlobeLand30/China_GL30_1990 \ --pyramiding_policyMODE \ --time_start1990-01-01 \ /path/to/China_GlobeLand30_1990.tif3.3 上传后处理与属性设置文件上传完成后在GEE代码编辑器中我们还需要为这些Image资产设置更丰富的属性以便于调用。这步必须在GEE的JavaScript或Python API代码中完成。// 假设我们已经将1990年数据上传到了 ‘projects/your-project/assets/GlobeLand30/China_GL30_1990‘ var image1990 ee.Image(‘projects/your-project/assets/GlobeLand30/China_GL30_1990‘); // 定义GlobeLand30的分类代码和对应的颜色 var classValues [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]; var classNames [‘Cropland‘, ‘Forest‘, ‘Grassland‘, ‘Shrubland‘, ‘Wetland‘, ‘Water‘, ‘Tundra‘, ‘Artificial Surface‘, ‘Bareland‘, ‘Permanent Snow/Ice‘]; var classPalette [‘#FFFF00‘, ‘#008000‘, ‘#00FF00‘, ‘#00A000‘, ‘#00FFFF‘, ‘#0000FF‘, ‘#AAAAFF‘, ‘#FF0000‘, ‘#C0C0C0‘, ‘#FFFFFF‘]; // 为影像设置属性 image1990 image1990 .rename(‘landcover‘) // 将波段重命名为‘landcover‘ .set({ ‘landcover_class_values‘: classValues, ‘landcover_class_names‘: classNames, ‘landcover_class_palette‘: classPalette, ‘system:time_start‘: ee.Date(‘1990-01-01‘), // 确保时间已设置 ‘dataset‘: ‘GlobeLand30‘, ‘version‘: ‘v2020‘, ‘resolution‘: 30 }); // 最后将处理好的影像重新导出到资产覆盖原资产或保存为新资产。 Export.image.toAsset({ image: image1990, description: ‘GlobeLand30_1990_Final‘, assetId: ‘projects/your-project/assets/GlobeLand30_Final/GL30_1990‘, region: image1990.geometry(), // 指定区域 scale: 30, maxPixels: 1e13 });这个过程需要对每个年份的影像执行一次。虽然繁琐但一劳永逸。完成后你就拥有了一个属性完善、可直接用于分析的GEE土地覆盖资产库。4. GEE调用实战封装与典型应用场景分析当所有年份的数据都规整地成为GEE资产后真正的乐趣就开始了。我们可以像搭积木一样快速构建各种分析。下面分享几个最常用的调用模式和场景。4.1 数据调用封装首先我们创建一个方便的调用函数避免每次重复写资产路径。// 定义一个函数根据年份返回对应的GlobeLand30影像 function getGlobeLand30(year) { // 基础资产路径根据你的实际位置修改 var baseAssetPath ‘projects/your-project/assets/GlobeLand30_Final/GL30_‘; var assetId baseAssetPath year; var image ee.Image(assetId); // 确保影像有我们设置的属性如果没有可以在这里补设 image image .rename(‘landcover‘) .set(‘system:time_start‘, ee.Date(year ‘-01-01‘)); return image; } // 示例获取1990、2000、2010、2020年的影像并组成一个ImageCollection var years [‘1990‘, ‘2000‘, ‘2010‘, ‘2020‘]; var landcoverCollection ee.ImageCollection(years.map(getGlobeLand30)); print(‘Landcover Collection:‘, landcoverCollection); // 可视化单一年份 var visParams { bands: [‘landcover‘], min: 10, max: 100, palette: getGlobeLand30(‘1990‘).get(‘landcover_class_palette‘).getInfo() // 获取颜色盘 }; Map.centerObject(ee.Geometry.Point([116.4, 39.9]), 6); // 定位到北京 Map.addLayer(getGlobeLand30(‘2020‘), visParams, ‘GlobeLand30 2020‘);4.2 应用场景一土地利用变化检测Transition Matrix计算两个年份之间土地类型转移矩阵是变化检测的核心。// 计算1990-2020土地覆盖转移矩阵 var lc1990 getGlobeLand30(‘1990‘).select(‘landcover‘); var lc2020 getGlobeLand30(‘2020‘).select(‘landcover‘); // 将两个年份的代码组合成一个双位数代码 // 公式oldClass * 1000 newClass (假设类别代码1000) var changeCode lc1990.multiply(1000).add(lc2020); // 定义一个区域例如京津冀边界 var roi ee.FeatureCollection(‘TIGER/2018/States‘) .filter(ee.Filter.inList(‘NAME‘, [‘Beijing‘, ‘Tianjin‘, ‘Hebei‘])); // 统计转移矩阵 var changeStats changeCode.reduceRegion({ reducer: ee.Reducer.frequencyHistogram(), geometry: roi.geometry(), scale: 1000, // 使用1km尺度进行统计以加快速度可根据精度要求调整 maxPixels: 1e13 }); print(‘土地利用转移统计部分:‘, changeStats); // 输出结果是一个字典键是‘old_new‘组合码值是该变化发生的像元数。 // 需要后续将代码解析回类别名称并整理成矩阵表格。4.3 应用场景二特定地类面积时空变化分析分析过去30年全国或特定区域耕地、森林、建设用地的面积变化。// 分析ROI内人造地表代码80的面积变化 var roi ee.Geometry.Rectangle([110, 20, 125, 45]); // 示例中国东部区域 // 定义一个函数用于计算单景影像中某类别的面积 function calculateArea(image, classValue, scale) { var areaImage image.eq(classValue) // 等于目标类别的像素变为1否则为0 .multiply(ee.Image.pixelArea()) // 乘以每个像素的面积平方米 .divide(10000); // 转换为公顷 var areaStats areaImage.reduceRegion({ reducer: ee.Reducer.sum(), geometry: roi, scale: scale, maxPixels: 1e13, bestEffort: true // 如果像素过多尝试近似计算 }); return ee.Number(areaStats.get(‘landcover‘)).getInfo(); // 返回面积值 } // 遍历年份进行计算 var artificialSurfaceArea []; years.forEach(function(year) { var img getGlobeLand30(year); var area calculateArea(img, 80, 300); // 使用300米尺度统计平衡精度与速度 artificialSurfaceArea.push({year: year, area_ha: area}); print(‘Year ‘ year ‘, Artificial Surface Area (ha): ‘ area); }); // 结果可以导出到Google Drive或用图表显示4.4 应用场景三与其它遥感数据联动分析GEE的强大之处在于数据融合。我们可以轻松地将土地覆盖数据与夜间灯光数据NPP/VIIRS、植被指数NDVI、气象数据等结合。// 示例分析2020年不同土地覆盖类型上的平均NDVI使用MODIS数据 var lc2020 getGlobeLand30(‘2020‘); var ndvi2020 ee.ImageCollection(‘MODIS/006/MOD13A1‘) .filterDate(‘2020-06-01‘, ‘2020-08-01‘) .select(‘NDVI‘) .mean(); // 计算夏季平均NDVI // 使用土地覆盖数据作为分区分区统计NDVI var ndviByClass ndvi2020.addBands(lc2020.select(‘landcover‘)) .reduceRegion({ reducer: ee.Reducer.mean().group({ groupField: 1, // 按第二个波段landcover分组 groupName: ‘landcover_class‘ }), geometry: roi, scale: 500, // MODIS NDVI尺度 maxPixels: 1e13 }); print(‘不同土地覆盖类型的平均NDVI:‘, ndviByClass);5. 避坑指南与性能优化心得在整理和调用这套数据的过程中我踩过不少坑也总结出一些优化技巧希望能帮你节省时间。5.1 数据上传与管理的坑坑1上传任务失败或卡住。GEE上传大文件有时会因网络不稳定或服务器端问题失败。对策使用earthengine task list和earthengine task cancel [TASK_ID]管理任务。对于失败的任务可以尝试重新上传。更稳妥的做法是将大文件分割成稍小的块如按省份分别上传再在GEE内拼接。坑2资产权限混乱。如果你在团队中协作资产权限设置不当会导致他人无法访问。对策在GEE代码编辑器的“Assets”选项卡中清晰地为文件夹和资产设置共享权限。对于公开项目可以考虑将最终处理好的资产发布为公开数据集需遵守数据许可协议。坑3属性丢失。通过命令行上传的影像在GEE中可能缺少我们在代码中设置的system:time_start等属性。对策如3.3节所示上传原始数据后务必运行一个“后处理”脚本将属性设置好并重新导出为最终资产。原始上传资产可以作为“原材料”保留。5.2 计算性能与精度平衡挑战1全国尺度统计耗时过长。对30米分辨率数据做全国范围的reduceRegion像素量巨大极易超时或超出内存限制。对策降低统计尺度如示例中将scale参数设为1000或更大虽然损失了细节但能极大提升速度适用于宏观趋势分析。使用bestEffort: true让GEE在超限时尝试返回一个近似结果。分区域统计将全国按省或流域分区循环计算后再汇总。可以使用ee.FeatureCollection的iterate方法或map函数。导出结果对于极其复杂的计算更好的方式是Export.table.toDrive或Export.image.toDrive将中间或最终结果导出到Google Drive然后在本地分析。挑战2可视化渲染慢。在地图上加载全国30米土地覆盖前端渲染压力大。对策GEE会自动使用金字塔Pyramid进行多尺度显示。确保上传时设置了正确的pyramiding_policy分类数据用MODE。在代码中也可以使用.reproject()或.reduceResolution()在显示前主动降低分辨率。5.3 代码健壮性与可复用性心得1封装与模块化。如4.1节所示将数据获取逻辑封装成函数getGlobeLand30(year)极大提高了代码的清晰度和复用性。你可以进一步封装变化检测、面积统计等常用功能为函数。心得2善用print和Chart调试。在开发复杂分析时多用print()输出中间变量的属性、大小。使用ui.Chart系列函数快速绘制时间序列或统计图表直观验证分析逻辑是否正确。心得3理解GEE的“延迟执行”。GEE的代码是生成一个处理任务链直到遇到print、Map.addLayer或Export等需要输出结果的操作时才会真正发送到服务器执行。这意味着你不能用传统的JavaScript思维进行for循环和条件判断。所有针对ee.ObjectImage,FeatureCollection等的操作都必须使用GEE提供的客户端函数如ee.List.sequence,iterate,map。最后我想说的是整理这套数据集的初衷是为了“偷懒”——让后续的分析工作更便捷。虽然前期投入了时间在数据上传和属性整理上但看到后来能用寥寥数行代码完成过去需要数天数据准备才能开始的分析这种效率的提升是实实在在的。GEE的学习曲线确实存在但一旦掌握了它的核心思想客户端与服务器端分离、延迟执行、面向对象的数据模型它就会成为你进行大规模地理空间分析不可或缺的利器。希望这份整理和分享能成为你打开GEE和长时间序列土地覆盖分析大门的一把钥匙。
郑州网站建设
网页设计
企业官网