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&lt;double&gt; 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&lt;double&gt;&amp; pdata_v 更改为vector&lt;double&gt;&amp; pdata_v

【讨论】:

感谢 ps1&2!我可以问一下,而不是 memcpy(在我看来更像 c,它是否容易出错?),使用 pdata_v(ptr,ptr+num_elements) 之类的东西是否安全? @lorniper 如果你正确使用它会很安全,尽管它比你提到的 C++ 风格更容易出错。 :) 您的解决方案编译成功但给出“分段错误 11”,我提到的方式在编译时给出错误:“不匹配调用 (std::vector)(double*& ,double*)" @lorniper 在此之前,请确保您已为 vector&lt;double&gt; 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++11 shared_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 容器的主要内容,如果未能解决你的问题,请参考以下文章

从 C++ 文件中导入 5 级 MAT 文件格式数据

qt creator 中读写.mat文件

用C读取matlab的mat文件

在 R 中使用 foreach 循环读取 MATLAB .mat 文件时出现问题

Matlab使用键值数据读取和分析 MAT 文件

matlab中如何读取mat文件的矩阵