如何写入png/tiff文件patchbypatch?

2024-03-28 23:49:40 发布

您现在位置:Python中文网/ 问答频道 /正文

我想从一个非常大的h5py数据集创建一个png或tiff图像文件,它不能同时加载到内存中。所以,我想知道python中是否有一种方法可以在补丁中写入png或tiff文件?(我可以将h5py数据集分片加载到numpy.ndarray)。 我尝试过使用pillow库并给出框坐标,但对于大图像,它会耗尽内存。在

基本上,我想知道有没有一种方法可以做到:

for y in range(0, height, patch_size):
    for x in range(0, width, patch_size):
        y2 = min(y + patch_size, height)
        x2 = min(x + patch_size, width)
        # image_arr is an h5py dataset that cannot be loaded completely
        # in memory, so load it in slices
        image_file.write(image_arr[y:y2, x:x2], box=(y, x, y2, x2))

我正在寻找一种方法来做到这一点,而不需要将整个图像加载到内存中。我试过枕头库,但它把所有的数据都存储在内存中。在

编辑:这个问题不是关于h5py,而是关于如何将非常大的图像(不能加载到内存中)以补丁的形式写入到一个文件中-类似于通过逐行写入来构造大文本文件。在


Tags: 文件数据方法内存in图像imagefor
2条回答

简单回答“如果Python中有一种方法可以在补丁中写入png或tiff文件?”。好吧,是的——只要有足够的时间和技能来实现它,在Python中一切都是可能的。另一方面,不,没有现成的解决方案-因为它似乎不是很有用。在

我不知道TIFF,这里有一条评论说它的容量限制在4GB,所以这种格式可能不是一个好的选择。PNG没有实际的限制,可以被写成块,所以理论上是可行的——前提是至少有一条扫描线可以放入内存中。在

如果您真的想继续这项工作,以下是您需要的信息: PNG文件由几个元数据块和一系列图像数据块组成。后者是相互独立的,因此您可以通过简单地将它们的图像数据块(IDAT)连接在一起并添加所需的元数据块(您可以从第一个小图像中选择这些块,除了IHDR块-需要构建一个包含最终图像大小的块)。在

因此,如果我必须这样做(注意,您需要了解Python的bytes类型以及在Python数据类型之间转换字节序列的方法,以实现这一点):

  • 找出我可以放入内存的行数,并将其作为“小图像块”的高度。宽度是整个最终图像的宽度。让我们称之为widthsmall_height

  • 在h5py中逐个查看我的巨大数据集(width * small_height),将其转换为PNG并将其保存到磁盘的一个临时文件中,或者如果您的图像转换库允许的话-直接将其转换为内存中的bytes字符串。然后按如下方式处理字节数据,并在末尾删除:

    在第一次迭代中:一次遍历一个PNG数据记录(参见PNG规范:http://www.libpng.org/pub/png/spec/1.2/png-1.2-pdg.html,它是长度标记值形式,非常容易编写代码,可以有效地逐个记录地遍历文件),将所有记录保存到目标文件中,除了:修改IHDR以获得最终图像大小并跳过IEND记录。在

    在所有后续的迭代中:扫描PNG数据并只选择IDAT记录,将其写入输出文件。

  • 向目标文件追加IEND记录。

全部完成-你现在应该有一个有效的巨大的巴布亚新几内亚。不过,我不知道谁或什么人能读懂这句话。在

尝试tifffile.memmap

from tifffile import memmap

image_file = memmap('temp.tif', shape=(height, width), dtype=image_arr.dtype,
                    bigtiff=True)

for y in range(0, height, patch_size):
    for x in range(0, width, patch_size):
        y2 = min(y + patch_size, height)
        x2 = min(x + patch_size, width)
        image_file[y:y2, x:x2] = image_arr[y:y2, x:x2]

image_file.flush()

这将创建一个带有一个条带的未压缩BigTIFF文件。内存映射图块尚未实现。不知道有多少库可以处理这种文件,但是您可以使用TIFF标记中的元数据直接从strip中读取。在

相关问题 更多 >