【问题标题】:Optimizing memory usage with large images in Python (Pillow)在 Python (Pillow) 中使用大图像优化内存使用
【发布时间】:2019-02-21 21:27:15
【问题描述】:

我正在使用pillow 并处理相当大的图像(至少 10500 x 10500 像素),这反过来又会占用大量内存。我想知道是否有办法降低它并尝试使用压缩图像来加载(这将是〜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)

有没有办法优化内存使用?

谢谢!

【问题讨论】:

  • 您能否更具体地说明您对这些图像执行的操作类型?如果你能给出一个完整的、简短的例子来说明你正在做的处理,人们可以提出具体的建议来改进它。
  • @user894763 我用一个针对基础图像的主要操作示例更新了主帖。它基本上需要在不同位置粘贴几个房间和走廊,以生成地牢布局。最后,我将 base 和 base_hallway 图像合并在一起并裁剪出未使用的空间。
  • 看看我的回答,关于使用调色板版本的图像将内存消耗减少 66% stackoverflow.com/a/51800547/2836621
  • 当我在 AppEngine 中的 Python 应用程序由于超出内存限制而开始崩溃时,我遇到了类似的情况。该应用程序仅使用Image.newimage.pasteimage.save 调整图像大小。当遇到 6570x4380 尺寸的图像时,进程的内存会增长到 530Mb

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


【解决方案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
775200:0.75

所以整个过程需要 0.75s 和 780mb 的内存。

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

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

现在不到 200mb,虽然速度较慢。

【讨论】:

    猜你喜欢
    • 2016-04-09
    • 2014-04-08
    • 2013-12-20
    • 2021-06-01
    • 2020-05-05
    • 2011-10-15
    • 1970-01-01
    • 2014-05-05
    • 1970-01-01
    相关资源
    最近更新 更多