是否可以通过 memmap 支持将 boolean numpy 数组保存为每个元素 1 位?

Is it possible to save boolean numpy arrays on disk as 1bit per element with memmap support?

是否可以将每个元素仅占用 1 位的布尔值格式的 numpy 数组保存在磁盘上? This answer suggests to use packbits and unpackbits,但是从文档来看,这似乎不支持内存映射。有没有办法在支持 memmap 的情况下在磁盘上存储 1 位数组?

memmap 要求的原因:我在全高清 (1920x1080) 图像数据库上训练我的神经网络,但我为每次迭代随机裁剪出一个 256x256 补丁。由于读取完整图像非常耗时,因此我使用 memmap 来读取唯一需要的补丁。现在,我想在我的图像中使用二进制掩码,因此有这个要求。

numpy 不支持每个元素数组 1 位,我怀疑 memmap 有这样的功能。 但是,有一个使用 packbits 的简单解决方法。

由于您的情况不是按位随机访问,您可以将其读取为每个元素数组 1 个字节。

# A binary mask represented as an 1 byte per element array.
full_size_mask = np.random.randint(0, 2, size=[1920, 1080], dtype=np.uint8)

# Pack mask vertically.
packed_mask = np.packbits(full_size_mask, axis=0)

# Save as a memmap compatible file.
buffer = np.memmap("./temp.bin", mode='w+',
                   dtype=packed_mask.dtype, shape=packed_mask.shape)
buffer[:] = packed_mask
buffer.flush()
del buffer

# Open as a memmap file.
packed_mask = np.memmap("./temp.bin", mode='r',
                        dtype=packed_mask.dtype, shape=packed_mask.shape)

# Rect where you want to crop.
top = 555
left = 777
width = 256
height = 256

# Read the area containing the rect.
packed_top = top // 8
packed_bottom = (top + height) // 8 + 1
packed_patch = packed_mask[packed_top:packed_bottom, left:left + width]

# Unpack and crop the actual area.
patch_top = top - packed_top * 8
patch_mask = np.unpackbits(packed_patch, axis=0)[patch_top:patch_top + height]

# Check that the mask is cropped from the correct area.
print(np.all(patch_mask == full_size_mask[top:top + height, left:left + width]))

请注意,此解决方案可以(并且很可能会)读取额外的位。 具体来说,两端最多7位。 在你的情况下,它将是 7x2x256 位,但这只是补丁的 5% 左右,所以我认为它可以忽略不计。

顺便说一下,这不是您问题的答案,但是当您处理二进制掩码(例如用于图像分割的标签)时,使用 zip 压缩可能会大大减小文件大小。 每个图像(不是每个补丁)可能会减少到 8 KB 以下。 您可能也想考虑这个选项。