Nodata口罩

nodata掩码允许您标识有效数据值的区域。在使用栅格时,你会遇到两种不同的面具。

一个是来自gdal的有效数据掩码,它是一个无符号字节数组,行数和列数与数据集相同,其中非零元素(通常为255)表示相应的数据元素有效。其他元素无效,或 NODATA 元素。

另一种面具是numpy的 `masked array <http://docs.scipy.org/doc/numpy/reference/maskedarray.generic.html`_ 它有反意义: True 屏蔽数组掩码中的值表示相应的数据元素无效。小心地,您可以安全地在两种遮罩类型之间导航转换。

考虑Rasterio的rgb.byte.tif测试数据集。它有718行和791列像素。每个像素有3个8位(uint8)通道或波段。它在0,0,0值像素的矩形背景中有一个梯形的图像数据。

https://www.dropbox.com/s/sg7qejccih5m4ah/RGB.byte.jpg?dl=1

数据集中的元数据声明0的值将被解释为无效数据或 NODATA 像素。例如,在将图像与相邻场景合并时,我们希望忽略节点数据像素,并且在最终的马赛克中只有有效的图像数据。

让我们看看这两种屏蔽及其在rgb.byte.tif上下文中的逆关系。

>>> import rasterio
>>> src = rasterio.open("tests/data/RGB.byte.tif")
>>> src.shape
(718, 791)
>>> src.count
3
>>> src.dtypes
('uint8', 'uint8', 'uint8')
>>> src.nodatavals
(0.0, 0.0, 0.0)
>>> src.nodata
0.0

读取数据集掩码

对于数据集的每个频带都有一个掩码。使用数据集的 read_masks() 方法。下面, ``msk` 是与第一个数据集带区对应的有效数据掩码。

>>> msk = src.read_masks(1)
>>> msk.shape
(718, 791)
>>> msk
array([[0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       ...
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0]], dtype=uint8)

在以下意义上,此二维数组是有效的数据掩码: GDAL RFC 15 . 这个 0 角上的值表示 NODATA 区域。放大遮罩数组的内部显示 255 表示的值 有效数据 区域。

>>> msk[200:205,200:205]
array([[255, 255, 255, 255, 255],
       [255, 255, 255, 255, 255],
       [255, 255, 255, 255, 255],
       [255, 255, 255, 255, 255],
       [255, 255, 255, 255, 255]], dtype=uint8)

使用Matplotlib显示 imshow() ,面具如下:

../_images/mask_band.png

等等,面具内部的0值是多少?这是8位栅格数据固有问题的一个例子:缺乏动态范围。数据集创建者说0值表示缺少的数据(请参见 nodatavals 属性),但某些有效数据的值太低,在处理过程中已四舍五入为零。这可能发生在将16位数据扩展到8位时。这个没有神奇的nodata值项目符号。使用每波段16位是有帮助的,但是您必须小心8位每波段数据集及其nodata值。

写口罩

编写一个应用于所有数据集带区的蒙版也很简单:通过 True (或评估为 True 指示有效数据和 False 表示没有数据 write_mask() . 考虑在“r+”(更新)模式下打开的测试数据的副本。

>>> import shutil
>>> import rasterio

>>> tmp = shutil.copy("tests/data/RGB.byte.tif", "/tmp/RGB.byte.tif")
>>> src = rasterio.open(tmp, mode="r+")

要标记所有带区的所有像素都有效(即,要覆盖无法取消设置的节点数据元数据值),您需要执行此操作。

>>> src.write_mask(True)
>>> src.read_masks(1).all()
True

没有更改任何数据,也没有更改数据集的no data值。已将新的带区添加到数据集以存储有效的数据掩码。默认情况下,它与数据集文件一起保存到“SideCar”geotiff。当存在这样的.msk geotiff时,rasterio将忽略nodata元数据值,并基于.msk文件返回掩码数组。

$ ls -l copy.tif*
-rw-r--r--@ 1 sean  staff  1713704 Mar 24 14:19 copy.tif
-rw-r--r--  1 sean  staff      916 Mar 24 14:25 copy.tif.msk

Rasterio能像rgb.byte.tif中的一样帮助修复bugy nodata屏蔽吗?当然可以。考虑该文件的新副本。

>>> src.close()
>>> tmp = shutil.copy("tests/data/RGB.byte.tif", "/tmp/RGB.byte.tif")
>>> src = rasterio.open(tmp, mode="r+")

这一次,我们将读取所有3个波段遮罩(基于nodata值,而不是.msk geotiff),并将它们显示为RGB图像(借助于 numpy.dstack() ):

>>> msk = src.read_masks()
>>> show(np.dstack(msk))  
../_images/mask_bands_rgb.png

彩色区域出现在有效数据像素不完全一致的地方。这也是一个将数据缩小到每波段8位的伪影。我们将从我们所读到的三个带掩码的逻辑连接构造一个新的掩码数组开始。

>>> new_msk = (msk[0] & msk[1] & msk[2])
>>> show(new_msk)  
../_images/mask_conj.png

现在我们用 sieve() 把面具上的小推车区域抖掉。我已经找到了 size 经验性论证。

>>> from rasterio.features import sieve
>>> sieved_msk = sieve(new_msk, size=800)
>>> show(sieved_msk)  
../_images/mask_sieved.png

最后要做的是将筛选后的屏蔽写回数据集。

>>> src.write_mask(sieved_msk)
>>> src.close()

结果是一个适当屏蔽的数据集,它允许一些0值像素被认为是有效的。

numpy屏蔽数组

如果需要,可以将数据集带区读取为numpy-masked数组。

>>> src = rasterio.open("tests/data/RGB.byte.tif")
>>> blue = src.read(1, masked=True)
>>> blue.mask
array([[ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       ...
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True]], dtype=bool)

如前所述,此蒙版与gdal波段蒙版相反。要获得符合GDAL RFC 15的面罩,请执行以下操作:

>>> msk = (~blue.mask * 255).astype('uint8')

对于任何整数值,都可以依赖此栅格标识。 N .

>>> N = 1
>>> (~src.read(N, masked=True).mask * 255 == src.read_masks(N)).all()
True

数据集掩码

有时每波段的屏蔽是不合适的。在这种情况下,您可以从组件带(或其他辅助数据)中手动构造一个遮罩。 or 使用栅格数据集 src.dataset_mask() 功能。这将返回一个具有由以下条件确定的gdal样式掩码的二维数组,其优先级为:

  1. 如果.msk文件、数据集范围的alpha或内部掩码存在,它将用作数据集掩码。

  2. 如果带阴影节点数据值的4波段rgba,则波段4将用作数据集掩码。

  3. 如果存在nodata值,请使用带屏蔽的二进制或()。

  4. 如果不存在no data值,则返回一个包含所有有效数据的掩码(255)

请注意,这与read_掩码和gdal rfc15不同,因为它适用于每个数据集,而不是每个频带。

栅格文件中的节点数据表示法

nodata的存储和表示方式因数据格式和配置选项而异。虽然栅格在阅读时为这些细节提供了一个抽象,但在创建、操作和写入栅格数据时,了解这些差异通常很重要。

  • nodata值src.nodata 值用于定义应屏蔽哪些像素。

  • 阿尔法带 :对于RGB图像,有时会提供额外的第4波段(包含gdal样式的8位掩码)来明确定义该掩码。

  • 内部屏蔽带 :gdal提供了存储额外的布尔1位掩码的能力,该掩码存储在数据集内部。此选项依赖于具有 GDAL_TIFF_INTERNAL_MASK=True . 否则,将从外部写入掩码。

  • 外屏蔽带 :同上,但遮罩带存储在侧车中 .msk 文件(默认)。