我正在尝试从转向fortran和c++。我主要处理的是巨大的图像,坐标方向是x:从左到右,y:自上而下,像素被存储在行中,这是图像格式中常见的。
Numpy说,它也按行存储矩阵。就好而言,它与fortran/c++保存图像是一样的。但是,请参阅下面的示例,灰色从黑色到白色依次排列。让我们创建第一行为123等的图像3x3。
mat = np.array([1,2,3,4,5,6,7,8,9], 'i1').reshape(3,3)
接下来,我使用下面的代码获取有关矩阵的信息。例程打印:在位置x=1, y=0
的值,在内存中的位置,看数组是否被复制,大步和迭代器。
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)
对于矩阵mat
的C阶,我得到
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=1
和y=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
如您所见,x=1 y=2
的值2是正确的,使用mat[x,y]
是正确的,内存顺序是正确的,但是迭代器是错误的1 4 7 ...
。后果是,保存或显示形象是不好的,所有的交换。不按内存顺序排列的迭代器具有很大的性能惩罚。
问题是:如何用交换的x,y来设置numpy矩阵,而不复制图像和所有其他属性都是C级的。我尝试过设置C_CONTIGUOUS=True,但这是不可能的。
一种方法是使用C-阶,但是在所有这样的矩阵上,必须使用反向索引y,x,问题是它非常混乱,所有的向量都是正规的(x,y,z)
,有些对象使用交换索引顺序。正确的轴的命名顺序有助于进一步的图像空间操作。
也许有可能扩展numpy,使用只返回mat[y,x]
或eg的其他索引方法,比如mat.swap2[x,y]
。mat[*reversed((x,y))]
。但是否有更好的解决办法?
下面是fortran和c++中的两个示例。armadillo矩阵库(因为c/c++似乎没有定义自己的泛型矩阵对象)。这两个示例都使用F顺序,索引正确mat[x,y]
,内存布局与输入图像的二进制布局相同,逐行、迭代器在内存布局中。在我看来奇怪的是,F顺序中的numpy不支持相同的行为。或者我根本就不懂裸体的哲学。
在fortran中,保存和迭代这样的矩阵是按内存顺序进行的(此处未显示)。
...
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++和armadillo中,保存和迭代是按内存顺序进行的(此处未显示)。
#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
...
发布于 2022-01-20 09:33:44
首先,numpy对于列主要模式有令人困惑的术语,对于2D和更多的模式,F_CONTIGUOUS
在内存中从不是连续的。它就像视图的设计和内存布局总是C
。由于性能原因和您指定的轴分配,像许多人一样使用列的主要顺序是比较自然的,但在numpy中并不容易。
此外,内置/扩展不允许仅使用setattr()
直接扩展numpy类,但您可以派生自己的类。
为了在numpy中简单起见,始终使用默认的C
顺序(行大顺序)和交换轴作为mat[z,y,x]
。在我看来,这似乎是最不令人困惑的。
https://stackoverflow.com/questions/70745254
复制