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