我正在考虑 Matlab 矩阵和 Python numpy 数组的问题。我有一个医学图像处理代码,给定一个 3D 数组作为输入(512x512 图像,80 个切片 -> 大小(图像)= (512,512,80)。 输入最初由 NifTI 结构给出。 当我在 matlab 中加载 Nii 文件时,我得到的大小为 512x512x80。 当我在 python 中加载 Nii 文件时,我得到 80x512x512 大小(带有 array.shape)
通过尝试测试矩阵,我发现: Matlabs 大小语法:(x = 行,y = 列,z = 第三维切片) 大小的 python 语法:(z = 第三个维度的切片,x = 行,y = 列)
现在我必须测试另一个数据,不是以 nii 文件形式给出,而是保存在 mat 文件中。 使用 Scipy 的 loadmat,我可以轻松地将矩阵加载到我的 python 程序中。 但是:现在,Python 中的矩阵大小现在也是 (512,512,80),以下代码现在在第 3 维中采用 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
与
save a.mat a
我将 a 保存在 mat 文件中。 现在我继续我的 python 代码,使用 import scipy.io as 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)
但这是错误的!它在 3 维中没有 4 个切片,而只是一个 3x4 矩阵。 我应该是:
[[[ 1 2 3]]
[[ 4 5 6]]
[[ 7 8 9]]
[[10 11 12]]]
with shape (4,1,3)
那么,如何以准确的 python 顺序加载 Matlab-Matrices,以便我的代码采用正确的切片? 此外,我有兴趣再次将生成的 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 只是可视化 3 维数组的方式不同。
请注意,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)
如果您只想转置第二个和最后一个轴(如您的示例中所示),您可以使用 swapaxes
来实现:
python> a = np.ascontiguousarray(np.swapaxes(a, 1, 2))
请注意,ascontigiousarray
会将数组(如果需要)复制到 C 顺序连续内存块。更有效地进行进一步的 numpy 处理例程。
最后,我们来看一个带有虚拟样本a
矩阵的示例:
>>> np.swapaxes(a, 1, 2)
array([[[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12]]], dtype=uint8)
我仍然会用 np.ascontigouslyarray
包装它,以确保数据被复制到新的内存块!
关于python - 通过 scipy.io.loadmat 将 matlab 3D 矩阵传输到 python 3D 数组会出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37117779/