[英]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.