NumPy: 对多通道图像进行跨步操作

4
我在numpy中遇到了一些困惑,主要是关于striding(步幅)的。我正在编写一些代码来进行多通道图像的插值。我将我的图像定义为np.ndarray类型的三维数组,其形状为[HEIGHT x WIDTH x CHANNELS]。我编写的C++代码必须在Matlab和Python中都能运行。对于单通道图像,我的代码可以正常工作,在Matlab中多通道图像也可以正常工作。
为了插值图像,我正在编写一个方法,其中给定一个[M x N x P]数组,您可以提供一组XY子像素坐标,以在图像中进行插值。这与scipy的ndimage.map_coordinates的功能相同。不幸的是,我需要一种插值方法,它在Matlab和Python中产生相同的结果,因此我正在编写自己的插值代码。
我的问题是,Matlab通过将通道连接在一起来排列其三维内存。这意味着对于一个[10, 10, 2]的图像,前100个元素将是第一个通道,而[100,200]元素将是第二个通道。因此,为了索引Matlab连续的内存,我按以下方式索引:
// i is the element of the indices array
// j is the current channel
// F is the image we are indexing
// F_MAX is M * N (the number of pixels per channel)
// N_ELEMS is the total number of elements in the indices array
// f_index is the index in the contiguous array equivalent to the x and y coordinate in the 2D image
for (size_t j = 0; j < N_CHANNELS; j++)
{
  out[i + j * N_ELEMS] = F[f_index + j * F_MAX];
}

我的问题在于numpy按照第三维度对其三维数组进行排序。也就是说,对于一个[10, 10, 2]的数组来说,前两个元素是索引[0, 0, 0][0, 0, 1]。但在Matlab中,它们是索引[0, 0, 0][0, 1, 0]
我认为可以通过在numpy中使用步幅来解决我的问题。然而,我完全无法想出一个适当的步幅模式。因此,针对我这个例子中的[10, 10, 2]数组,请问如何更改步幅(假设是double类型):
>>> np.ones([10,10,2], dtype=np.float64).strides
(160, 16, 8)

如何将其转换为类似Matlab数组索引的形式?

值得一提的是,我知道Matlab和numpy在列优先/行优先方面存在差异。正如我所说,我的方法适用于单通道图像,但在多通道图像上会出现索引错误。

2个回答

4

也许你可以使用np.swapaxes函数,如下所示的ipython示例:

In [1]: a = np.arange(2*2*2).reshape((2,2,2))

In [2]: a
Out[2]: 
array([[[0, 1],
        [2, 3]],

       [[4, 5],
        [6, 7]]])

In [3]: a.flatten()
Out[3]: array([0, 1, 2, 3, 4, 5, 6, 7])

In [4]: np.swapaxes(a,2,1).flatten()
Out[4]: array([0, 2, 1, 3, 4, 6, 5, 7])

编辑:

我认为仅在使用交换轴的数组副本后,内部存储器布局才会发生变化,例如:

In [6]: b = a.swapaxes(1,2)

In [7]: b.strides
Out[7]: (16, 4, 8)

In [8]: b = a.swapaxes(1,2).copy()

In [9]: b.strides
Out[9]: (16, 8, 4)

很好的发现,确实改变轴会像你演示的那样起作用。不幸的是,我仍然无法完全纠正我的问题,所以只能使用宏来更改每个平台上的索引模式。 - BeRecursive

3

创建数组时,您可以指定Fortran顺序:

>>> a = np.ones((10,10,2),dtype=np.float64)
>>> a.strides
(160, 16, 8)
>>> b = np.ones((10,10,2),dtype=np.float64,order='f')
>>> b.strides
(8, 80, 800)

如果数组已经被创建,可以使用np.asfortranarray。但是这会复制数据。 - Daniel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接