合并磁盘上的大图像

时间:2018-05-11 17:14:19

标签: python image mapreduce computer-vision

主要问题:

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

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'数组和写入切片,我会尝试。但是,我正在寻找开箱即用的解决方案

有没有人知道更容易的选择? 尽管到目前为止我尝试过的所有方法都是在python中,但它不需要在python中

2 个答案:

答案 0 :(得分:4)

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×300,000像素。

PIL的paste等价的pyvips是insert。你也可以使用它,虽然对于大量的图像它不会那么好用。

还有一个命令行界面,所以你只需输入:

vips arrayjoin "${echo *.jpg}" x.tif --across 10

加入大量JPG图片。

答案 1 :(得分:1)

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

LibTIFF是读取和编写TIFF文件的规范方式。它有一种简单的方法来创建一个新的TIFF文件,并在此时添加一个。因此,您的程序可以创建TIFF文件,获取一个扇区,将其写为(一个或多个)磁贴到TIFF文件,获取下一个扇区等。您必须选择磁贴大小来均匀划分一个扇区。 / p>

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