【问题标题】:numpy: contiguous 3d volume of contiguous 2d slices?numpy:连续 2d 切片的连续 3d 体积?
【发布时间】:2020-09-24 19:16:59
【问题描述】:

我想将几个 2D C 连续图像阵列加载到 3D 卷中,并通过直观的索引访问它们,例如slice3 = volume[:,:,2] 需要对原始串联的一维表示进行一些重塑。

现在,由于我加载了大量图像并从中计算出更多的新卷,这必须在您的普通 PC 上运行,所以我担心内存使用情况以及计算性能。

问:我怎样才能使 3D 体积和 2D 切片保持连续,以便我可以有效地在体积上做一些事情,在单个切片上做一些事情。

这里有一些可以玩的例子:

import numpy as np

# dimensions:
rows   = 2
cols   = 2
slices = 3

# create array
a = np.arange(rows*cols*slices)
print(a)
# [ 0  1  2  3  4  5  6  7  8  9 10 11]
# this is the original concatenated input of the slices [[0,1],[2,3]], [[4,5],[6,7]], [[8,9],[10,11]]

# a contiguous?
print(a.flags['C_CONTIGUOUS'])
# True

a = a.reshape(rows,cols,slices)
print(a)
# a still contiguous?
print(a.flags['C_CONTIGUOUS'])
# True

# what about a slice?
print(a[:,:,0])
# [[0 3]
#  [6 9]]
# ouch! that's not the slice I wanted! I wanted to keep [[0,1],[2,3]] together
# this slice is of course also not contiguous:
print(a[:,:,0].flags['C_CONTIGUOUS'])
# False

# ok, let's start over
a = a.ravel()
print(a)
# [ 0  1  2  3  4  5  6  7  8  9 10 11]
a = a.reshape(slices,rows,cols)
a = a.swapaxes(0,1)
a = a.swapaxes(1,2)
# what about a slice?
print(a[:,:,0])
# [[0 1]
#  [2 3]]
# now that's the kind of slice I wanted!

# a still contiguous?
print(a.flags['C_CONTIGUOUS'])
# False

# slice contiguous?
print(a[:,:,0].flags['C_CONTIGUOUS'])
# True
# only halfway there.. :(

再次声明:有没有办法实现所需的切片索引,同时保持体积以及单个切片 C 连续?

【问题讨论】:

    标签: python numpy


    【解决方案1】:

    选项 1

    不要太在意哪个维度对应slices

    a = a.reshape(slices, rows, cols)
    

    就这样吧。一个很好的副作用是要说切片1,你只需这样做

    a[1]
    

    不需要a[1, :, :] 甚至a[1, ...]

    选项 2

    如果您对slices 对应的维度感到困惑,则必须复制数据以保持连续性。但是,您只需一份副本即可到达那里,而不是使用两次swapaxes

    一种方法是使用transpose:

    a = a.reshape(slices, rows, cols).transpose(1, 2, 0)
    

    或者你可以使用np.moveaxis:

    a = np.moveaxis(a.reshape(slices, rows, cols), 0, -1)
    

    【讨论】:

    • 不错的答案。 NumPy 存储其元素的方式是“C 顺序”,其中“右侧”中的维度比“左侧”中的维度变化得更快。这就是为什么表示切片的维度是第一个更自然的原因。它与例如 MATLAB 的相反,由于 MATLAB 使用“Fortran order”,因此使用最后一个维度作为切片更自然。
    • 感谢您展示了如何可以更优雅地实现它,即使复制是我试图避免的事情。我想我会强迫我的同事[slice row col] 索引。由于行(y 维)和列(x 维)已经与笛卡尔坐标相反,因此在前面具有切片(z 维)至少是一致的(具有仅用一个处理整个切片的良好副作用索引如上所述)。
    【解决方案2】:

    不,3D 数组 a 不可能是 C 连续的,a[:,:,0] 也不可能是 C 连续的。

    为什么?根据定义,一个 C 连续数组在最后一维有一个单位步长,例如

    >>> a = np.arange(rows*cols*slices)
    >>> a = a.reshape(slices,rows,cols)
    >>> print([stride // a.itemsize for stride in a.strides])
    [4, 2, 1]
    

    对于any C-contiguous 数组,对最后一维进行切片会创建一个非C-contiguous 数组,因为它在最后一维中不能有单位步幅:

    >>> b = a[:, :, 0]
    >>> print([stride // b.itemsize for stride in b.strides])
    [4, 2]
    

    如果您希望切片是 C 连续的,则需要在第一个维度上进行切片,并且只对第一个维度进行切片:

    >>> c = a[0, :, :]
    >>> print([stride // c.itemsize for stride in c.strides])
    [2, 1]
    

    【讨论】:

    • 感谢您让我意识到大步
    猜你喜欢
    • 2023-03-22
    • 2017-08-09
    • 2020-04-13
    • 2020-01-15
    • 2015-06-06
    • 2022-10-14
    • 2017-10-22
    • 1970-01-01
    • 2014-08-15
    相关资源
    最近更新 更多