[英]memory error while processing large geotiffs on python
我有两个光栅图像 geotiff,一个 (275521, 329643) 变暗(我们称之为年度图像)和另一个(73583, 152367)变暗(月度图像)。 两个栅格的像元大小已经相同。 使用 Python,我想做以下事情:
我一直在 Windows 上的 Python 中使用 rasterio 和 rioxarray,并且想学习如何在 Python 中执行此操作,因为我将循环浏览 8 个年度图像文件,并且对于这些年中的每一年,12 个每月图像文件。
可以预见的是,我一直遇到内存错误,特别是当我尝试从年度图像创建蒙版时,
MemoryError:无法为形状为 (1, 73583, 152367) 且数据类型为 uint8 的数组分配 10.4 GiB
我知道我应该尝试使用某种多处理工具,并且一直在尝试使用 Dask 实现我需要的东西,但老实说,我不知道我在做什么或如何开始处理这些数组(即,创建一个庞大的数组 [年掩码],将这个庞大的数组与另一个庞大的数组 [每月图像] 相乘,以创建另一个庞大的数组 [掩码的每月数据])。 是否会感谢所有类型的帮助或建议、代码示例、教程? 非常感谢。
不确定如何提供数据,但如果有帮助,它们是从谷歌地球引擎下载的图像文件。 这是一些示例代码:
import rasterio as rio
import xarray as xr
import rioxarray
import numpy as np
years = np.arange(2012, 2020)
monthly_file_paths = ["\paths\to\monthly\image\tifs"]
yearly_file_paths = ["\paths\to\yearly\image\tifs"]
monthly_sample = xr.open_rasterio(monthly_file_paths[0], chunks={"x":256, "y":256})
for yearly_file in yearly_file_paths:
yearly = xr.open_rasterio(yearly_file, chunks={"x":256, "y":256}) # !!!: Previously encountered memory error here before including the "chunks" bit
yearly = yearly.rio.set_nodata(0)
# crop yearly layer to monthly bounding box
yearly = yearly.rio.clip_box(minx=monthly_sample.x.min().item(),
miny=monthly_sample.y.min().item(),
maxx=monthly_sample.x.max().item(),
maxy=monthly_sample.y.max().item())
# reproject and resample yearly to match monthly extents and crs
yearly = yearly.rio.reproject_match(monthly_sample )
yearly = yearly.assign_coords({
"x": monthly_sample.x,
"y": monthly_sample.y})
# create mask.
yearly.data = xr.where(yearly==3, 1, 0) # !!!: Error occurs here
for month_file in monthly_file_paths :
_monthly = xr.open_rasterio(month_file)
_monthly.data = xr.where(_monthly==2, 1, 0)
yearly_monthly = yearly * _monthly
yearly_monthly = yearly_monthly.rio.update_attrs(_monthly.attrs)
yearly_monthly.rio.to_raster(f'{month_file}.tif', dtype=np.uint8,
compress='deflate')```
这将是一个棘手的问题! 处理这么大的光栅文件总是很麻烦。 我没有灵丹妙药的答案,但这里有一些我会考虑的事情。
我首先会直接检查您的文件,并确保您的数据精确对齐,例如使用_monthly.x.isin(yearly.x.values).all()
和 y 相同。
然后,仅在打开数据时使用da.sel
读取这些索引。
另外,请确保您将 _monthly 文件分块,而不仅仅是年度文件:
_monthly = xr.open_rasterio(month_file)
执行此操作时,请尝试确保您的块完全对齐(您不希望它们偏移,因此需要加载多个块以进行每个块的合并xr.unify_chunks
在这里可能会有所帮助 - 我还没有使用过它,但我认为这是预期的用例。
另一个问题是 xarray 假设您总是需要 64 位数据类型,除非您指定。 线
_monthly.data = xr.where(_monthly==2, 1, 0)
首先将_monthly==2
转换为 bool 类型,然后将 python int
s 1
和0
转换为与输入数组相同的形状,并猜测它们应该是 64 位整数。 这将您的 10GB 问题变成了 80GB 问题! 看这个简单的例子:
In [10]: data = xr.DataArray(np.array([1], dtype='uint8'))
In [11]: xr.where(data==1, 1, 0).dtype
Out[11]: dtype('int64')
相反,对你的类型要非常迂腐:
In [12]: one_u8 = np.array(1, dtype='uint8')
In [13]: zero_u8 = np.array(0, dtype='uint8')
In [14]: xr.where(data==1, one_u8, zero_u8).dtype
Out[14]: dtype('uint8')
最后,任何涉及“重新投影”或重塑数据的事情都可能真的把事情搞砸:
yearly = yearly.rio.reproject_match(monthly_sample)
我对重新投影的担忧是:
好消息是你绝对是在正确的轨道上。 我会用 rioxarray、xarray 和 dask 来完全按照您的方法来执行此操作。 逐行逐步执行工作流程,而不是尝试将其全部写出来并在失败时对其进行调试。 检查xarray对象在每一步,在DASK块,大小,并在dtypes密切关注da.data
对象,当您去。 如果它是一个选项,请在 jupyterlab notebook 中对其进行原型设计 - dask-backed xarray.DataArrays 的 html 界面真的很有帮助。
我能提供的最好建议是不要试图一次性完成这一切,至少在您知道工作流程的每个部分都顺利运行之前不要尝试。 相反,将您的工作流程分解为多个步骤,并在每个步骤之后写入磁盘,从中间文件中读取以进行下一步。
xr.align(..., join='exact')
可能有用的一件事是使用明确支持并行 I/O 和分块的文件类型,例如 zarr。 如果您在缓存步骤中将 zarr 换成 rasterio,这可能会变得容易一些。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.