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 文件中读取数据?