基于 Google Earth Engine 的大规模遥感数据分块导出方法
这段代码是Google Earth EngineGEEJavaScript 端的大范围遥感影像分块批量导出脚本核心目标是解决「新疆全域 30 米 影像直接导出时因数据量过大触发 GEE 内存超限、计算超时」的问题通过规则网格分块 化整为零的策略逐块提交导出任务大幅提升导出成功率。当然也可以是其余区域根据你的shp文件。一、研究区定义模块var xinjiang ee.FeatureCollection(添加你的shp文件路径); var roi_geometry xinjiang.geometry();加载你上传到 GEE 资产Assets中的新疆矢量边界 shp 文件使用时需替换为你自己的 shp 资产路径。.geometry()提取矢量集合的整体几何对象作为后续网格生成、影像裁剪的基准范围。二、多资产数据集合并模块var LandsatComposite ee.ImageCollection(projects/forest-image-china/assets/China_Landsat_Yearly); // 循环合并2~14号资产库 for (var i 2; i 15; i){ LandsatComposite LandsatComposite.merge(ee.ImageCollection(projects/forest-image-chinai/assets/China_Landsat_Yearly)); } // 循环合并16~33号资产库 for (var i 16; i 34; i){ LandsatComposite LandsatComposite.merge(ee.ImageCollection(projects/forest-image-chinai/assets/China_Landsat_Yearly)); } // 链式合并剩余零散资产库 LandsatComposite LandsatComposite .merge(ee.ImageCollection(projects/ee-caiyt33-chinalandsatyearly/assets/China_Landsat_Yearly)) .merge(ee.ImageCollection(projects/ee-caiyt33-chinalandsatyearly1/assets/China_Landsat_Yearly)) // ... 剩余多个merge背景原因GEE 单个资产仓库有存储容量上限因此「中国区域 Landsat 年度合成数据集」被拆分存储到了 30 个不同的项目资产路径中。这段代码通过for循环 链式merge方法将所有分散存储的China_Landsat_Yearly影像集合并为一个完整的、可统一筛选的影像集合。循环中跳过了i15是因为原始数据不存在 15 号资产库属于数据本身的编号断层。三、规则网格分块生成var crs EPSG:4326; // 投影坐标系WGS84地理坐标系 var pixelSize 30; // 影像空间分辨率Landsat为30米 var rows 3; // 网格行数把研究区分成3行 var cols 4; // 网格列数把研究区分成4列 // 获取研究区的外接矩形包络框 var bounds roi_geometry.bounds({proj: crs, maxError: 1}); // 提取外接矩形的边界坐标转为数组 var ring ee.Array(ee.List(bounds.coordinates()).get(0)); // 分离所有经度(x)和纬度(y)坐标 var xs ring.slice(1, 0, 1); var ys ring.slice(1, 1, 2); // 计算研究区最小/最大经度、最小/最大纬度四至范围 var xMin xs.reduce(ee.Reducer.min(), [0]).get([0, 0]); var xMax xs.reduce(ee.Reducer.max(), [0]).get([0, 0]); var yMin ys.reduce(ee.Reducer.min(), [0]).get([0, 0]); var yMax ys.reduce(ee.Reducer.max(), [0]).get([0, 0]); var xStep xMax.subtract(xMin).divide(cols); // 每个网格的经度宽度 var yStep yMax.subtract(yMin).divide(rows); // 每个网格的纬度高度 var rowIdx ee.List.sequence(0, rows - 1); var colIdx ee.List.sequence(0, cols - 1); var gridFeatures rowIdx.map(function(r) { r ee.Number(r); return colIdx.map(function(c) { c ee.Number(c); // 计算当前网格的四个角点坐标 var x1 xMin.add(xStep.multiply(c)); var x2 xMin.add(xStep.multiply(c.add(1))); var y1 yMax.subtract(yStep.multiply(r.add(1))); var y2 yMax.subtract(yStep.multiply(r)); // 构建闭合多边形坐标首尾点相同 var coords ee.List([ ee.List([x1, y1]), ee.List([x2, y1]), ee.List([x2, y2]), ee.List([x1, y2]), ee.List([x1, y1]) ]); // 生成多边形几何并附加行、列、ID属性 var geom ee.Geometry.Polygon(coords, crs, false); return ee.Feature(geom, { row: r, col: c, id: r.multiply(cols).add(c) }); }); }).flatten(); var grid ee.FeatureCollection(gridFeatures).filterBounds(roi_geometry); print(有效分块数量, grid.size());最终会生成3×412个规则矩形网格后续会过滤掉无研究区覆盖的无效网格。行列数可根据需求调整分块越小单任务导出成功率越高但任务总数越多。.bounds()计算研究区的最小外接矩形把不规则的新疆边界转换成规则矩形方便均匀切分网格。从外接矩形坐标中提取出整个研究区的东西经度范围xMin~xMax和南北纬度范围yMin~yMax。总经度跨度 ÷ 列数 单个网格的经度宽度总纬度跨度 ÷ 行数 单个网格的纬度高度生成行索引、列索引序列通过双层 map 遍历逐行逐列计算每个网格的四角坐标。纬度计算从北向南从 yMax 向下递减符合常规网格编号习惯第一行在最北侧。每个网格生成一个带属性的矢量要素Feature记录网格的行号、列号、唯一 ID。.flatten()将二维的「行 × 列」嵌套列表拍平为一维的要素列表方便后续转成 FeatureCollection。新疆是不规则形状外接矩形的边角网格可能完全落在研究区外。通过filterBounds(roi_geometry)只保留与新疆边界有交集的网格减少无效导出任务。四、地图可视化预览模块Map.centerObject(xinjiang, 5); Map.addLayer(grid, {color: blue}, 分块网格); Map.addLayer(xinjiang, {color: red, strokeWidth: 2}, 新疆边界); var year 2023; var start ee.Date.fromYMD(year, 1, 1); var end ee.Date.fromYMD(year, 12, 31); var demoImage LandsatComposite.filterDate(start, end).median() .clip(roi_geometry); Map.addLayer(demoImage, {bands: [B4, B3, B2], min: 0, max: 3000}, 新疆裁剪影像(2023));将地图视图定位到新疆叠加显示蓝色分块网格和红色新疆边界直观检查分块大小、范围是否合理。以 2023 年为例筛选当年所有影像并做中值合成年度中值是 Landsat 常用的去云合成方法裁剪后以真彩色B4 红、B3 绿、B2 蓝加载到地图验证数据集是否正常可用。五、分块批量导出模块var years [2022]; // 可添加多个年份如 [2020,2021,2022] years.forEach(function(year) { // 1. 生成单年度中值合成影像 var yearStart ee.Date.fromYMD(year, 1, 1); var yearEnd ee.Date.fromYMD(year, 12, 31); var yearlyImage LandsatComposite.filterDate(yearStart, yearEnd).median(); // 2. 网格转列表获取分块总数 var gridList grid.toList(grid.size()); var total gridList.length().getInfo(); // 3. 循环遍历每个网格逐个提交导出任务 for (var i 0; i total; i) { var feature ee.Feature(gridList.get(i)); var geometry feature.geometry(); var clipped yearlyImage.clip(roi_geometry).clip(geometry); Export.image.toDrive({ image: clipped, description: XJ_ year _ i, fileNamePrefix: XJ_ year _tile_ i, folder: Landsat_Xinjiang_ year, region: geometry, crs: crs, scale: pixelSize, maxPixels: 1e13, fileFormat: GeoTIFF, formatOptions: { cloudOptimized: true } }); } });年度遍历通过years数组控制需要导出的年份支持批量导出多年数据。年度合成对每年的影像做中值合成得到单幅年度无缝影像。客户端循环关键grid.toList()将服务端的 FeatureCollection 转为列表方便索引访问。.getInfo()是客户端 - 服务端通信把 GEE 服务端计算的网格总数传到本地 JavaScript 环境。因为for循环是客户端语法必须拿到具体数值才能执行循环。逐块裁剪导出取出单个网格的几何范围对年度影像做裁剪。调用Export.image.toDrive向 GEE 提交导出任务六、完整代码var xinjiang ee.FeatureCollection(添加你的shp文件路径); var roi_geometry xinjiang.geometry(); var LandsatComposite ee.ImageCollection(projects/forest-image-china/assets/China_Landsat_Yearly); for (var i 2; i 15; i){ LandsatComposite LandsatComposite.merge(ee.ImageCollection(projects/forest-image-chinai/assets/China_Landsat_Yearly)); } for (var i 16; i 34; i){ LandsatComposite LandsatComposite.merge(ee.ImageCollection(projects/forest-image-chinai/assets/China_Landsat_Yearly)); } LandsatComposite LandsatComposite.merge(ee.ImageCollection(projects/ee-caiyt33-chinalandsatyearly/assets/China_Landsat_Yearly)) .merge(ee.ImageCollection(projects/ee-caiyt33-chinalandsatyearly1/assets/China_Landsat_Yearly)) .merge(ee.ImageCollection(projects/ee-caiyt331/assets/China_Landsat_Yearly)) .merge(ee.ImageCollection(projects/ee-caiyt333232/assets/China_Landsat_Yearly)) .merge(ee.ImageCollection(projects/extreme-tide-356507/assets/China_Landsat_Yearly)) .merge(ee.ImageCollection(projects/gsw-china-monly/assets/China_Landsat_Yearly)) .merge(ee.ImageCollection(projects/starry-runner-356802/assets/China_Landsat_Yearly)); var crs EPSG:4326; var pixelSize 30; var rows 3; var cols 4; var bounds roi_geometry.bounds({proj: crs, maxError: 1}); var ring ee.Array(ee.List(bounds.coordinates()).get(0)); var xs ring.slice(1, 0, 1); var ys ring.slice(1, 1, 2); var xMin xs.reduce(ee.Reducer.min(), [0]).get([0, 0]); var xMax xs.reduce(ee.Reducer.max(), [0]).get([0, 0]); var yMin ys.reduce(ee.Reducer.min(), [0]).get([0, 0]); var yMax ys.reduce(ee.Reducer.max(), [0]).get([0, 0]); var xStep xMax.subtract(xMin).divide(cols); var yStep yMax.subtract(yMin).divide(rows); var rowIdx ee.List.sequence(0, rows - 1); var colIdx ee.List.sequence(0, cols - 1); var gridFeatures rowIdx.map(function(r) { r ee.Number(r); return colIdx.map(function(c) { c ee.Number(c); var x1 xMin.add(xStep.multiply(c)); var x2 xMin.add(xStep.multiply(c.add(1))); var y1 yMax.subtract(yStep.multiply(r.add(1))); var y2 yMax.subtract(yStep.multiply(r)); var coords ee.List([ ee.List([x1, y1]), ee.List([x2, y1]), ee.List([x2, y2]), ee.List([x1, y2]), ee.List([x1, y1]) ]); var geom ee.Geometry.Polygon(coords, crs, false); return ee.Feature(geom, { row: r, col: c, id: r.multiply(cols).add(c) }); }); }).flatten(); var grid ee.FeatureCollection(gridFeatures).filterBounds(roi_geometry); print(有效分块数量, grid.size()); Map.centerObject(xinjiang, 5); Map.addLayer(grid, {color: blue}, 分块网格); Map.addLayer(xinjiang, {color: red, strokeWidth: 2}, 新疆边界); var year 2023; // 展示年份 var start ee.Date.fromYMD(year, 1, 1); var end ee.Date.fromYMD(year, 12, 31); var demoImage LandsatComposite.filterDate(start, end).median() .clip(roi_geometry); Map.addLayer(demoImage, {bands: [B4, B3, B2], min: 0, max: 3000}, 新疆裁剪影像(2023)); // 导出 var years [2022]; // 可添加更多年份 years.forEach(function(year) { var yearStart ee.Date.fromYMD(year, 1, 1); var yearEnd ee.Date.fromYMD(year, 12, 31); var yearlyImage LandsatComposite.filterDate(yearStart, yearEnd).median(); var gridList grid.toList(grid.size()); var total gridList.length().getInfo(); for (var i 0; i total; i) { var feature ee.Feature(gridList.get(i)); var geometry feature.geometry(); var clipped yearlyImage.clip(roi_geometry).clip(geometry); Export.image.toDrive({ image: clipped, description: XJ_ year _ i, fileNamePrefix: XJ_ year _tile_ i, folder: Landsat_Xinjiang_ year, region: geometry, crs: crs, scale: pixelSize, maxPixels: 1e13, fileFormat: GeoTIFF, formatOptions: { cloudOptimized: true } }); } });参考文献Cai et al. 2025 |https://doi.org/10.34133/remotesensing.0698