我有一个地图步骤,我可以并行渲染图像的大量扇区:
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中。
答案 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。它应该允许您在Python中遵循上述模型。同一个存储库有纯Python模块来读写TIFF文件,我不知道是否能够在tile中写入TIFF文件,或者它是否允许以块的形式写入它们。还有许多用于读写TIFF文件的Python模块,但大多数都会将一个矩阵写成TIFF文件,而不是一次只能写一个文件。