首页 > 解决方案 > 如何在 Python 中加载图像,但保持压缩?

问题描述

我有一系列图像,在 JP2 和 PNG 上都可用,我需要在 python 程序上加载这个图像以按顺序显示它们。现在我只需要显示序列的一部分,例如:

  • 一次从 Frame12 到 Frame24,
  • 第二次从 Frame2 到 Frame7,


  • 加载所有图像会占用我太多的内存,并且每次新序列都是一项漫长的任务时加载。
    有一个函数/方法可以在程序中加载图像,但保持压缩?我可以将这些图像保存在内存中以备使用,但内存占用率低吗?

  • 标签: pythonpython-3.ximage

    解决方案


    您可以将可爱的小型 JPEG/PNG/JP2 图像作为一堆字节读入内存,并将它们压缩到与磁盘上相同的大小,然后在需要时从内存中解压缩它们。

    首先,让我们看看 RGB888 的 1280x1024 图像在内存中所需的内存 - 高达 3.9MB:

    # Decompressed image in memory takes 3.9MB memory
    im = np.zeros([1280,1024,3], dtype=np.uint8)
    
    # print(im.nbytes) => 3932160
    

    现在让我们看一个相同大小的JPEG:

    在此处输入图像描述

    这是在磁盘上,带有ls -l

    -rw-r--r--@  1 mark  staff      47276  2 Apr 17:13 image.jpg
    

    在这里,它仍然在内存中压缩,大小也为 47kB 或仅为 1.2%:

    # Same image as JPEG takes 47kB of memory
    with open('image.jpg','rb') as f: 
       jpg = f.read() 
    
    # print(len(jpg)) => 47276
    

    现在当你想要一个图像时,从内存而不是磁盘解压缩它

    # Read with 'imageio'
    from io import BytesIO 
    import imageio
    numpyArray = imageio.imread(BytesIO(jpg))
    # print(numpyArray.shape) =>(1024, 1280, 3)
    
    # Or, alternatively, and probably faster, read with OpenCV
    import cv2
    numpyArray = cv2.imdecode(np.frombuffer(jpg,dtype=np.uint8), -1)  
    # print(numpyArray.shape) =>(1024, 1280, 3)
    

    另一个完全不同的选择是对图像进行调色,它可以更快地解码英里,但只会将内存占用减少 3 倍。您将颜色数量减少到少于 256 种独特颜色,并存储具有 256 种颜色的调色板。然后在每个像素位置存储一个字节,它是调色板的索引,而不是 RGB 的 3 个字节。这会将您的内存使用量从 3.9MB/图像减少到 1.3MB/图像。它不需要任何解码。但可能会导致色彩保真度和/或条纹的轻微损失——这可能是也可能不是问题,具体取决于您的相机/图像的质量。

    看起来像这样:

    from PIL import Image
    import numpy as np
    
    im = Image.open('image.jpg')
    
    # Make into Numpy array - size is 3.9MB
    a = np.array(im)
    
    # Now make a 256 colour palletised version
    p = im.convert('P',palette=Image.ADAPTIVE)
    
    # Make into Numpy array - size is now only 1.3MB
    a = np.array(p)
    

    推荐阅读