簡體   English   中英

在python上處理大型geotiff時出現內存錯誤

[英]memory error while processing large geotiffs on python

我有兩個光柵圖像 geotiff,一個 (275521, 329643) 變暗(我們稱之為年度圖像)和另一個(73583, 152367)變暗(月度圖像)。 兩個柵格的像元大小已經相同。 使用 Python,我想做以下事情:

  1. 剪裁年度圖像,使其與每月圖像范圍相同。
  2. 將年度影像的范圍與每月影像的范圍相匹配。
  3. 從年度圖像文件創建一個二進制掩碼,該文件是一個分類數據集 (vals 0/1/2/3),使得所有包含 3 的單元格返回值 1,所有其他單元格都返回 0。
  4. 將月度圖像文件與這個新的蒙版層相乘以過濾掉與 yearly.data == 3 單元格對齊的單元格。

我一直在 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 10轉換為與輸入數組相同的形狀,並猜測它們應該是 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)

我對重新投影的擔憂是:

  1. 您需要確保重新投影后坐標標簽相同,而不是之前。 因此,請確保在合並之前但在重新投影之后在兩個數組之間共享每個 x 和 y。 我知道這是 reproject_match 的目標,但是當依賴浮點坐標精確匹配時,這種情況可能會出錯。 如果需要,您可以考慮在重新投影后使用整數坐標。
  2. 這是否加載數據? 塊會發生什么? 我認為這是應該起作用的事情; 當您談論這么大的工作時,它是否在實踐中起作用始終是另一個問題。 在處理如此大的數組時,您正在推動 xarray/rioxarray 的限制,因為單個加載或隨意的 float64 強制可能會破壞您的記憶。

可能的前進方向

好消息是你絕對是在正確的軌道上。 我會用 rioxarray、xarray 和 dask 來完全按照您的方法來執行此操作。 逐行逐步執行工作流程,而不是嘗試將其全部寫出來並在失敗時對其進行調試。 檢查xarray對象在每一步,在DASK塊,大小,並在dtypes密切關注da.data對象,當您去。 如果它是一個選項,請在 jupyterlab notebook 中對其進行原型設計 - dask-backed xarray.DataArrays 的 html 界面真的很有幫助。

我能提供的最好建議是不要試圖一次性完成這一切,至少在您知道工作流程的每個部分都順利運行之前不要嘗試。 相反,將您的工作流程分解為多個步驟,並在每個步驟之后寫入磁盤,從中間文件中讀取以進行下一步。

  1. 減少您的數據以僅包含所需的形狀
  2. 重新投影。 祝你好運:D
  3. 使用分塊讀取數據,並明確檢查數據對齊,例如使用xr.align(..., join='exact')
  4. 掩碼和乘法

可能有用的一件事是使用明確支持並行 I/O 和分塊的文件類型,例如 zarr。 如果您在緩存步驟中將 zarr 換成 rasterio,這可能會變得容易一些。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM