遥感云平台-GEE分块下载与拼接
内容介绍
在GEE中处理大范围遥感数据时,常常会遇到导出超时或内存溢出的情况。为了解决这些问题,通常采用分块处理方法以提高效率。许多资料展示了通过矢量边界或卫星条带来进行分块的方法,本文提供一个网页与本地“即插即用”的计算渔网并分块导出的代码,以及如何在下载后进行拼接。(仅栅格也可)
GEE网页端
核心代码
渔网创建的核心在于将一个给定的研究区域按照设定的行列数划分成多个小单元。首先计算研究区域的边界框,然后通过设定的行列数,计算出每个网格的尺寸。最后按照行优先顺序生成每个网格的坐标,将每块单独进行裁剪和导出。
- 计算网格尺寸。根据边界框的宽度和高度,计算出每个网格的尺寸:
var xStep = (xMax - xMin) / cols
var yStep = (yMax - yMin) / rows
- 计算每个网格的坐标。每个网格的四个角点坐标可以通过如下公式计算:
var x1 = xMin + xStep * col;
var x2 = xMin + xStep * (col + 1);
var y1 = yMax - yStep * (row + 1);
var y2 = yMax - yStep * row;
完整代码
本代码使用十分简便,只需要在计算代码后插入即可,将roi或者image定义为想要下载的影像!
// 如果有矢量边界:
var roi = table //(替换)
var roi_geometry = roi.geometry()// 如果只有影像:
var image = ;//(替换)
var roi_geometry = image.geometry()//导出参数设置
var crs = 'EPSG:4326';//(替换)
var pixelSize = 30;//(替换)
var rows = 4; // 行数
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);
//显示渔网
Map.addLayer(grid, {color: 'blue'}, 'Grid');//分块导出
var total = grid.size().getInfo();
var gridList = grid.toList(total);
for (var i = 0; i < total; i++) {var feature = ee.Feature(gridList.get(i));var geometry = feature.geometry();var clipped = image.clip(geometry);Map.addLayer(clipped,{'min':1,'max':9,'palette':visPaletteCLCD},'CLCD');Export.image.toDrive({image: clipped,description: 'Export_tile_' + i,fileNamePrefix: 'tile_' + i,region: geometry,crs: crs,scale: pixelSize,maxPixels: 1e13});
}
效果如图:
GEE-python
在Geemap中有fishnet函数,可以直接用来分块并下载。
代码
# 定义渔网
fishnet = geemap.fishnet(roi_geometry, rows=4, cols=4, delta=1)
style = {'color': 'ffff00ff', 'fillColor': '00000000'}
Map.addLayer(fishnet.style(**style), {}, 'Fishnet')# 分块下载
image = //(替换)
out_dir = r''//(替换)
pixelSize = 30//(替换)
geemap.download_ee_image_tiles(image, fishnet, out_dir, prefix='tile_', crs="EPSG:4326", scale=pixelSize
)
效果如图:
合并分块
将所有分块下载到同一目录后(文件夹中仅含分块),运行下方代码即可完成栅格拼接;这里使用 gdal库进行读取、对齐与写出。
from osgeo import gdal, gdalconst, osr
import osinputDir = r''//(替换)
destDir = r''//(替换)
files = os.listdir(inputDir)
tif_files = [f for f in files if f.endswith('.tif')]
tif_files = [os.path.join(inputDir, tif) for tif in tif_files]# 检查投影
osrs = []
for tif in tif_files:ds = gdal.Open(tif, gdalconst.GA_ReadOnly)osr_ = gdal.Dataset.GetSpatialRef(ds)osrs.append(osr_)osr_ref = osrs[0]
for osr_i in osrs:if not osr.SpatialReference.IsSame(osr_ref, osr_i):print('待拼接的栅格影像必须有相同的投影!')exit(1)# 拼接所有文件
destFile = os.path.join(destDir, '.tif')//(替换文件名)
resampleType = gdalconst.GRA_NearestNeighbour
options = gdal.WarpOptions(srcSRS=osr_ref, dstSRS=osr_ref, format='GTiff',resampleAlg=resampleType,creationOptions=["COMPRESS=LZW"],dstNodata=-9999
)
gdal.Warp(destFile, tif_files, options=options)
print(f'已完成拼接,输出文件: {destFile}')
参考资料汇总
- GEE前沿教程|在 Google Earth Engine 中进行大规模分块处理
- GEE前沿教程|geemap多线程、网格化数据集极速下载
- 新年快乐!(GEE如何优雅的分块下载影像以及批量下载与拼接代码)
- GEE必须会教程——研究区域分块处理
写在最后
本代码整理了众多资料,如代码有问题请及时私信谢谢!