【问题标题】:image stack population is slow in numpynumpy中的图像堆栈填充速度很慢
【发布时间】:2015-03-20 03:12:27
【问题描述】:

我正在通过 numpy/python 将单独的 tiff 堆栈读取到单个 3D 数组中。当文件只是被读取并插入某个变量时,速度与文件数量成线性关系,例如,加载 100 个文件需要 0.2 秒,加载 1000 个文件需要 2.46 秒等等。

但是,当我尝试从这些文件中创建 3D 堆栈时,使用 dstack() 时间开始非线性缩放,例如10个文件0.21秒,100个文件5.39秒等等。

我意识到减速是由 dstack() 背后的一些魔法造成的。从一组图像文件创建 3D 堆栈的正确和最快的方法是什么?

如果我不使用 dtack(),而是预先创建 3D 数组然后填充它,脚本运行得更快,但仍然非线性缩放(0.2s 用于 10,2.2s 用于 100,40s 用于 1000 个图像) 本案例代码:

import numpy as np
from PIL import Image
import time
import random

def toc(t):
    return time.time() - t

i_max = 1000
t = time.time()
for i in range(0,i_max):
    fname = r"..\Pos0\img_"+("%09d"%i)+"_Default_000.tif"
    im = np.array(Image.open(fname))
    if i>0:
        stack[:,:,i] = im
    else:
        s = im.shape
        stack = np.empty((s[0],s[1],i_max))
        stack[:,:,0] = im
print toc(t)

PS:Python 2.7.8 Anaconda 2.1,Intel i5 @ 32GB RAM,从 4-striped HDD 读取

【问题讨论】:

  • 每张图片有多大 (MB)?如果您超出了可用 free RAM 的数量,这将解释从 100 到 1000 个图像的非线性增加,因为某些对象需要存储在交换内存上。从 10 到 100 的增加是线性的,您关于未预分配的猜测是正确的。
  • 单个 tiff
  • 除了索引之外,如果您需要经常加载相同的图像序列,值得首先将其转换为一个包含原始字节的大文件。一个转换工具,比如Imagemagick,可以做到这一点并尝试使用多核,所以如果速度很重要,它会比使用 python 脚本转换更快。
  • 问题是,我使用 MicroManager 获取图像,所以从技术上讲,我首先可以拥有单个文件堆栈。会更好吗,我有 >27k z 切片(或时间点,即 3D 图像)?我也希望能够从这 27k 帧中删除子堆栈

标签: python image numpy


【解决方案1】:

您可以通过更改索引顺序来解决此问题,首先使图像索引。像这样:

i_max = 1000
sx, sy = 1000,1000
t = time.time()
for i in range(0,i_max):
    im = np.ones((sx,sy))
    if i>0:
        #stack[:,:,i] = im
        stack[i,:,:] = im
    else:
        #stack = np.empty((sx,sy,i_max))
        #stack[:,:,0] = im
        stack = np.empty((i_max, sx, sy))
        stack[0,:,:] = im
print toc(t)

我得到的时间是:

4.44851183891   # original order, i_max = 100
118.510767937   # original order, i_max = 1000

1.78239989281   # modified order, i_max = 100
23.4904351234   # modified order, i_max = 1000

我认为这样做的原因是数据不是逐位处理的,而是以固定大小的块的形式处理的,而不管每个块中实际使用了多少数据。根据您的原始订单,这些块没有得到有效使用。例如,看这个视频的前几分钟:https://vimeo.com/97337258 也就是说,它不是关于 RAM,而是关于 CPU 缓存。

【讨论】:

  • 很好地调用内存排序。或者,将数组初始化为 fortran 排序并使用 OP 的原始索引样式应该可以解决相同的问题,并且具有使索引保持更逻辑顺序的优点。
  • 这似乎是一个疯狂的解决方案。你可以想象,我不关心索引,(t,x,y) 和 (y,t,x) 一样好。
  • 非常感谢您的帮助。更改索引或 fortran 排序可以解决问题,order='F' 的速度要慢 2 倍。没想到这么简单。但是,是否有从单独的图像文件编译 3D 堆栈的行业标准,或者就是这样?
  • 这不是“图像”特定问题。这只是一个numpy 数组构造。这是一种方式。 np.array([make_array(i) for i in range(n)]) 是另一个,它与使用列表附加相同。至少在这种情况下,索引分配是更快的方法。
  • @aandreev:我认为没有“行业标准”。然而,图像堆叠并不少见,例如,在图像自然堆叠的专业中,如共焦显微镜(它们被称为“z 堆叠”)。我认为人们通常遵循指南而不是标准,将他们想要阅读的数据点放在一起。因此,如果您收集了一个图像堆栈,但又想处理垂直平面,则旋转堆栈是有意义的(这就是我不进行 Fortran 排序的原因,所以我的排序可以邮寄并且不会混淆)。
猜你喜欢
  • 2016-06-28
  • 1970-01-01
  • 2017-01-13
  • 1970-01-01
  • 2018-05-21
  • 1970-01-01
  • 2014-12-13
  • 2017-07-19
  • 1970-01-01
相关资源
最近更新 更多