【问题标题】:stack images as numpy array faster (than preallocation)?将图像堆栈为 numpy 数组更快(比预分配)?
【发布时间】:2014-06-18 11:22:17
【问题描述】:

我经常需要堆叠 2d numpy 数组(tiff 图像)。为此,我首先将它们附加到一个列表中并使用 np.dstack。这似乎是获得 3D 阵列堆叠图像的最快方法。但是,有没有更快/内存效率更高的方法?

from time import time
import numpy as np

# Create 100 images of the same dimention 256x512 (8-bit). 
# In reality, each image comes from a different file
img = np.random.randint(0,255,(256, 512, 100))

t0 = time()
temp = []
for n in range(100):
    temp.append(img[:,:,n])
stacked = np.dstack(temp)
#stacked = np.array(temp)  # much slower 3.5 s for 100

print time()-t0  # 0.58 s for 100 frames
print stacked.shape

# dstack in each loop is slower
t0 = time()
temp = img[:,:,0]
for n in range(1, 100):
    temp = np.dstack((temp, img[:,:,n]))
print time()-t0  # 3.13 s for 100 frames
print temp.shape

# counter-intuitive but preallocation is slightly slower
stacked = np.empty((256, 512, 100))
t0 = time()
for n in range(100):
    stacked[:,:,n] = img[:,:,n]
print time()-t0  # 0.651 s for 100 frames
print stacked.shape

# (Edit) As in the accepted answer, re-arranging axis to mainly use 
# the first axis to access data improved the speed significantly.
img = np.random.randint(0,255,(100, 256, 512))

stacked = np.empty((100, 256, 512))
t0 = time()
for n in range(100):
    stacked[n,:,:] = img[n,:,:]
print time()-t0  # 0.08 s for 100 frames
print stacked.shape

【问题讨论】:

  • 你可以避免调用dstack,只要保证temp中的所有数组满足这个条件,你就可以简单地调用stacked = np.concatenate(temp,axis=2),这样可以节省少量的python开销时间。如果您显示更多代码,可能会有更好的方法来做到这一点,但如图所示,顶部代码几乎是最佳的。
  • temp 中的数组都是 2D 的,我想连接起来得到一个 3D 数组。因此,np.concatenate(temp, axis=2) 将产生错误:axis 2 out of bounds [0, 2)。 np.concatenate(temp, axis=1) 将创建一个二维数组 (256x51200)。
  • 我错过了我评论的关键部分,它应该是“...如果满足此条件,temp 中的所有数组都是 3D ......”。应该注意的是,这种节省是微不足道的,除了非常大的临时尺寸,可能在每个阵列约 2us 的数量级上。

标签: python arrays image numpy


【解决方案1】:

在与 otterb 的共同努力下,我们得出结论,预分配数组是可行的方法。显然,性能瓶颈是数组布局,图像编号 (n) 是变化最快的索引。如果我们将 n 设为数组的第一个索引(默认为“C”排序:第一个索引变化最慢,最后一个索引变化最快)我们将获得最佳性能:

from time import time
import numpy as np

# Create 100 images of the same dimention 256x512 (8-bit). 
# In reality, each image comes from a different file
img = np.random.randint(0,255,(100, 256, 512))

# counter-intuitive but preallocation is slightly slower
stacked = np.empty((100, 256, 512))
t0 = time()
for n in range(100):
    stacked[n] = img[n]
print time()-t0  
print stacked.shape

【讨论】:

  • 谢谢!我还认为预分配应该是最快的,但不知何故它会稍微慢一些。我更新了我的问题以包括预分配。知道为什么吗?
  • 嗨,这确实很有趣,我敢打赌它会更快。假设您将时间索引作为第一个索引时是否会有所不同(想法是您编写的块可以更容易地访问)。猜测为什么它可能会变慢是数组的索引有一些开销,例如允许负数。使用 cython,您可以摆脱那些...
  • 你的意思是stacked[n,:,:]而不是stacked[:,:,n]?好主意。当我可以访问用于分析的同一台 PC 时,我会尝试。
  • 是的!我按照您的建议重新排列了轴。现在它明显更快。我已经接受了您的回答,但是您能否修改您的回答以澄清第一个轴??
  • 嗨 otterb,感谢您的努力。真的很高兴它有效。我必须说我也从中学到了一些东西。我以一种对其他人有用并反映您的贡献的形式给出了答案。您愿意提供您获得的性能,以便我们也可以将其放入其中吗?
猜你喜欢
  • 2015-10-15
  • 2019-12-07
  • 1970-01-01
  • 2019-12-01
  • 2014-05-13
  • 1970-01-01
  • 2018-06-18
  • 2017-05-09
相关资源
最近更新 更多