【发布时间】:2017-10-20 01:44:36
【问题描述】:
我正在尝试找到将一堆图像从目录读取到 numpy 数组中的最快方法。我的最终目标是计算所有这些图像中像素的最大、最小和第 n 个百分位数等统计数据。当所有图像的像素都在一个大的 numpy 数组中时,这很简单快速,因为我可以使用内置数组方法,例如 .max 和 .min,以及 np.percentile 函数。
以下是 25 张 tiff 图像(512x512 像素)的几个示例时序。这些基准来自在 jupyter-notebook 中使用 %%timit。差异太小,仅对 25 张图像没有任何实际意义,但我打算在未来阅读数千张图像。
# Imports
import os
import skimage.io as io
import numpy as np
-
添加到列表
%%timeit imgs = [] img_path = '/path/to/imgs/' for img in os.listdir(img_path): imgs.append(io.imread(os.path.join(img_path, img))) ## 32.2 ms ± 355 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) -
使用字典
%%timeit imgs = {} img_path = '/path/to/imgs/' for img in os.listdir(img_path): imgs[num] = io.imread(os.path.join(img_path, img)) ## 33.3 ms ± 402 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
对于上面的列表和字典方法,我尝试用相应的理解替换循环,在时间上具有相似的结果。我还尝试过预分配字典键,但所用时间没有显着差异。要将图像从列表中获取到大数组中,我会使用 np.concatenate(imgs),这只需要大约 1 毫秒。
-
沿第一维预分配一个 numpy 数组
%%timeit imgs = np.ndarray((512*25,512), dtype='uint16') img_path = '/path/to/imgs/' for num, img in enumerate(os.listdir(img_path)): imgs[num*512:(num+1)*512, :] = io.imread(os.path.join(img_path, img)) ## 33.5 ms ± 804 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) -
沿第三维预分配一个 numpy
%%timeit imgs = np.ndarray((512,512,25), dtype='uint16') img_path = '/path/to/imgs/' for num, img in enumerate(os.listdir(img_path)): imgs[:, :, num] = io.imread(os.path.join(img_path, img)) ## 71.2 ms ± 2.22 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
我最初认为 numpy 预分配方法会更快,因为循环中没有动态变量扩展,但似乎并非如此。我发现最直观的方法是最后一种方法,其中每个图像沿数组的第三轴占据一个单独的维度,但这也是最慢的。花费的额外时间不是由于预分配本身,它只需要大约 1 毫秒。
我对此有三个问题:
- 为什么 numpy 预分配方法不比字典和列表解决方案快?
- 将数千张图像读入一个大型 numpy 数组的最快方法是什么?
- 我可以从 numpy 和 scikit-image 之外寻找更快的模块来读取图像吗?我试过
plt.imread(),但scikit-image.io模块更快。
【问题讨论】:
-
您是否尝试过初始化
(25, 512, 512)数组?第一个维度是外部维度。第一个列表方法中的np.array(imgs)会产生这种形状。这 33 毫秒的大部分时间是加载,而不是存储。为了测试这一点,尝试在不累积数组的情况下加载。 -
谢谢@hpaulj!您关于外部尺寸的提示以及我花费的大部分时间都来自开销是有帮助的。我尝试了 300 个更高分辨率的 tiff(1024x1024 像素),而 numpy 外部维度方法([300, 1024, 1024] 或 [1024, 300, 1024])现在是最快的(~1s)。其次是列表和字典解决方案(~1.7s),numpy inner(?) 维度 [1024, 1024, 300] 是最后一个(~4.6s)。如果您添加答案,我可以添加这些基准并接受它。
-
@hpaulj 如果您可以添加一个链接来更详细地说明第一个(和第二个?)维度是外部维度的含义,我将不胜感激。我在搜索中找不到任何相关内容。
-
查找
order,如C ordervF order。 -
完全跳过加载阶段怎么样?选项 1:
numpy.memmap / numpy.load(..., mmap_mode="r")选项 2:blaze
标签: python image performance numpy