使用光栅显示 tiff 图像的特定部分,而无需加载整个文件

Display specific part of tiff image using rasterio without having to load the entire file

我有一个包含地图的大型 tiff 文件(大约 2GB)。我已经能够成功读取数据,甚至可以使用以下 python 代码显示它:

import rasterio
from rasterio.plot import show

with rasterio.open("image.tif") as img:
    show(img)
    data = img.read()

这很好用。但是,我需要能够显示此地图的特定部分,而不必将整个文件加载到内存中(因为它占用了太多的 RAM,并且在许多其他 PC 上不可行)。为此,我尝试使用 rasterio 的 Window class,但是当我尝试显示地图时,结果与完整地图的显示方式不同(好像它导致数据丢失):

import rasterio
from rasterio.plot import show
from rasterio.windows import Window

with rasterio.open("image.tif") as img:
    data = img.read(window=Window(0, 0, 100000, 100000))
    show(data)

所以我的问题是,如何在不将整个文件加载到内存的情况下显示地图的一部分,同时使它看起来好像是从完整地图图像中裁剪出来的?

提前致谢:)

它在第一种情况下显示良好,但在第二种情况下显示不佳的原因是,在第一种情况下,您将 rasterio.DatasetReader 的实例传递给 showshow(img) ),但在第二种情况下,您传入一个 numpy 数组 (show(data))。 DatasetReader 包含附加信息,特别是 show 使用的仿射变换和颜色解释。

show 在第一种情况下(对于 RGB 数据)所做的额外事情可以像这样为窗口情况重新创建:

import rasterio
from rasterio.enums import ColorInterp
from rasterio.plot import show
from rasterio.windows import Window

with rasterio.open("image.tif") as img:
    window = Window(0, 0, 100000, 100000)

    # Lookup table for the color space in the source file
    source_colorinterp = dict(zip(img.colorinterp, img.indexes))

    # Read the image in the proper order so the numpy array will have the colors in the
    # order expected by matplotlib (RGB)
    rgb_indexes = [
        source_colorinterp[ci]
        for ci in (ColorInterp.red, ColorInterp.green, ColorInterp.blue)
    ]
    data = img.read(rgb_indexes, window=window)

    # Also pass in the affine transform corresponding to the window in order to
    # display the correct coordinates and possibly orientation
    show(data, transform=img.window_transform(window))

(我通过查看源代码弄明白了show的作用here


对于单通道数据,用于绘图的底层 matplotlib 库会根据数据的最小值和最大值缩放颜色范围。要获得与以前完全相同的颜色,您需要知道整个图像的最小值和最大值,或者一些相当接近的值。

然后你可以明确告诉matplotlib的imshow如何缩放:

with rasterio.open("image.tif") as img:
    window = Window(0, 0, 100000, 100000)
    data = img.read(window=window, masked=True)

    # adjust these
    value_min = 0
    value_max = 255

    show(data, transform=img.window_transform(window), vmin=value_min, vmax=value_max)

其他 kwargs(如此处的 vminvmax)将传递给 matplotlib.axes.Axes.imshow,如记录 here 所示。 来自 matplotlib documenation:

vmin, vmax: float, optional
When using scalar data and no explicit norm, vmin and vmax define the data range that the colormap covers. By default, the colormap covers the complete value range of the supplied data. It is deprecated to use vmin/vmax when norm is given. When using RGB(A) data, parameters vmin/vmax are ignored.

这样您还可以更改它使用的颜色图等。