在 R 中处理大型栅格马赛克,无需将它们合并到单个文件(如lidR目录)

Hon*_*ear 6 r raster gdal

litR 包有一种巧妙的方法来处理巨大(点云)数据集:该catalog函数(此处为doc)避免将数据集加载到内存中,并且可以将马赛克(分布在多个(不重叠)图块上的数据集)视为单个数据集。它在计算过程中以智能方式动态加载所需的图块。如果只处理数据集的一小部分,最好避免使用大文件(多个 GB)并保持内存需求精简。

R 中是否有类似的方便/内存高效/“lidR-catalog-way”来处理大型光栅马赛克? 或者用更通用的方式来说: 是否有一种方法可以在 R 中使用镶嵌栅格数据集而无需先合并它们?

我知道mosaicdoc)和merge函数,它们允许我将平铺栅格马赛克合并到单个栅格数据集中。我还发现这样gdal做会更快并且内存效率更高。这是一个 R 片段:

  mosaicgdal <- function(files, out) {
    in_files = do.call(paste, c(as.list(files), sep = " "))
    cmd = paste("gdal_merge.py -a_nodata -32767 -ps 25 25 -o", out, in_files) 
    system(cmd)
  }
Run Code Online (Sandbox Code Playgroud)

然而,两者都需要将整个数据集具体化为内存中(或至少在磁盘上)的单个文件。有办法避免这种情况吗?

我的应用程序: 我正在使用一个巨大的 LAS 点云(几个 TB,所有内容都平铺在 100 MB 文件中)和相应的栅格数据集(大约 100 GB),例如高分辨率地形模型。我通常处理小部分(通过空间多边形 [.shp/.kml] 分隔)或整个 LAS 切片。这在lidR中的内存效率非常高,只加载必要的图块:

# load several TB las tiles as catalog (only file-paths and metadata)
las_data = catalog("D:/FOLDER/WITH/11TB/OF/LAS/TILES")
# load polygon of region of interest
region_of_interest = readOGR("D:/EG/SHP/FILE/OF/ROI")

# cut out the portion of las_data overlapping the polygon
# this will load only the required tiles in memory
las_data_roi = clip_roi(las_data, extent(region_of_interest ))
# ... and create a DTM for example
dtm_roi = grid_terrain(las_data_roi , algorithm = kriging(k = 10L))
Run Code Online (Sandbox Code Playgroud)

我想对栅格数据集执行相同的操作:

# load raster dataset only as pointers to files (and metadata such as extent)
raster_data = raster("D:/FOLDER/WITH/LOTS/OF/RASTER/TILES")
# e.g. crop from mosaic without having to call mosaic/merge first
# avoiding having a huge single file/reading the whole dataset
raster_roi = crop(raster_data, roi)
Run Code Online (Sandbox Code Playgroud)

我通常使用raster package,但这似乎没有提供任何此类功能。

cal*_*lst 9

您应该研究一下terra通过虚拟光栅图块 (VRT) 提供您正在寻找的功能的软件包。我们可以使用它们将磁盘上的光栅文件集合视为单个光栅文件,同时利用 API 执行与通过包执行的大部分相同任务raster

首先,让我们使用直接来自文档的示例创建 4 个栅格的样本?terra::vrt()

library(terra)

r <- rast(ncols=100, nrows=100)
values(r) <- 1:ncell(r)
x <- rast(ncols=2, nrows=2)
filename <- paste0(tempfile(), "_.tif")
ff <- makeTiles(r, x, filename)
ff
#> [1] "/var/folders/b7/_6hwb39d43l71kpy59b_clhr0000gn/T//RtmpACJYNv/filedf6b65d4fca4_1.tif"
#> [2] "/var/folders/b7/_6hwb39d43l71kpy59b_clhr0000gn/T//RtmpACJYNv/filedf6b65d4fca4_2.tif"
#> [3] "/var/folders/b7/_6hwb39d43l71kpy59b_clhr0000gn/T//RtmpACJYNv/filedf6b65d4fca4_3.tif"
#> [4] "/var/folders/b7/_6hwb39d43l71kpy59b_clhr0000gn/T//RtmpACJYNv/filedf6b65d4fca4_4.tif"
Run Code Online (Sandbox Code Playgroud)

现在,我们将再次直接从同一个示例中将它们作为 VRT 读入。这允许

vrtfile <- paste0(tempfile(), ".vrt")
v <- vrt(ff, vrtfile)
head(readLines(vrtfile))
#> [1] "<VRTDataset rasterXSize=\"100\" rasterYSize=\"100\">"                                                                                                                                                                                                                                                                                                             
#> [2] "  <SRS dataAxisToSRSAxisMapping=\"2,1\">GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AXIS[\"Latitude\",NORTH],AXIS[\"Longitude\",EAST],AUTHORITY[\"EPSG\",\"4326\"]]</SRS>"
#> [3] "  <GeoTransform> -1.8000000000000000e+02,  3.6000000000000001e+00,  0.0000000000000000e+00,  9.0000000000000000e+01,  0.0000000000000000e+00, -1.8000000000000000e+00</GeoTransform>"                                                                                                                                                                             
#> [4] "  <VRTRasterBand dataType=\"Float32\" band=\"1\">"                                                                                                                                                                                                                                                                                                                
#> [5] "    <NoDataValue>nan</NoDataValue>"                                                                                                                                                                                                                                                                                                                               
#> [6] "    <ColorInterp>Gray</ColorInterp>"
v
#> class       : SpatRaster 
#> dimensions  : 100, 100, 1  (nrow, ncol, nlyr)
#> resolution  : 3.6, 1.8  (x, y)
#> extent      : -180, 180, -90, 90  (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84 (EPSG:4326) 
#> source      : filedf6b216a737.vrt 
#> name        : filedf6b216a737 
#> min value   :               1 
#> max value   :           10000

Run Code Online (Sandbox Code Playgroud)

现在,我们可以创建一个简单的示例多边形来将我们感兴趣的区域限制在 -180 到 180 到 -90 到 90 经度之间。

library(sf)

pl <- list(rbind(c(-90,-90), c(-90,90), c(90,90), c(90,-90), c(-90,-90)))
roi <- st_sfc(st_polygon(pl), crs = "EPSG:4326")

crop(v, roi)
#> class       : SpatRaster 
#> dimensions  : 100, 50, 1  (nrow, ncol, nlyr)
#> resolution  : 3.6, 1.8  (x, y)
#> extent      : -90, 90, -90, 90  (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84 (EPSG:4326) 
#> source      : memory 
#> name        : filedf6b216a737 
#> min value   :              26 
#> max value   :            9975
Run Code Online (Sandbox Code Playgroud)

  • 只需添加一条注释来强调这样一个事实:VRT 是“gdal”而不是“terra”,并且受“raster”、“terra”和“stars”支持 (4认同)
  • `sf::gdal_utils("buildvrt", ...)`、`terra::vrt(...)`、`stars::st_mosaic()` (3认同)
  • `stars`、`terra` 和 `sf` 可以调用 `gdalbuildvrt`。我不确定“光栅” (2认同)