我正在编写一个 python 模块,它需要计算 1000 多个数组(相同维度)中像素值的平均值和标准差。
我正在寻找最快的方法来做到这一点。
目前我正在遍历数组并使用 numpy.dstack 将 1000 个数组堆叠成一个相当大的 3d 数组......然后将计算第三(?)维度的平均值。每个数组都有形状(5000,4000)。
这种方法需要相当长的时间!
任何人都可以就解决此问题的更有效方法提出建议吗?
也许你可以计算mean
并std
以这样的累积方式(未经测试):
im_size = (5000,4000)
cum_sum = np.zeros(im_size)
cum_sum_of_squares = np.zeros(im_size)
n = 0
for filename in filenames:
image = read_your_image(filename)
cum_sum += image
cum_sum_of_squares += image**2
n += 1
mean_image = cum_sum / n
std_image = np.sqrt(cum_sum_of_squares / n - (mean_image)**2)
这可能受到您从磁盘读取图像的速度的限制。它不受内存限制,因为您一次只有一个图像在内存中。以这种方式计算std
可能会遇到数值问题,因为您可能要减去两个大数。如果这是一个问题,您必须遍历文件两次,首先计算平均值,然后(image - mean_image)**2
在第二遍中累积。
预分配和填充。这将我的运行时间缩短了大约 1000 秒到 20 秒
data_stack = numpy.empty((321, 720, 1000), dtype=numpy.float32)
for index in range(len(data)):
data_stack[0:321,0:720,index] = data[index]
我正在做类似的事情。dstack 不是解决这个问题的好方法。一位同事让我想起了动态数组问题和摊销分析。 http://anh.cs.luc.edu/363/notes/06A_Amortizing.html
当你想扩展一个动态数组时,你需要分配一个新的数组来保存原始数据和新数据。然后将旧数组复制到新数组中,将新数据复制到新数组中。这是一项昂贵的操作。
假设您有一个大小为 10 的数组,并且您想一次向其中添加 2 个项目。要添加第一个项目,您需要将数组扩展为 11 大小并复制 11 个项目(原始 10 + 1 个新项目)。要添加第二个项目,您需要将数组扩展为 12 大小并复制 12 个项目。如果您提前知道要添加 2 个项目,则可以将数组的大小调整为 12,然后只复制 12 个项目而不是总共 23 个。事实证明,每次用完数组的大小都会加倍空间是一个更有效的解决方案。
这在这里如何应用: dstack 不会将 ndarray 的大小加倍,它意味着只分配所需的内存。因此,每次调用 dstack 时,都会将 ndarray 中的所有数据复制到一个新的 ndarray 中,并为新数据留出空间。请注意,每次调用 dstack 的时间都会增加。
如果您想大幅减少计算时间,可以选择多线程解决方案。像这样的python有几个库。