繁体   English   中英

numpy 是否有可能在不更改 memory 顺序和迭代器的情况下交换矩阵的 x,y?

[英]Is there possibilty in numpy to swap x,y of matrix without changing memory order and iterators?

我正在尝试从fortranc++ 的世界切换到 numpy 主要是我正在处理巨大的图像,其中坐标方向是x:从左到右,y:自上而下,像素存储在行中,常见于图像格式。

Numpy 说它还按行存储矩阵。 就好的而言,它与 fortran/c++ 保存图像相同。 但是,请参阅以下示例,从黑色到白色的灰色行。 让我们创建图像 3x3,其中第一行是 123 等

黑白图像符合预期,带有 matplotlib imshow(mat)

mat = np.array([1,2,3,4,5,6,7,8,9], 'i1').reshape(3,3)

接下来我使用以下代码获取有关矩阵的信息。 例行打印: position x=1, y=0 , position 中的值在 memory 中查看是否复制了数组、步幅和迭代器。

def pr(a):
    x=1; y=0;
    print(a[x,y])
    print(a.ctypes.data, a.strides, a.ravel(order='K'), [x for x in a.flat], a.flatten(order='K'))
    print(a.flags)

对于C 顺序的矩阵mat ,我有

4
94598176807408 (3, 1) [1 2 3 4 5 6 7 8 9] [1, 2, 3, 4, 5, 6, 7, 8, 9] [1 2 3 4 5 6 7 8 9]
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False

所以很明显x,y被交换了,因为对于x=1y=0像素值是 2 而不是 4,所以我已更改为 F 顺序。

# mat = mat.ravel(order='K').reshape(3,3, order='F')
mat.strides = (1,3)
# mat = np.swapaxes(mat, 0, 1)

以上是获得具有相同结果的F 阶的三种可能性。

2
94598176807408 (1, 3) [1 2 3 4 5 6 7 8 9] [1, 4, 7, 2, 5, 8, 3, 6, 9] [1 2 3 4 5 6 7 8 9]
  C_CONTIGUOUS : False
  F_CONTIGUOUS : True

现在,当使用具有相同 memory 布局的 F 订单时,图像被交换

如您所见, x=1 y=2的值 2 是正确的,使用mat[x,y]是正确的,memory 顺序是正确的,但迭代器是错误的1 4 7... 结果是保存或显示图像不好,全部被交换。 不在 memory 订单中的迭代器有很大的性能损失。

问题是:如何在没有图像副本的情况下设置 numpy 矩阵,交换 x,y 并且所有其他属性都与 C 顺序相同。 我尝试设置 C_CONTIGUOUS=True,但这是不可能的。?

一种方法是使用 C 顺序,但在所有此类矩阵上都必须使用反向索引 [y,x],问题是它非常混乱,所有向量都是正常的(x,y,z)并且一些对象使用交换索引顺序.? 轴的正确命名顺序有助于图像的进一步空间操作。

也许有可能扩展numpy ,使用其他索引方法,如mat.swap2[x,y]只返回mat[y,x]或例如。 mat[*reversed((x,y))] 但是有更好的解决方案吗?

接下来是fortranc++中的两个示例,例如。 犰狳矩阵库(因为 c/c++ 似乎没有定义自己的通用矩阵对象)。 两个示例都使用 F 顺序,索引正确mat[x,y] ,memory 布局与输入图像的二进制布局相同,逐行,迭代器在 memory 布局中。 在我看来,F 顺序中的 numpy 不支持相同的行为似乎很奇怪。 或者只是我不明白 numpy 的哲学。

fortran中的示例,保存和迭代此类矩阵按 memory 顺序(此处未显示)。

...
    integer(1) :: mat(0:2,0:2)      ! matrix 3x3 indexing 0,1,2
    data mat /1,2,3,4,5,6,7,8,9/    ! memory order
    print*, mat(1,0)                ! value for x=1 y=0 is 2 ok
...

C++中的示例与犰狳,保存并再次迭代是按 memory 顺序(此处未显示)。

#define ARMA_U8_TYPE   uint8_t
#define ARMA_S8_TYPE    int8_t        // define support for int8 instead of char
#include <armadillo>
...
    using namespace arma;
    int8_t amem[] = {1,2,3,4,5,6,7,8,9};        // memory order
    Mat<int8_t> mat(amem, 3,3,  false,true);    // matrix 3x3
    cout << (int)mat(1,0) << "\n";              // value for x=1 y=0 is 2 ok
...

首先 numpy 对列主模式有混淆的术语, F_CONTIGUOUS在 memory 中对于 2D 等从不连续。 就像按设计查看一样, memory 布局始终为C 出于性能原因和您指定的轴分配,使用列主顺序更自然,但在 numpy 中并不容易。

此外,内置/扩展不允许仅使用setattr()直接扩展 numpy 类,但您可以派生自己的。

为了简单起见, numpy 始终使用默认的C顺序(行主要顺序)并将轴交换为mat[z,y,x] 在我看来,这似乎是最不容易混淆的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM