Matlab API 从 C++ 读取 .mat 文件,使用 STL 容器
Posted
技术标签:
【中文标题】Matlab API 从 C++ 读取 .mat 文件,使用 STL 容器【英文标题】:Matlab API reading .mat file from c++, using STL container 【发布时间】:2014-12-01 19:14:00 【问题描述】:我必须从 c++ 中读取一些 .mat 数据文件,我通读了文档,但我想知道如何以干净优雅的方式处理数据,例如使用std:vector(.mat文件大小适中(10M~1G),但内存问题要认真对待)
我的功能是这样的:
#include <stdio.h>
#include "mat.h"
#include <vector>
int matread(const char *file, const vector<double>& pdata_v)
MATFile *pmat;
pmat=matOpen("data.mat","r");
if (pmat == NULL)
printf("Error opening file %s\n", file);
return(1);
mxArray *pdata = matGetVariable(pmat, "LocalDouble");
// pdata -> pdata_v
mxDestroy pa1; // clean up
return 0;
所以,问题是,我怎样才能有效且安全地从 mxArray *pdata 数组复制到向量 pdata_v?
【问题讨论】:
文件很大?内存可能是个问题?我们在谈论什么大小的文件?fgets
并自己跟踪文件指针似乎是一种可行的方法。是的,它很难,但不会对记忆造成压力,而且速度很快。
使用 MATLAB 中的fwrite
并将数据以 C++ 可以轻松读取的简单二进制格式(甚至是内存映射)要容易得多。
【参考方案1】:
可以先获取mxArray *pdata
的数据指针,然后将数据复制到vector<double> pdata_v
:
double *ptr = (double *) mxGetData(pdata);
pdata_v.resize(numOfData);
memcpy(&pdata_v[0], ptr, numOfData*sizeof(double));
ps1:要特别注意,在 MATLAB 中,矩阵是 col-major 的。所以如果pdata
存储[1 2 3; 4 5 6]
,pdata_v
将是1 4 2 5 3 6
。
ps2:如果要更改其内容,请将const vector<double>& pdata_v
更改为vector<double>& pdata_v
。
【讨论】:
感谢 ps1&2!我可以问一下,而不是 memcpy(在我看来更像 c,它是否容易出错?),使用 pdata_v(ptr,ptr+num_elements) 之类的东西是否安全? @lorniper 如果你正确使用它会很安全,尽管它比你提到的 C++ 风格更容易出错。 :) 您的解决方案编译成功但给出“分段错误 11”,我提到的方式在编译时给出错误:“不匹配调用 (std::vectorvector<double> pdata_v
分配内存,例如pdata_v.resize(numOfData)
.
@lorniper:如果你想使用该语法,你可以调用vector::assign
为:pdata_v.assign(ptr, ptr+num);
其中double *ptr = mxGetPr(pdata);
和size_t num = mxGetNumberOfElements(pdata);
【参考方案2】:
这是另一个想法。如果您对 C++ 代码中的裸指针过敏(顺便说一句,它们没有问题),您可以将裸指针包装在 boost 或 C++11 智能指针中,并使用删除器调用正确的mxDestroyArray()
,当指针超出范围。这样您就不需要副本,您的用户代码也不需要知道如何正确解除分配。
typedef shared_ptr<mxArray> mxSmartPtr;
mxSmartPtr readMATarray(MATFile *pmat, const char *varname)
mxSmartPtr pdata(matGetVariable(pmat, varname),
mxDestroyArray); // set deleter
return pdata;
int some_function()
mxSmartPtr pdata = readMATarray(pmat, "LocalDouble");
...
// pdata goes out of scope, and mxDestroy automatically called
取自这里的想法:http://www.boost.org/doc/libs/1_56_0/libs/smart_ptr/sp_techniques.html#incomplete
【讨论】:
充分利用 C++11shared_ptr
来简化使用。我正在记下这个!【参考方案3】:
这里是一个使用MAT-API的例子:
test_mat.cpp
#include "mat.h"
#include <iostream>
#include <vector>
void matread(const char *file, std::vector<double>& v)
// open MAT-file
MATFile *pmat = matOpen(file, "r");
if (pmat == NULL) return;
// extract the specified variable
mxArray *arr = matGetVariable(pmat, "LocalDouble");
if (arr != NULL && mxIsDouble(arr) && !mxIsEmpty(arr))
// copy data
mwSize num = mxGetNumberOfElements(arr);
double *pr = mxGetPr(arr);
if (pr != NULL)
v.reserve(num); //is faster than resize :-)
v.assign(pr, pr+num);
// cleanup
mxDestroyArray(arr);
matClose(pmat);
int main()
std::vector<double> v;
matread("data.mat", v);
for (size_t i=0; i<v.size(); ++i)
std::cout << v[i] << std::endl;
return 0;
首先我们构建独立程序,并将一些测试数据创建为 MAT 文件:
>> mex -client engine -largeArrayDims test_mat.cpp
>> LocalDouble = magic(4)
LocalDouble =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
>> save data.mat LocalDouble
现在我们运行程序:
C:\> test_mat.exe
16
5
9
4
2
11
7
14
3
10
6
15
13
8
12
1
【讨论】:
完全符合我的预期!只是一点,为什么 matGetVariable 而不是 matGetNextVariable ?如果从 mat 文件中读取多个向量,哪个更好? @lorniper:我想让这个例子保持简单。基本上,当您想按名称检索特定变量时,您使用matGetVariable
。如果要遍历 MAT 文件中所有保存的变量,请在循环内使用 matGetNextVariable
。查看 MATLAB 附带的 matdgns.c
示例(查看 $MATLABROOT/extern/examples/eng_mat/
文件夹)
对于导入/导出功能非常有用。不错!
@Amro 只能在 Matlab 本身中使用 mat.h 吗?我们不能在不同的 IDE 中使用它吗?
@Sndn 当然可以。 mex -client engine
是used for convenience,您可以通过指定所需的headers and libs 自行构建应用程序。注意mex -v ..
显示了实际的编译器调用。以上是关于Matlab API 从 C++ 读取 .mat 文件,使用 STL 容器的主要内容,如果未能解决你的问题,请参考以下文章