使用Python中的大图像优化内存使用(枕头)

时间:2018-09-17 22:29:16

标签: python-3.x python-imaging-library

我正在使用pillow并处理非常大的图像(至少10500 x 10500 px),这反过来会占用大量内存。我想知道是否有降低它的方法,并尝试使用压缩图像来加载(大约是400kb,而不是420mb),而不是直接创建一个新图像..但是内存使用情况是相同的:

Line #    Mem usage    Increment   Line Contents
================================================
   151   35.969 MiB    0.742 MiB       base = Image.open("C:/Users/Nick/Desktop/transparent.png")
   152  456.992 MiB  421.023 MiB       base.load()
   155  877.641 MiB  420.648 MiB       base_hallway = Image.new("RGBA", (map_width_px, map_height_px))

我也尝试仅将jpg或Image.new()与RGB一起用于第二张图像,但是放弃alpha通道也不起作用。

Line #    Mem usage    Increment   Line Contents
================================================
   151   36.309 MiB    0.766 MiB       base = Image.open("C:/Users/Nick/Desktop/transparent.png")
   152  457.359 MiB  421.051 MiB       base.load()
   156  457.367 MiB    0.008 MiB       base_hallway = Image.open("C:/Users/Nick/Desktop/blackjpg.jpg")
   157  878.312 MiB  420.945 MiB       base_hallway.load()

主要是在基础图像上运行的操作是将其他图像粘贴在其顶部的不同位置。房间或走廊上也有操作,但是相比之下,几乎不使用任何内存,例如根据先前的房间或走廊选择合适的位置粘贴,如有必要则进行旋转等。但是由于需要数十甚至数百个项目粘贴在顶部,每次迭代后我都无法关闭基础图像(因此任何时候都只能打开base OR base_hallway)。我试图仅在需要时打开base和base_hallway图像,这也需要大量保存和关闭操作。最终导致代码运行时间增加了十倍。简化:

room = Image.open(open_room)

if next_tile == "room":
    base.paste(room, box=(rand_width_position, rand_height_position), mask=room)
elif next_tile == "hallway" or next_tile == "junction":
    base_hallway.paste(room, box=(rand_width_position, rand_height_position), mask=room)

有什么方法可以优化内存使用?

谢谢!

1 个答案:

答案 0 :(得分:1)

我喜欢pyvips。我不知道这是否对您有用。

pyvips是一个流式图像处理库,因此它没有将所有内容都保留在内存中,而是建立了一个操作网络,然后通过网络将源图像中的像素流式传输到光盘上。

该程序将加载图像,在随机位置的顶部粘贴更多图像,然后将结果写回。

import sys
import random
import pyvips

# the access hint means we want to stream this image
base = pyvips.Image.new_from_file(sys.argv[2], access='sequential')

for filename in sys.argv[3:]:
    tile = pyvips.Image.new_from_file(filename, access='sequential')
    x = random.randint(0, base.width - tile.width)
    y = random.randint(0, base.height - tile.height)
    base = base.insert(tile, x, y)

# all the processing happens on the final save as the pipeline executes
base.write_to_file(sys.argv[1])

对于测试数据,我制作了100张1,500 x 2,000像素的图像以及10,000 x 10,000像素的背景图像。我可以这样运行:

$ /usr/bin/time -f %e:%M python3 ../insert.py x.jpg ../background.jpg *.jpg
0.89:418252

因此,整个过程为0.89s和420mb的内存。

这是一台具有8个线程的大型台式机。如果我告诉vips使用更少的线程运行,则内存使用会下降很多:

$ VIPS_CONCURRENCY=1 /usr/bin/time -f %e:%M python3 ../insert.py x.jpg ~/pics/huge.jpg *.jpg
5.23:290116

现在不到300mb,尽管速度要慢得多。