Python: 如何从内存中的压缩文件中读取图像?

Python: How to read images from zip file in memory?

我见过这个问题的变体,但不是在这个确切的上下文中。我有一个名为 100-Test.zip 的文件,其中包含 100 张 .jpg 图像。我想在内存中打开这个文件并处理每个文件做 PIL 操作。剩下的代码已经写好了,我只想集中精力从 zip 文件到第一个 PIL 图像。这就是我从阅读其他问题中收集到的建议中的代码现在的样子,但它不起作用。你们能帮忙看看吗?

import zipfile
from StringIO import StringIO
from PIL import Image

imgzip = open('100-Test.zip', 'rb')
z = zipfile.ZipFile(imgzip)
data = z.read(z.namelist()[0])
dataEnc = StringIO(data)
img = Image.open(dataEnc)

print img

但是当我 运行 它时我得到这个错误:

 IOError: cannot identify image file <StringIO.StringIO instance at
 0x7f606ecffab8>

备选方案:我看到其他来源说要改用这个:

image_file = StringIO(open("test.jpg",'rb').read())
im = Image.open(image_file)

但问题是我没有打开文件,它已经在内存中的数据变量中。我也尝试使用 dataEnc = StringIO.read(data) 但出现此错误:

TypeError: unbound method read() must be called with StringIO instance as 
first argument (got str instance instead)

原来的问题是在 namelist() 中有一个额外的空元素,因为图像被压缩到 zip 文件中的目录中。下面是完整代码,用于检查并遍历 100 张图像。

import zipfile
from StringIO import StringIO
from PIL import Image
import imghdr

imgzip = open('100-Test.zip')
zippedImgs = zipfile.ZipFile(imgzip)

for i in xrange(len(zippedImgs.namelist())):
    print "iter", i, " ",
    file_in_zip = zippedImgs.namelist()[i]
    if (".jpg" in file_in_zip or ".JPG" in file_in_zip):
        print "Found image: ", file_in_zip, " -- ",
        data = zippedImgs.read(file_in_zip)
        dataEnc = StringIO(data)
        img = Image.open(dataEnc)
        print img
    else:
        print ""

谢谢大家!

我有同样的问题,感谢@alfredox,我修改了答案,在python3中使用io.BytesIO而不是StringIo。

z = zipfile.ZipFile(zip_file)
for i in range(len(z.namelist())):

    file_in_zip = z.namelist()[i]
    if (".jpg" in file_in_zip or ".JPG" in file_in_zip):

        data = z.read(file_in_zip)
        dataEnc = io.BytesIO(data)
        img = Image.open(dataEnc)
        print(img)

不需要使用StringIO。 zipfile 可以读取内存中的图像文件。以下循环遍历 .zip 文件中的所有图像:

import zipfile
from PIL import Image

imgzip = zipfile.ZipFile("100-Test.zip")
inflist = imgzip.infolist()

for f in inflist:
    ifile = imgzip.open(f)
    img = Image.open(ifile)
    print(img)
    # display(img)

如果您需要处理像素数据,那么您可以按照以下步骤从 zip 文件加载图像流数据作为 numpy 数组,保持原始数据形状(即 32x32 RGB):

  1. 使用 zipfile 获取 ZipExtFile 格式
  2. 使用PIL.Image将ZipExtFile转成图像类数据结构
  3. 将PIL.image转换为numpy数组

不需要用原始数据形状重塑 numpy 数组,因为 PIL.Image 已经有了信息。所以输出将是一个 shape=(32,32,3)

的 numpy 数组
import numpy as np
import zipfile
from PIL import Image

with zipfile.ZipFile(zip_data_path, "r") as zip_data:
    content_list = zip_data.namelist()
    for name_file in content_list:
        img_bytes = zip_data.open(name_file)          # 1
        img_data = Image.open(img_bytes)              # 2
        # ndarray with shape=(32,32,3)
        image_as_array = np.array(img_data, np.uint8) # 3

cv2.imdecode() 版本:

with zipfile.ZipFile(zip_data_path, "r") as z:
    for img_name in z.namelist():
        buf = z.read(name)
        np_buf = np.frombuffer(buf, np.uint8)
        img = cv2.imdecode(np_buf, cv2.IMREAD_UNCHANGED)
        # Saving image as an example.
        cv2.imwrite(name, img)