使用pyvips连接多个大型图像

4

我正在尝试通过Python中的vips来合并多个图像。我在一个文件夹中有30个(但可以超过600个)png文件,它们是条纹形状,分辨率为854x289920(分辨率全部相同)...

如果我尝试使用PIL在Python中将它们水平连接,它会立即崩溃并显示"MemmoryError(内存错误)"。因此我搜索了一下,找到了VIPS,它可以同时完成我需要的两件事情:合并图像和从结果创建深度缩放图像。

不幸的是,我不确定如何在Python中正确地将它们水平连接。

我有一个图像列表数组来自文件夹,但是如何循环遍历它们并按顺序将合并后的图像写入磁盘?

3个回答

7

仅供参考,您也可以在命令行上执行此操作。请尝试:

vips arrayjoin "a.png b.png c.png" mypyr.dz --across 3

将三张PNG图像水平连接,并将结果保存为名为mypyr的DeepZoom金字塔。 arrayjoin文档包含所有选项:

https://www.libvips.org/API/current/libvips-conversion.html#vips-arrayjoin

您可以在.dz后面用方括号将参数包含起来,以向金字塔生成器提供参数。

vips arrayjoin "a.png b.png c.png" mypyr.dz[overlap=0,container=zip] --across 3

在Windows上,由于Windows不喜欢创建文件并且不喜欢巨大的目录,因此深度缩放金字塔的编写可能非常缓慢。如果使用container=zip进行编写,则vips将直接创建一个包含金字塔的.zip文件。这使得金字塔的创建速度提高了4倍左右。

1

这似乎也可以很好地打开大量图像并对它们执行joinarray,使它们相邻。感谢@user894763。

import os
import pyvips
# natsort helps with sorting the list logically
from natsort import natsorted

source = r"E:/pics/"
output = r"E:/out/"
save_to = output + 'final' + '.tif'

# define list of pictures we are going to get from folder
list_of_pictures = []
# get the 
for x in os.listdir(source):
    list_of_pictures.append(source + x)

# list_of_pictures now contains all the images from folder including full path
# since os.listdir will not guarantee proper order of files we use natsorted to do it
list_of_pictures = natsorted(list_of_pictures)

array_images = []
image = None
# lets create array of the images for joining, using sequential so it use less ram
for i in list_of_pictures:
    tile = pyvips.Image.new_from_file(i, access="sequential")
    array_images.append(tile)

# Join them, across is how many pictures there be next to each other, so i just counted all pictures in array with len 
out = pyvips.Image.arrayjoin(array_images, across=len(list_of_pictures))
# write it out to file....
out.write_to_file(save_to, Q=95, compression="lzw", bigtiff=True)

1
save 方法中的 Q 参数仅适用于 JPG 压缩,对 LZW 没有影响。使用 compression="deflate"predictor="horizontal" 可能会获得最佳结果。不过,我建议直接编写金字塔而不是保存中间结果,这样速度会更快。 - jcupitt

0

我解决了它,但还有一些问题:

import pyvips

list_of_pictures = []
for x in os.listdir(source):
    list_of_pictures.append(source + x)

image = None
for i in list_of_pictures:
    tile = pyvips.Image.new_from_file(i, access="sequential")
    image = tile if not image else image.join(tile, "horizontal")

image.write_to_file(save_to)

是的,它会生成包含合并图片的 TIF 文件...但是天啊!原始图片是 PNG 格式(30x),总共 4.5GB,而结果的 TIFF 文件却是 25GB!这是怎么回事,为什么有如此巨大的大小差异?


好的,这里有一些压缩选项:image.write_to_file(save_to, Q=95, compression="lzw", bigtiff=True) - VladoPortos
1
您可以使用 arrayjoin 将图像数组合并为单个步骤。对于大量源图像,它的效果更好。您可以直接写入 DeepZoom 金字塔,只需将最后一行替换为 image.dzsave("mypyr") 即可。 - jcupitt
你也可以使用 write_to_file 写入一个 DeepZoom 金字塔:只需使用 .dz 作为后缀即可。例如:image.write_to_file("mypyr.dz[suffix=.png]") - jcupitt
就生成巨大的图像然后制作金字塔而言,这样做没有任何好处--我会直接生成金字塔。当然,这取决于你! - jcupitt
@user894763 确实,我认为你的方法是正确的,而且可以节省一些步骤。但是最终我还是完成了,只是花了很长时间:D 网站仍在上传中,但结果可以在这里看到:http://deepzoom.reverz.sk/ 所有的.sk域名都在一张图片上。 - VladoPortos
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接