主要问题:
我有一个映射步骤,我在其中并行渲染图像的大量扇区:
1 2
3 4
worker a -> 1
worker b -> 2
...
merge 1,2,3,4 to make final image
如果它能装进内存
对于相对较小且可以放入 RAM 的图像,可以简单地使用 PIL 的功能:
def merge_images(image_files, x, y):
images = map(Image.open, image_files)
width, height = images[0].size
new_im = Image.new('RGB', (width * x, height * y))
for n, im in enumerate(images):
new_im.paste(im, ((n%x) * width, (n//y) * height))
return new_im
不幸的是,我将拥有很多很多大扇区。我想最终将这些图片合并成一张大约 40,000 x 60,000 像素的图像,我估计大约有 20 GB。 (或者甚至更多)
很明显,我们不能在 RAM 上解决这个问题。我知道有一些替代方案,例如 memmap
'ing 数组和写入切片,我会尝试这些。但是,我正在寻找尽可能开箱即用的解决方案。
有没有人知道任何更简单的替代方案? 尽管到目前为止我尝试过的所有方法都是在 python 中,但它不需要在 python 中。
最佳答案
pyvips可以非常快速有效地做你想做的事。例如:
import sys
import pyvips
images = [pyvips.Image.new_from_file(filename, access="sequential")
for filename in sys.argv[2:]]
final = pyvips.Image.arrayjoin(images, across=10)
final.write_to_file(sys.argv[1])
access="sequential"
选项告诉 pyvips 您想要流式传输图像。它只会在生成输出时按需加载像素,因此您可以仅使用少量内存来合并大量图像。 arrayjoin
运算符将图像数组连接到 across
的网格中。它有很多布局选项:您可以指定边框、重叠、背景、居中行为等。
我可以这样运行它:
$ for i in {1..100}; do cp ~/pics/k2.jpg $i.jpg; done
$ time ../arrayjoin.py x.tif *.jpg
real 0m2.498s
user 0m3.579s
sys 0m1.054s
$ vipsheader x.tif
x.tif: 14500x20480 uchar, 3 bands, srgb, tiffload
所以它在这台笔记本电脑上加入 100 张 JPG 图片以在大约 2.5 秒内制作 14,000 x 20,000 像素的马赛克,并且从观看 top
来看,需要大约 300mb 的内存。我用它把 30,000 多张图片合并到一个文件中,而且它会更高。我制作了超过 300,000 x 300,000 像素的图像。
PIL 的 paste
的 pyvips 等价物是 insert
.你也可以使用它,尽管它对于大量图像来说效果不佳。
还有一个命令行界面,所以你可以输入:
vips arrayjoin "${echo *.jpg}" x.tif --across 10
加入大量 JPG 图片。
关于python - 合并磁盘上的大图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50297176/