在 Python、C++ 中读写 mat 格式文件

mat 格式是 MATLAB 专有的格式,主要用来保存数组数据。 写此文章目的是为了在 C++、Python、MATLAB 中以 mat 格式文件传递数据,实现混合编程。
Python 读写 mat 格式数据,需要用到 scipy.io 类来实现,非常简单。
C++ 读写 mat 格式数据,需要调用 MATLAB 函数接口,相对繁琐。

1. Python 中读写 mat 格式文件

Python 中读写 mat 格式文件非常简单,用 scipy.io 类中的 loadmat() 和 savemat() 函数直接对 ndarray 数组进行操作。

$ python
>>> import numpy as np
>>> import scipy.io as sio
>>> a = np.arange(9).reshape(3, 3)
>>> print(a)
>>> [[0 1 2]
     [3 4 5]
     [6 7 8]]
>>> sio.savemat('test.mat', {'test': a})

得到 test.mat 格式文件 ,接下来我们导入它

>>> mat = sio.loadmat('test.mat')
>>> test = mat['test']  # 你保存时的名字,这里为 test
>>> print(test)
>>> [[0 1 2]
     [3 4 5]
     [6 7 8]]

2. C++ 中读写 mat 格式文件

首先,我们需要安装 MATLAB,这里以 Windows10 + MATLAB2017b + VS2017 为例。

环境配置

VS2017 中,项目属性 -> VC++ 目录 -> 包含目录,添加以下目录

C:\Program Files\MATLAB\R2017b\extern\include\win64
C:\Program Files\MATLAB\R2017b\extern\include

项目属性 -> VC++ 目录 -> 库目录,添加以下目录

C:\Program Files\MATLAB\R2017b\extern\lib\win64\microsoft

项目属性 -> 链接器 -> 输入 -> 附加依赖项,添加以下项

libmat.lib
libmx.lib
libmex.lib
libeng.lib

Win10 环境变量设置

C:\Program Files\MATLAB\R2017b\bin\win64

测试代码

关于 MATLAB 接口函数说明,可以参见官网:

https://ww2.mathworks.cn/help/matlab/matlab-c-api-to-read-mat-file-data.html

这里我们简单地跑一个测试代码:

raw.mat 文件是我们用 python 保存的一副图像,我们要将这个 raw.mat 用 C++ 读出来,并且保存到另一个 source.mat 文件里

#include <iostream>
#include <mat.h>

using namespace std;

int main()
{
	MATFile *raw, *source;  
	mxArray *img1, *img2;
	uint8_T *img1_data;

	raw = matOpen("raw.mat", "r");
	img1 = matGetVariable(raw, "img1");
	img1_data = (uint8_T *)mxGetData(img1);
	matClose(raw);

	source = matOpen("source.mat", "w");
	img2 = mxCreateNumericMatrix(mxGetM(img1), mxGetN(img1), mxUINT8_CLASS, mxREAL);
	cout << "img2 element size is:" << mxGetElementSize(img2) << endl;  // 每项数据所占字节
	mxSetData(img2, img1_data);
	matPutVariable(source, "testimg", img2);

	matClose(source);
	return 0;
}

这下我们可以把 source.mat 文件用 Python 来读取进行验证,验证结果这里就不给出了。

一些值得注意的地方:

  • 经过我的反复实验发现,按照以下坐标系:mat 文件保存的数组是一维的,对于二维数组,mat 中读取数组是按行(沿 y 轴,即竖轴)优先读取的,numpy 中读取数组是按列(沿 x 轴,即横轴)优先读取的。三维数组中,mat 文件里读取数组按 行 -> 列 -> 通道(y -> x -> z)读取,numpy 中按 通道 -> 列 -> 行(z -> x -> y)读取,numpy 三维数组中,第一面比如 a[0, :, :] 是从上往下看的面(不是从前往后哦),所以我们读写 mat 文件的时候需要注意。
坐标系
  • 创建数组时,需要先申请内存:pData = (double *)mxCalloc(len, sizeof(double)); // 创建一个 len*size 的数据指针
  • 程序结束时,我们需要释放这个指针:mxFree(pData);
  • 程序结束时,需要关闭 mat 文件: matClose(source);
  • 图片是 uint8 格式的,创建数组时,用:img2 = mxCreateNumericMatrix(mxGetM(img1), mxGetN(img1), mxUINT8_CLASS, mxREAL); // mxUINT8_CLASS 指定数据类型,mxREAL代表实数

还有一些其他的注意事项和技巧参考:

C++读写Mat文件:https://zhuanlan.zhihu.com/p/23334508
C++ 读写Matlab的mat文件的注意事项:https://blog.csdn.net/zzzblog/article/details/17560721

3. MATLAB 中读写 mat 格式文件

% 读取 mat 文件
load raw.mat

% 保存 mat 文件,注意:直接 save 会将工作区内所有变量按名字保存
save source.mat

发表评论

您的电子邮箱地址不会被公开。