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

Posted

技术标签:

【中文标题】Python:如何从内存中的 zip 文件中读取图像?【英文标题】:Python: How to read images from zip file in memory? 【发布时间】:2015-08-02 22:15:55 【问题描述】:

我看到了这个问题的变体,但不是在这个确切的上下文中。我拥有的是一个名为 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)

【问题讨论】:

你的第一个例子对我来说很好,你也可以z = zipfile.ZipFile('100-Test.zip') @alfredox 你检查过z.namelist()[0] 是否是一个图像文件吗? @PadraicCunningham 所以您没有对代码进行任何更改并且它有效吗?我不确定我错过了什么,因为我收到了这些错误。 @ozgur 我只是假设它包含 zipfile 中的第一个文件,我不知道如何测试这是一个图像。 是的,正如@ozgur 暗示的那样,问题可能是压缩文件中的第一项不是有效的图像文件(或者至少你的 PIL 不知道如何解码)。只需打印 z.namelist 即可让您了解您实际打开的是哪个文件 【参考方案1】:

原来的问题是由于图像被压缩在压缩文件的目录中,namelist() 中有一个额外的空元素。以下是检查并遍历 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 ""

谢谢大家!

【讨论】:

【参考方案2】:

没有必要使用 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)

【讨论】:

我刚刚在一个大型压缩 TIFF 文件 (1024*768*116) 上尝试了这个想法。虽然它可能对小文件有好处,但对于大文件来说太慢了。 (> 20 分钟 vs 6 秒未压缩)不过好主意......【参考方案3】:

我有同样的问题,感谢@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)

【讨论】:

【参考方案4】:

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

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

不需要用原始数据形状重塑 numpy 数组,因为 PIL.Image 已经有了信息。所以输出将是一个形状=(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

【讨论】:

【参考方案5】:

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)

【讨论】:

以上是关于Python:如何从内存中的 zip 文件中读取图像?的主要内容,如果未能解决你的问题,请参考以下文章

从 Python3 中的 .zip 文件中提取和读取 [重复]

如何在不使用临时文件的情况下从 Java 中的嵌套 zip 文件中读取数据?

如何使用 spark(python)读取 zip 文件中的 CSV 文件的内容 [重复]

您如何将 zip 文件中的文件作为文本而不是字节读取?

怎么从zip里提取文件 Python

如何读取多个 zip 文件中的所有 csv 文件?