我正在尝试将1.000.000图像的数据集加载到内存中。作为标准的numpy数组(uint8),所有合并的图像都填充了大约100 GB的RAM,但是我需要将其降低到<50 GB,同时仍然能够快速将图像读回到numpy(这就是将所有内容保留在内存中的全部目的)。像blosc这样的无损压缩只会将文件大小减少10%左右,因此我选择了JPEG压缩。最小示例:
import io
from PIL import Image
numpy_array = (255 * np.random.rand(256, 256, 3)).astype(np.uint8)
image = Image.fromarray(numpy_array)
output = io.BytesIO()
image.save(output, format='JPEG')
在运行时,我通过以下方式读取图像:
[np.array(Image.open(output)) for _ in range(1000)]
JPEG压缩非常有效(<10 GB),但是将1000张图像读回到numpy数组所需的时间约为2.3秒,这严重损害了我的实验性能。我正在寻找可以在压缩和读取速度之间取得更好权衡的建议。
答案 0 :(得分:2)
我仍然不确定我了解您要做什么,但是我创建了一些虚拟图像并进行了如下测试。我将展示如何做到这一点,以防其他人想尝试其他方法并想要一个数据集。
首先,我使用 GNU Parallel 和 ImageMagick 创建了1,000张图像,如下所示:
parallel convert -depth 8 -size 256x256 xc:red +noise random -fill white -gravity center -pointsize 72 -annotate 0 "{}" -alpha off s_{}.png ::: {0..999}
这给了我1,000张名为s_0.png
至s_999.png
的图像,图像663看起来像这样:
然后我做了我认为您要尝试做的事情-尽管很难从您的代码中看出:
#!/usr/local/bin/python3
import io
import time
import numpy as np
from PIL import Image
# Create BytesIO object
output = io.BytesIO()
# Load all 1,000 images and write into BytesIO object
for i in range(1000):
name="s_{}.png".format(i)
print("Opening image: {}".format(name))
im = Image.open(name)
im.save(output, format='JPEG',quality=50)
nbytes = output.getbuffer().nbytes
print("BytesIO size: {}".format(nbytes))
# Read back images from BytesIO ito list
start=time.clock()
l=[np.array(Image.open(output)) for _ in range(1000)]
diff=time.clock()-start
print("Time: {}".format(diff))
这需要2.4秒才能从BytesIO对象读取所有1,000张图像并将它们转换为numpy数组。
然后,我通过减少到256种颜色(我同意这是有损的-就像您的方法一样)来对图像进行调色板处理,并保存了一个已调色板化的图像对象列表,稍后我可以通过简单地调用以下命令将其转换回numpy数组:>
np.array(ImageList[i].convert('RGB'))
将数据存储为有色图像可节省66%的空间,因为每个像素仅存储一个字节的调色板索引,而不是RGB的3个字节,因此它比您寻求的50%压缩效果要好。
#!/usr/local/bin/python3
import io
import time
import numpy as np
from PIL import Image
# Empty list of images
ImageList = []
# Load all 1,000 images
for i in range(1000):
name="s_{}.png".format(i)
print("Opening image: {}".format(name))
im = Image.open(name)
# Add palettised image to list
ImageList.append(im.quantize(colors=256, method=2))
# Read back images into numpy arrays
start=time.clock()
l=[np.array(ImageList[i].convert('RGB')) for i in range(1000)]
diff=time.clock()-start
print("Time: {}".format(diff))
# Quick test
# Image.fromarray(l[999]).save("result.png")
现在需要0.2s而不是2.4s-我们希望您未声明的应用程序可以接受颜色准确性的损失:-)