首页 > 解决方案 > 使用光栅显示 tiff 图像的特定部分,而无需加载整个文件

问题描述

我有一个包含地图的大型 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 类,但是当我尝试显示地图时,结果与显示完整地图的方式不同(好像它导致数据丢失):

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)

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

提前致谢 :)

标签: pythontiffrasterio

解决方案


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

在第一种情况下(对于 RGB 数据)所做的其他事情show可以为窗口情况重新创建,如下所示:

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通过查看源代码了解了这里的作用)


对于具有单通道的数据,用于绘图的底层 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 (like vminand vmaxhere) 将被传递给matplotlib.axes.Axes.imshow,如此处所述。来自 matplotlib文档

vmin, vmax: float, optional
当使用标量数据且没有明确的范数时,vmin 和 vmax 定义颜色图覆盖的数据范围。默认情况下,颜色图覆盖所提供数据的完整值范围。当给出 norm 时,不推荐使用 vmin/vmax。当使用 RGB(A) 数据时,参数 vmin/vmax 被忽略。

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


推荐阅读