【问题标题】:How can I save a huge image with PIL?如何使用 PIL 保存巨大的图像?
【发布时间】:2021-05-21 09:16:07
【问题描述】:

我想组合 8 张 9450x75600 像素(即 75600x75600 像素)的图像

import sys
import PIL
from PIL import Image
    
PIL.Image.MAX_IMAGE_PIXELS = 9331200000
ListeImage=['test1.tif','test2.tif','test3.tif','test4.tif','test5.tif','test6.tif','test7.tif','test8.tif']
images = [Image.open(x) for x in ListeImage]
widths, heights = zip(*(i.size for i in images))
    
total_width = sum(widths)
max_height = max(heights)
    
new_im = Image.new('RGB', (total_width, max_height))
    
y_offset = 0
for im in images:
      new_im.paste(im, (0,y_offset))
      y_offset += im.size[0]
      new_im.save('TOTAL'+str(y_offset)+'.tif')

但是我遇到了这个错误...

Traceback (most recent call last):
  File "C:\Python27\MergeImages.py", line 21, in <module>
    new_im.save('test'+str(bande[0])+'.tif')
  (...)
  File "C:\Python27\lib\site-packages\PIL\TiffImagePlugin.py", line 626, in _pack
    return struct.pack(self._endian + fmt, *values)
error: integer out of range for 'L' format code

我认为这是一个内存问题。如何解决?

【问题讨论】:

  • 您已调整输出图像的大小以并排放置所有图像,但您似乎粘贴的是垂直而不是水平堆叠的单个图像。我认为您需要使用x 偏移量而不是y

标签: image python-imaging-library


【解决方案1】:

您遇到了异常,因为您超出了 4GB Tiff 格式限制。

请参阅:What is the maximum size of TIFF metadata?

您可以使用BigTIFF 格式。
您可以尝试使用Tifffile 来编写 BigTIFF 图像文件。

我更喜欢使用 JPEG 2000 图像格式。
我发现了this 的帖子,关于用枕头保存 JPEG 2000。

我知道的方法是使用 OpenCV 保存 JPEG 2000。
OpenCV 以 无损 格式保存 JP2 图像(与 Tiff 无损的方式相同)。

使用 OpenCV 保存的问题:

  • 我们需要将枕头图像转换为 NumPy 数组。
  • 我们需要从 RGB 转换为 BGR 颜色格式。

这是您的代码的修改版本,它使用 OpenCV 保存 JP2:

import sys
import PIL
from PIL import Image
import cv2
import numpy as np
    
PIL.Image.MAX_IMAGE_PIXELS = 9331200000
ListeImage=['test1.tif','test2.tif','test3.tif','test4.tif','test5.tif','test6.tif','test7.tif','test8.tif']
images = [Image.open(x) for x in ListeImage]
widths, heights = zip(*(i.size for i in images))
    
#total_width = sum(widths)
#max_height = max(heights)
    
#new_im = Image.new('RGB', (total_width, max_height))
new_im = Image.new('RGB', (max(widths), sum(heights)))
    
y_offset = 0
for im in images:
    new_im.paste(im, (0,y_offset))
    y_offset += im.size[1] #im.size[0]
    # new_im.save('TOTAL'+str(y_offset)+'.tif')
    cv2.imwrite('TOTAL'+str(y_offset)+'.jp2', cv2.cvtColor(np.array(new_im), cv2.COLOR_RGB2BGR))

注意事项:

  • 您似乎在混合宽度和高度 - 我试图修复它。
  • 我的系统中没有足够的 RAM 来测试具有如此大图像的代码 - 我使用较小的图像对其进行了测试。
  • 我使用 Python 3.6 测试了代码,不知道它是否适用于 Python 2.7
  • 我在没有中间变量的情况下实现了代码,希望它消耗更少的 RAM。

更新:

上述解决方案消耗了太多 RAM(超过 100GB)。
使用大页面文件(磁盘空间作为虚拟内存)可以,但是太慢了。
该解决方案(另存为 JPEG 2000)对于大多数系统来说并不实用。

以下解决方案使用 BigTIFF 格式。
该实现在 RAM 方面也更高效:

import sys
import PIL
from PIL import Image
import tifffile
import numpy as np
import gc
    
PIL.Image.MAX_IMAGE_PIXELS = 9331200000
ListeImage=['test1.tif','test2.tif','test3.tif','test4.tif','test5.tif','test6.tif','test7.tif','test8.tif']
images = [Image.open(x) for x in ListeImage]
widths, heights = zip(*(i.size for i in images))

# Free memory - release memory of all images.
del images
gc.collect()  # Explicitly invoke the Garbage Collector https://stackoverflow.com/questions/1316767/how-can-i-explicitly-free-memory-in-python

    
#new_im = Image.new('RGB', (max(widths), sum(heights)))
new_im = np.zeros((sum(heights), max(widths), 3), np.uint8)  # Use NumPy array instead of pillow image.
    
y_offset = 0
for x in ListeImage:
    im = Image.open(x)  # Read one input image at a time (for saving RAM).
    #new_im.paste(im, (0,y_offset))
    new_im[y_offset:y_offset+im.size[1], :, :] = np.array(im)  # Copy im to NumPy array (instead of pasting to pillow image - saves RAM).
    y_offset += im.size[1]
    tifffile.imwrite('TOTAL'+str(y_offset)+'.tif', new_im, bigtiff=True)  # Write new_im as BigTIFF.

    del im
    gc.collect()  # Explicitly invoke the Garbage Collector

【讨论】:

    猜你喜欢
    • 2013-01-05
    • 2013-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-21
    • 1970-01-01
    • 1970-01-01
    • 2016-04-11
    相关资源
    最近更新 更多