合并磁盘上的大图像

Merge large images on disk

主要问题:

我有一个地图步骤,我在其中并行渲染图像的大量扇区:

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.

我建议使用 TIFF 文件格式。大多数 TIFF 文件是条带化的(一条或多条扫描线作为一个块存储在文件上),但也可以编写分块 TIFF 文件(其中图像被分成多个块,每个块都作为一个独立的块存储在文件上)。

LibTIFF 是读写 TIFF 文件的规范方式。它有一种创建新 TIFF 文件的简单方法,并一次添加一个图块。因此,您的程序可以创建 TIFF 文件,获取一个扇区,将其作为(一个或多个)图块写入 TIFF 文件,获取下一个扇区,等等。您必须选择图块大小以平均划分一个扇区。

有一个名为 LibTIFF 的 Python 绑定,还有什么,PyLibTIFF。它应该允许您从 Python 中遵循上述模型。同一个存储库有纯 Python 模块来读取和写入 TIFF 文件,我不知道它是否能够以块的形式写入 TIFF 文件,或者是否允许以块的形式写入它们。还有许多其他 Python 模块用于读取和写入 TIFF 文件,但大多数会将一个矩阵写入 TIFF 文件,而不是允许您一次写入一个文件。

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

所以它在这台笔记本电脑上用大约 2.5 秒的时间将 100 张 JPG 图片拼接成 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 图片。