如何逐个补丁地写入png / tiff文件?

时间:2018-06-16 23:16:19

标签: python python-imaging-library pillow

我想从一个非常大的h5py数据集创建一个png或tiff图像文件,该数据集无法一次性加载到内存中。所以,我想知道在python中是否有办法在补丁中写入png或tiff文件? (我可以将切片中的h5py数据集加载到select a.id, (a.data1 + data2 + count(b.post_id)) as total from a INNER JOIN b on a.id = b.post_id having total > 0;)。 我尝试过使用枕头库并 <table> <tr> <td onclick="myFnA()">R1C1</td> <td onclick="myFnB()">R1C2</td> <td onclick="myFnC()">R1C3</td> </tr> <tr> <td onclick="myFnA()">R2C1</td> <td onclick="myFnB()">R2C2</td> <td onclick="myFnC()">R2C3</td> </tr> </table> const myFnA = () => console.log('myFnA'); const myFnB = () => console.log('myFnB'); const myFnC = () => console.log('myFnC'); const triggerTds = () => { $('td').trigger('click', 'blur'); }; $(document).ready(triggerTds()); 给出框坐标,但是对于大图像,它会耗尽内存。

基本上,我想知道是否有办法做某事:

numpy.ndarray

我正在寻找一种方法来做到这一点,而不是将整个图像加载到内存中。我已经尝试过枕头库,但它会将所有数据加载/保存在内存中。

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

2 个答案:

答案 0 :(得分: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记录追加到目标文件。

全部完成-您现在应该具有有效的硕大PNG。我不知道是谁或什么读的。

答案 1 :(得分:1)

尝试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标记中的元数据直接从带中读取。