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

Posted

技术标签:

【中文标题】使用光栅显示 tiff 图像的特定部分,而无需加载整个文件【英文标题】:Display specific part of tiff image using rasterio without having to load the entire file 【发布时间】:2021-07-27 03:41:49 【问题描述】:

我有一个包含地图的大型 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)

所以我的问题是,我怎样才能显示地图的一部分,而不必将整个文件加载到内存中,同时让它看起来好像是从完整的地图图像中裁剪出来的?

提前感谢:)

【问题讨论】:

你能澄清一下你所说的结果不同是什么意思吗?我假设坐标,还有其他的东西,比如颜色? @mihi 两者。首先,它显示了所有的地图,而宽度和高度小于实际的宽度和高度。另外,这是一张地形图。当我完全显示它时,它看起来很棒,但是当我尝试显示它的一部分时,它显示为黄色和紫色,并且高度根本不清楚。 【参考方案1】:

它在第一种情况下显示得很好但在第二种情况下显示不好的原因是,在第一种情况下,您将rasterio.DatasetReader 的实例传递给show (show(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))

(通过查看源代码here,我知道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(如 vminvmax 此处)将传递给 matplotlib.axes.Axes.imshow,如文档中的 here 所述。 来自matplotlibdocumenation:

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

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

【讨论】:

虽然它没有 RGB 通道...只是灰色。这是我打印 source_colorinterp 字典时得到的:<ColorInterp.gray: 1>: 1 啊,我明白了。我还为单通道案例添加了一些细节。不过,如果没有一些实际数据,我也不是 100% 确定的。我希望它仍然有帮助:)

以上是关于使用光栅显示 tiff 图像的特定部分,而无需加载整个文件的主要内容,如果未能解决你的问题,请参考以下文章

在水体上移除部分光栅图像

使用 C# 裁剪图像

Vectoraster 7.4.6 | 光栅图案和半色调

怎么用matlab把压缩成tiff

在 UIWebView 中使用 tiff 和 gif 格式图像时出现问题

如何在Bokeh中显示TIFF图像?