通过scipy.io.loadmat将matlab 3D矩阵传输到python 3D数组是错误的

通过scipy.io.loadmat将matlab 3D矩阵传输到python 3D数组是错误的,python,matlab,numpy,matrix,multidimensional-array,Python,Matlab,Numpy,Matrix,Multidimensional Array,我正在考虑一个有关Matlab矩阵和Python numpy数组的问题。我有一个用于医学图像处理的代码,给定一个3D数组作为输入(512x512个图像,80个切片->大小(图像)=(512512,80)。 输入最初由NifTI结构提供。 当我在matlab中加载Nii文件时,得到的大小是512x512x80。 在python中加载Nii文件时,我得到80x512x512作为大小(使用array.shape) 通过试用TestMatrix,我发现: Matlabs大小语法:(x=行,y=列,z=第

我正在考虑一个有关Matlab矩阵和Python numpy数组的问题。我有一个用于医学图像处理的代码,给定一个3D数组作为输入(512x512个图像,80个切片->大小(图像)=(512512,80)。 输入最初由NifTI结构提供。 当我在matlab中加载Nii文件时,得到的大小是512x512x80。 在python中加载Nii文件时,我得到80x512x512作为大小(使用array.shape)

通过试用TestMatrix,我发现: Matlabs大小语法:(x=行,y=列,z=第三维度的切片) 大小的python语法:(z=第三维度中的切片,x=行,y=列)

现在我必须测试另一个数据,不是作为nii文件提供的,而是保存在mat文件中的。 使用Scipy的loadmat,我可以轻松地将矩阵加载到python程序中。 但是:现在在python中矩阵的大小也是(512512,80),下面的代码现在在第三维中采用512个切片,512行和80列(而不是80个切片,512x512个图像)。 我希望这是可以理解的解释

一个简单的例子:

我通过以下方式在Matlab中加载矩阵:

a = 1:12;
a = reshape(a, [1 3 4])

a(:,:,1) =

     1     2     3


a(:,:,2) =

     4     5     6


a(:,:,3) =

     7     8     9


a(:,:,4) =

    10    11    12

size(a)

ans =

     1     3     4

我将一个文件保存在mat文件中。 现在我继续我的python代码,使用import scipy.io作为spio,我可以访问matfile:

mat = spio.loadmat('a.mat')
a = mat['a']
print(a)

   Output:
[[[1 4 7 10]

  [2 5 8 11]

  [3 6 9 12]]]

print(a.shape)

   Output:
(1,3,4)
但这是错误的!它在三维中没有4个切片,而是一个3x4矩阵。 我应该:

[[[ 1 2 3]]

 [[ 4 5 6]]

 [[ 7 8 9]]

 [[10 11 12]]]

with shape (4,1,3)
那么,如何以python的精确顺序加载Matlab矩阵,从而使我的代码获得正确的切片呢? 此外,我还想再次将生成的python数组转换回matlab矩阵


非常感谢您!

您误解了matlab的可视化:

a(:,:,1) =

     1     2     3
是否意味着
a
的最后一个轴包含
1 2 3
,这意味着第二个轴的第一个元素组是
1 2 3
。Python只显示了完整的数组,matlab显示了该数组的列(我将列调用到第二个轴,假设忽略第一个轴,因为它是空的)

通过键入python,可以检查加载matlab和python的数组是否等效:

>>> a[:, :, 0]
array([[1, 2, 3]], dtype=uint8)
它给出的结果与matlab的可视化结果相同

Python和matlab只是有不同的可视化三维数组的方法


注意,matlab是Fortran排序的,这意味着数组中的列排在第一位,然后是行

matlab> reshape(1:6, [2, 3])
ans =

     1     3     5
     2     4     6
这一次,由于矩阵只有2列,因此可视化是您所期望的。如果您用python加载该矩阵,它也将被正确加载(python足够聪明,可以加载具有Fortran排序的numpy数组)。但是,请注意,当您尝试用python创建等效矩阵时,结果会截然不同:

python> np.arange(1,7).reshape(2, 3)
array([[1, 2, 3],
       [4, 5, 6]])
顺序不同。在numpy中,数组默认为C顺序


最后,对于任何最新的numpy/scipy版本,您应该能够从matlab导入/导出矩阵,而无需任何修改

matlab> a = rand(512, 512, 10);
matlab> save /tmp/a.mat a
然后在python中加载它:

python> a = spio.loadmat('/tmp/a.mat')['a']
python> a.shape
(512, 512, 10)
矩阵是相同的。因此,matlab->python转换没有问题。您似乎只是希望在python中使用转置版本


如果需要pythonic
(10、512、512)
数组,只需将其转置:

python> a = np.ascontiguousarray(a.T)
如果您只想转置第二个轴和最后一个轴(如您的示例中所示),则可以使用
交换键进行转置:

python> a = np.ascontiguousarray(np.swapaxes(a, 1, 2))
请注意,
ascontiguousarray
将把数组(如果需要)复制到一个C顺序的连续内存块中。对于进一步的numpy处理例程来说效率更高


最后,以虚拟样本
a
矩阵为例:

>>> np.swapaxes(a, 1, 2)
array([[[ 1,  2,  3],
        [ 4,  5,  6],
        [ 7,  8,  9],
        [10, 11, 12]]], dtype=uint8)
我仍然会用
np.ascontiguousarray
包装它,以确保数据被复制到新的内存块中

>>> np.swapaxes(a, 1, 2)
array([[[ 1,  2,  3],
        [ 4,  5,  6],
        [ 7,  8,  9],
        [10, 11, 12]]], dtype=uint8)