我试图找到最快的方法将一堆图像从目录读取到numpy数组中。我的最终目标是计算所有这些图像中像素的最大,最小和第n个百分点之类的统计信息。当所有图像中的像素位于一个大的numpy数组中时,这是直接且快速的,因为我可以使用诸如.max
和的内置数组方法.min
以及np.percentile
函数。
以下是一些带有25张tiff图像(512x512像素)的时序示例。这些基准来自%%timit
一本jupyter笔记本中的使用。差异太小,不足以对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)))
使用字典
%%timeit
imgs = {}
img_path = ‘/path/to/imgs/’
for img in os.listdir(img_path):
imgs[num] = io.imread(os.path.join(img_path, img))
对于上面的列表和字典方法,我尝试用相应的理解替换循环,并在时间上获得相似的结果。我还尝试了预分配字典键,但所花费的时间没有明显差异。为了将图像从列表传递到一个大数组,我将使用np.concatenate(imgs)
,它只需要大约1毫秒。
沿第一个维度预分配一个numpy数组
%%timeit
imgs = np.ndarray((51225,512), dtype=’uint16’)
img_path = ‘/path/to/imgs/’
for num, img in enumerate(os.listdir(img_path)):
imgs[num512:(num+1)*512, :] = io.imread(os.path.join(img_path, img))
沿第三维预分配一个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))
我最初认为numpy的预分配方法会更快,因为循环中没有动态变量扩展,但是事实并非如此。我发现最直观的方法是最后一个,其中每个图像沿数组的第三个轴占据一个单独的维度,但这也是最慢的。所花费的额外时间不是由于预分配本身而引起的,预分配本身仅花费〜1
ms。
我对此有三个问题:
plt.imread()
,但是scikit-image.io
模块更快。A部分:访问和分配NumPy数组
按照NumPy数组以行优先顺序存储元素的方式,每次迭代沿最后一个轴存储这些元素时,您做的正确。这些将占用连续的内存位置,因此对于访问和分配值将是最有效的。因此,像注释中提到的那样,初始化类似np.ndarray((512*25,512), dtype='uint16')
或np.ndarray((25,512,512), dtype='uint16')
最好的初始化。
将它们编译为用于测试时序并以随机数组(而不是图像)进行馈入的函子后,
N = 512
n = 25
a = np.random.randint(0,255,(N,N))
def app1():
imgs = np.empty((N,N,n), dtype='uint16')
for i in range(n):
imgs[:,:,i] = a
# Storing along the first two axes
return imgs
def app2():
imgs = np.empty((N*n,N), dtype='uint16')
for num in range(n):
imgs[num*N:(num+1)*N, :] = a
# Storing along the last axis
return imgs
def app3():
imgs = np.empty((n,N,N), dtype='uint16')
for num in range(n):
imgs[num,:,:] = a
# Storing along the last two axes
return imgs
def app4():
imgs = np.empty((N,n,N), dtype='uint16')
for num in range(n):
imgs[:,num,:] = a
# Storing along the first and last axes
return imgs
时间-
In [45]: %timeit app1()
...: %timeit app2()
...: %timeit app3()
...: %timeit app4()
...:
10 loops, best of 3: 28.2 ms per loop
100 loops, best of 3: 2.04 ms per loop
100 loops, best of 3: 2.02 ms per loop
100 loops, best of 3: 2.36 ms per loop
这些定时确认在一开始提出的表演理论,虽然我预期的最后一个设置时序有定时的药粥之间app3
和app1
,但也许从最后要到第一线,用于访问和分配的影响不是线性的。关于这一方面的更多研究可能会很有趣(在此处跟踪问题)。
为了示意性地说明,考虑我们正在存储图像数组,分别由x
(图像1)和o
(图像2)表示,我们将有:
应用1:
[[[x 0]
[x 0]
[x 0]
[x 0]
[x 0]]
[[x 0]
[x 0]
[x 0]
[x 0]
[x 0]]
[[x 0]
[x 0]
[x 0]
[x 0]
[x 0]]]
因此,在内存空间中,将是:[x,o,x,o,x,o..]
遵循行优先顺序。
App2:
[[x x x x x]
[x x x x x]
[x x x x x]
[o o o o o]
[o o o o o]
[o o o o o]]
因此,在内存空间中,它将为:[x,x,x,x,x,x...o,o,o,o,o..]
。
App3:
[[[x x x x x]
[x x x x x]
[x x x x x]]
[[o o o o o]
[o o o o o]
[o o o o o]]]
因此,在存储空间上,它将与前一个相同。
B部分:从磁盘读取图像作为数组
现在,关于读取图像的部分,我已经看到OpenCV的imread
速度要快得多。
作为测试,我从Wiki页面下载了Mona Lisa的图像,并测试了图像读取的性能-
import cv2 # OpenCV
In [521]: %timeit io.imread('monalisa.jpg')
100 loops, best of 3: 3.24 ms per loop
In [522]: %timeit cv2.imread('monalisa.jpg')
100 loops, best of 3: 2.54 ms per loop
问题内容: 要求: 我需要从数据中任意增加一个数组。 我可以猜测大小(大约100-200),但不能保证每次都适合该数组 一旦增长到最终大小,我就需要对其进行数值计算,因此我更希望最终使用二维numpy数组。 速度至关重要。例如,对于300个文件之一,update()方法被称为4500万次(大约需要150秒),而finalize()方法被称为500k次(总共需要106s)……总共需要250s或者。
问题内容: 我知道我可以像下面这样: 但是,由于它做了完整的排序,所以它非常慢。 我想知道numpy是否提供一些可以快速完成的方法。 问题答案: 该模块具有一种快速的局部排序方法,可直接与Numpy数组配合使用:。 请注意,返回的是已排序的实际值,如果要使用已排序的值的索引(返回值),则应使用。 我已经进行了基准测试: 其中是一个随机的1,000,000个元素的数组。 时间安排如下: :每个循环2
问题内容: 我正在尝试从Matplotlib图中获取一个numpy数组图像,目前正在通过保存到文件中,然后再读回文件的方式来完成此操作,但是我觉得必须有一种更好的方法。这是我现在正在做的事情: 我尝试了这个: 从我发现的示例中发现,但是它给我一个错误,指出“ FigureCanvasAgg”对象没有属性“ renderer”。 问题答案: 为了获得图形内容作为RGB像素值,需要首先绘制画布的内容。
问题内容: 假设我有数组和围棋。什么是追加的所有值最快的方式来? 问题答案: Go中的数组是次要的,而 切片 则是方法。Go提供了一个内置功能来附加切片: 输出: 在Go Playground上尝试一下。 笔记: Go中的数组是固定大小的:创建数组后,就无法增加其大小,因此无法向其添加元素。如果需要,您将需要分配一个更大的新数组。大到足以容纳2个数组中的所有元素。切片更加灵活。 Go中的数组是如此
问题内容: 我在AI项目上使用Redis。 这个想法是让多个环境模拟器在许多cpu内核上运行策略。模拟器将体验(状态/操作/奖励元组列表)写入Redis服务器(重播缓冲区)。然后,培训过程将经验作为数据集读取以生成新策略。将新策略部署到模拟器,删除先前运行的数据,然后继续该过程。 大部分经验都记录在“状态”中。通常将其表示为尺寸为80 x 80的大型numpy数组。模拟器会以cpu允许的最快速度生
本文向大家介绍Numpy数组的保存与读取方法,包括了Numpy数组的保存与读取方法的使用技巧和注意事项,需要的朋友参考一下 1. 数组以二进制格式保存 np.save和np.load是读写磁盘数组数据的两个主要函数。默认情况下,数组以未压缩的原始二进制格式保存在扩展名为npy的文件中,以数组a为例 利用这种方法,保存文件的后缀名字一定会被置为.npy 2. 存取文本文件 使用 np.savetxt