我正在Kaggle上进行CIFAR挑战。
他们提供了一个.7z的文件,其中包含5万张火车照片。我花了1个小时解压缩它,然后又花了40分钟读取所有文件并将其存储在内存中。
尽量不创建50k文件,因为这是它的瓶颈,我已经安装了pylzma和其他库,但所有这些库都会告诉我该文件无效。
来自bash的7z,可以正确读取文件,并列出文件。因此,我使用Popen
解压缩所有文件,并使用bash7z程序将其放入内存中的字符串中
import subprocess
p = subprocess.Popen(["7z", "e", "-so", "awa.7z"], stdout=subprocess.PIPE).communicate()[0]
我通过查看每个文件的大小,然后从字符串中获得适当的字节,成功地分别获得了每个文件
f1 = p[0][0:2105]
我现在想要的是让Python思考F1文件指针,这样我就可以调用skimage.io.imread,它将转换为合适的结构。或者只需将内存值传递给skimage,它就会为我进行转换。
虽然skimage.io.imread的doc说第一个参数是文件名的字符串,但我发现它也接受类似文件的对象(skimage版本为0.10.0)
所以你可以像这样把图像数据读入内存:
from StringIO import StringIO
with open(filename) as f:
img_data = f.read()
decoded_img_data = skimage.io.imread(StringIO(img_data))
print decoded_img_data
>> OUTPUT:
array([[[235, 230, 234],
[233, 228, 232],
[231, 226, 230],
...,
skimage.io.imread()
的第一个参数是要读取的图像文件的名称,因此您无法使用字符串中的图像数据来欺骗它。选项(按方便顺序):
-
直接使用
imread
软件包-请参阅imread.imread_from_blob()
。这将返回一个numpy.ndarray
(与skimage.io.imread
相同)。您需要知道图像文件类型(jpg、png、gif等),因为这必须作为第二个参数传递:from imread import imread_from_blob img_data = imread_from_blob(f1, 'jpg') >>> img_data array([[[ 23, 123, 149], [ 22, 120, 147], [ 22, 118, 143], ..., etc.
-
将数据写入临时文件,然后使用
imread()
打开该临时文件。imread()
在处理URL时会自己执行此操作。 - 使用命名管道。使用
imread()
打开管道进行读取,然后将数据写入管道。您可能需要线程或多处理来完成此操作
浏览skimage代码,我发现它们可以与另一个图像库PIL集成。这个库有一个函数,可以直接从打开的文件指针中获取图像信息。
在我的例子中,文件指针是StringIO,所以它可以读取数据并识别它的内容。
霍克,谢谢你的帮助。在我看来,你的解决方案也会起作用,但我不想处理图像数据本身。
我已经把代码放在github中了(它只是一个骨架,但可以工作),如果有人感兴趣,下面是精彩的页面http://adrianow.github.io/7z_on_array/
下面是解决方案的一个简短部分:
import numpy as np
from PIL import Image
from StringIO import StringIO
# begin and end of each file
low = 0
up = 0
images = [0] *len(p_f_list)
# get each file from the byte file
for i, f in enumerate(p_f_list):
up += int(f[0])
# get bytes from the array
raw_img = p_f_data.data[low:up]
low = up
# Convert rawImage to Mat
pil_image = Image.open(StringIO(raw_img))
np_image = np.array(pil_image)
images[i] = np_image