从Kaggle竞赛Zip文件读取PIL图片时遇AttributeError错误求助
问题:从Zip文件读取图片时出现AttributeError及numpy转换异常
正在练习Kaggle的「Dogs vs. Cats Redux: Kernels Edition」竞赛,尝试用以下Python代码从训练集Zip文件读取图片:
def get_files_names(zip_file_path): with ZipFile(zip_file_path) as myzip: return myzip.namelist() def get_image(zip_path, image_name): with ZipFile(zip_path) as myzip: with myzip.open(image_name) as myfile: img = Image.open(myfile) return img names = get_files_names(train_file_path) img = get_image(train_file_path, names[1]) img.show()
调用img.show()时出现如下错误:
Traceback (most recent call last): File "/cats_vs_dogs/unrelated_file.py", line 46, in <module> img.show() File "/Users/user/.pyenv/versions/3.7.8-thesis/lib/python3.7/site-packages/PIL/Image.py", line 2205, in show _show(self, title=title, command=command) File "/Users/user/.pyenv/versions/3.7.8-thesis/lib/python3.7/site-packages/PIL/Image.py", line 3167, in _show _showxv(image, **options) File "/Users/user/.pyenv/versions/3.7.8-thesis/lib/python3.7/site-packages/PIL/Image.py", line 3181, in _showxv ImageShow.show(image, title, **options) File "/Users/user/.pyenv/versions/3.7.8-thesis/lib/python3.7/site-packages/PIL/ImageShow.py", line 56, in show if viewer.show(image, title=title, **options): File "/Users/user/.pyenv/versions/3.7.8-thesis/lib/python3.7/site-packages/PIL/ImageShow.py", line 81, in show return self.show_image(image, **options) File "/Users/user/.pyenv/versions/3.7.8-thesis/lib/python3.7/site-packages/PIL/ImageShow.py", line 107, in show_image return self.show_file(self.save_image(image), **options) File "/Users/user/.pyenv/versions/3.7.8-thesis/lib/python3.7/site-packages/PIL/ImageShow.py", line 103, in save_image return image._dump(format=self.get_format(image), **self.options) File "/Users/user/.pyenv/versions/3.7.8-thesis/lib/python3.7/site-packages/PIL/Image.py", line 636, in _dump self.load() File "/Users/user/.pyenv/versions/3.7.8-thesis/lib/python3.7/site-packages/PIL/ImageFile.py", line 247, in load s = read(self.decodermaxblock) File "/Users/user/.pyenv/versions/3.7.8-thesis/lib/python3.7/site-packages/PIL/JpegImagePlugin.py", line 400, in load_read s = self.fp.read(read_bytes) File "/Users/user/.pyenv/versions/3.7.8/lib/python3.7/zipfile.py", line 930, in read data = self._read1(n) File "/Users/user/.pyenv/versions/3.7.8/lib/python3.7/zipfile.py", line 998, in _read1 data += self._read2(n - len(data)) File "/Users/user/.pyenv/versions/3.7.8/lib/python3.7/zipfile.py", line 1030, in _read2 data = self._fileobj.read(n) File "/Users/user/.pyenv/versions/3.7.8/lib/python3.7/zipfile.py", line 753, in read self._file.seek(self._pos) AttributeError: 'NoneType' object has no attribute 'seek'
将图片提取到Mac本地Finder后可正常查看,尝试将RGB图片转为numpy数组np.array(img)时也出现异常,请问哪里操作出错了?
解决方法
问题根源在于PIL的Image.open()采用延迟加载机制:它不会立即读取文件中的图片数据,而是在调用show()、np.array()或其他需要访问像素数据的方法时才会去读取。但你的代码中,当退出with myzip.open(image_name) as myfile:的上下文管理器后,myfile这个文件对象已经被关闭,后续再尝试读取数据时,就会因文件对象失效而抛出AttributeError。
你可以通过以下两种方式解决:
方法一:在文件对象有效时预加载图片数据
修改get_image函数,在myfile打开的上下文内调用img.load(),将图片数据提前加载到内存中:
def get_image(zip_path, image_name): with ZipFile(zip_path) as myzip: with myzip.open(image_name) as myfile: img = Image.open(myfile) img.load() # 立即加载图片内容到内存,脱离文件对象也能访问 return img
方法二:读取二进制数据到内存后再打开
直接读取Zip内图片的二进制内容,用BytesIO包装成内存文件对象,再用Image.open()打开:
from io import BytesIO def get_image(zip_path, image_name): with ZipFile(zip_path) as myzip: img_binary = myzip.read(image_name) # 读取图片的二进制数据 img = Image.open(BytesIO(img_binary)) # 从内存中加载图片 return img
两种方法都能确保图片数据被完整加载到内存中,不再依赖已关闭的Zip文件对象,后续调用img.show()或np.array(img)就能正常执行。
内容的提问来源于stack exchange,提问作者Kenny Smith
相关产品推荐
相关产品推荐

