Ubuntu 下用 C++ 读写.mat文件

该博客为《Ubuntu 相关》系列博客的第四篇,该系列博客主要对Ubuntu安装各种软件或者库进行一个记录,方便重装系统后快速恢复工作。
这是进项目组以来接受的第一个任务,以此记录实现过程。
此篇紧接上篇实现c++读取.mat文件。


由于项目工程要求,需要使用matlab生成的.mat文件,于是查找了基本使用方法。

C++代码

该代码是这个项目的部分代码,包含了前几篇博客的内容,就借助这个代码解释一下。

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

#include <stdio.h>
#include <stdlib.h>

#include "mclmcrrt.h"//
#include "mclmcr.h"  
#include "matrix.h"  
#include "mclcppclass.h"

#include "predictresult.h"//


using namespace std;  
  
int main() 
{  


    ///初始化应用程序///
    // Set up the application state for the MATLAB Runtime instance created in the application.
    if (!mclInitializeApplication(NULL,0)) 
    {
     	cerr << "could not initialize the application properly" << endl;
    	return -1;
    }
    cout << "I initialize the application properly" << endl;
    
    
    ///读取mat文件//
    MATFile *pmatFile = NULL;
    mxArray *pMxArray = NULL;
    
    // 读取.mat文件(例:mat文件名为"xunlianjitezheng.mat",其中包含"result_feature_5")
    double *result_feature_5;
    char Train_file[100];
    cout << "Please enter the file path of training data:" << endl;
    cin >> Train_file;
    pmatFile = matOpen(Train_file,"r");
    pMxArray = matGetVariable(pmatFile, "result_feature_5");
    // 按列读的数据
    result_feature_5 = (double*) mxGetData(pMxArray);
    size_t M_1 = mxGetM(pMxArray);
    size_t N_1 = mxGetN(pMxArray);
    double Train_date[M_1*N_1];
    for (int i=0; i<M_1; i++)
		for (int j=0; j<N_1; j++)
	    	Train_date[M_1*j+i] = result_feature_5[M_1*j+i];
    matClose(pmatFile);
    mxFree(result_feature_5);
    cout << "OK! I get the result_feature_5 date!" << endl;

    // 读取.mat文件(例:mat文件名为"ceshijitezheng.mat",其中包含"result_feature_test")
    double *result_feature_test;
    char Test_file[100];
    cout << "Please enter the file path of testing data:" << endl;
    cin >> Test_file;
    pmatFile = matOpen(Test_file,"r");
    pMxArray = matGetVariable(pmatFile, "result_feature_test");
    // 按列读的数据
    result_feature_test = (double*) mxGetData(pMxArray);
    size_t M_2 = mxGetM(pMxArray);
    size_t N_2 = mxGetN(pMxArray);
    double Test_date[M_2*N_2];
    for (int i=0; i<M_2; i++)
		for (int j=0; j<N_2; j++)
	    	Test_date[M_2*j+i] = result_feature_test[M_2*j+i];
    matClose(pmatFile);
    mxFree(result_feature_test);
    cout << "OK! I get the result_feature_test date!" << endl;

    //初始化函数库
    // initialize lib,这里必须做初始化!  
    if( !predictresultInitialize())  
    {  
        cout << "Could not initialize libpredictresultInitialize!" << endl;  
        return -1;  
    }
    cout << "I initialize libpredictresultInitialize!" << endl;
    
    
    ///调用predictresult函数//
    // 为变量分配内存空间, maltab只有一种变量,就是矩阵,为了和c++变量接轨,设置成1*1的矩阵  
    // 此处应为【列, 行】!!!
    // 不转换了!!!
    mwArray mwA(M_1, N_1, mxDOUBLE_CLASS); 
    mwArray mwB(M_2, N_2, mxDOUBLE_CLASS);  
    mwArray mwC(1, 1, mxINT8_CLASS);  
    // 调用类里面的SetData函数给类赋值  
    // 此处矩阵赋值,跟一般的不同,其从列开始赋值,所以需要做以下处理:1.上一步创建矩阵空间应为【列, 行】。 2.matlab的输入做一个转置处理。
    // 惊奇的发现,读取mat文件时也是按列读取的,所以不用转换了
    mwA.SetData(Train_date, M_1*N_1);  
    mwB.SetData(Test_date, M_2*N_2);  
    // 调用自己的函数,分类。  
    predictresult(1, mwC, mwA, mwB);  
    // 输出结果
    int Result=mwC.Get(1, 1);
    cout << "Result: " << Result << endl;

    // 后面是一些终止调用的程序  
    // terminate the lib  
    predictresultTerminate();  

    // terminate MCR  
    mclTerminateApplication();  

    return EXIT_SUCCESS;  
}  

代码分解

初始化应用程序

但纯的读取.mat文件不需要这个,如果读取了.mat文件之后需要调用自己的matlab函数,这一步很重要,而且一定要在读取.mat文件的代码之前,否则就会出现段错误(核心已转储)的错误。这个错误我搞了一中午,一直没发现这个错误!!!突然想到整个程序实在RCM Install的环境下运行的,那是不是应该先初始化这个环境,结果就好了!!!

///初始化应用程序///
// Set up the application state for the MATLAB Runtime instance created in the application.
if (!mclInitializeApplication(NULL,0)) 
{
 	cerr << "could not initialize the application properly" << endl;
	return -1;
}
cout << "I initialize the application properly" << endl;

.mat读取部分

 // 读取.mat文件(例:mat文件名为"xunlianjitezheng.mat",其中包含"result_feature_5")
    double *result_feature_5;

	// 为了工程实现,定义一个输入,这个输入是.mat的文件路径+文件名
	// 如:/home/al007/桌面/predictresult/xunlianjitezheng.mat
    char Train_file[100];
    cout << "Please enter the file path of training data:" << endl;
    cin >> Train_file;
	
	// 读取.mat文件
    pmatFile = matOpen(Train_file,"r");
    // 这里的要注意.mat里面的变量名,是这个函数的第二个输入
    pMxArray = matGetVariable(pmatFile, "result_feature_5");
    
    // 注意:按列读的数据,就是先读第一列数据,然后依次按列读取数据。很重要!很重要!!很重要!!!
    result_feature_5 = (double*) mxGetData(pMxArray);
	
	//获取数据的行和列
    size_t M_1 = mxGetM(pMxArray);
    size_t N_1 = mxGetN(pMxArray);
    
    //单纯的读取.mat文件不需要定义一个数组,这是为了跟mwArray传递数据用的
    double Train_date[M_1*N_1];
    for (int i=0; i<M_1; i++)
		for (int j=0; j<N_1; j++)
	    	Train_date[M_1*j+i] = result_feature_5[M_1*j+i];
	    	
    matClose(pmatFile);
    mxFree(result_feature_5);
    
    cout << "OK! I get the result_feature_5 date!" << endl;

调用自己编译的MATLAB函数函数

单纯的调用.mat文件不需要这部分,如果程序涉及到调用MATLAB函数,那就要注意数据的传输!!!

.mat读取部分我们额外定义了一个数组,并把我们读到的数据复制到了数组中,为什么不直接用mat文件的变量直接传数据呢,我试了一下午,数据一直不对,我也不清楚原因(如果有知道的大佬,还请评论区留言,非常感谢!),然后自己的写一个小的demo传入的是数组,发现数据没有问题,那我也就把数据复制到数组中,发现成了!!!

.mat读取是按列读取,mwArray构造数组也是按列来的(在这篇博客已经说明!),所以这个地方放就不要特殊的处理了!!!

///调用predictresult函数//
// 为变量分配内存空间, maltab只有一种变量,就是矩阵,为了和c++变量接轨,设置成1*1的矩阵  
// 此处应为【列, 行】!!!
// 不转换了!!!
mwArray mwA(M_1, N_1, mxDOUBLE_CLASS); 
mwArray mwB(M_2, N_2, mxDOUBLE_CLASS);  
mwArray mwC(1, 1, mxINT8_CLASS);  
// 调用类里面的SetData函数给类赋值  
// 此处矩阵赋值,跟一般的不同,其从列开始赋值,所以需要做以下处理:1.上一步创建矩阵空间应为【列, 行】。 2.matlab的输入做一个转置处理。
// 惊奇的发现,读取mat文件时也是按列读取的,所以不用转换了
mwA.SetData(Train_date, M_1*N_1);  
mwB.SetData(Test_date, M_2*N_2);  
// 调用自己的函数,分类。  
predictresult(1, mwC, mwA, mwB);  
// 输出结果
int Result=mwC.Get(1, 1);
cout << "Result: " << Result << endl;

测试数组输入的demo:

double a[6] = {2.4435e07, 1.46488, 6.15623, 1.22475, 19.4892, 2.03679};
mwArray A(2,3,mxDOUBLE_CLASS);  
A.SetData(a,6);

for (int i=0; i<6; i++)
	cout << a[i] << ", ";
cout << endl;
cout << A << endl;

至此我们已经完成C++读取.mat文件。

生成.mat文件

// 生成.mat文件  
double *outA = new double[M*N];  
    for (int i=0; i<M; i++)  
        for (int j=0; j<N; j++)  
            outA[M*j+i] = A[i][j];  
pmatFile = matOpen("A.mat","w");  
pMxArray = mxCreateDoubleMatrix(M, N, mxREAL);  
mxSetData(pMxArray, outA);  
matPutVariable(pmatFile, "A", pMxArray);  
matClose(pmatFile);  

2022年11月22日更新

创建一个.mat文件

在这里插入图片描述
main.cpp文件

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

#include <stdio.h>
#include <stdlib.h>

#include "mclmcrrt.h"//
#include "mclmcr.h"  
#include "matrix.h"  
#include "mclcppclass.h"


using namespace std;  
  
int main() 
{  
    
    ///初始化应用程序///
    // Set up the application state for the MATLAB Runtime instance created in the application.
    if (!mclInitializeApplication(NULL,0)) 
    {
     	cerr << "could not initialize the application properly" << endl;
    	return -1;
    }
    cout << "I initialize the application properly" << endl;

    ///读取mat文件//
    MATFile *pmatFile = NULL;
    mxArray *pMxArray = NULL;
    
    // 读取.mat文件(例:mat文件名为"matlab.mat",其中包含"a")
    double *a;

    pmatFile = matOpen("/home/f216/matlab.mat","r");
    
    pMxArray = matGetVariable(pmatFile, "a");
    // 按列读的数据
    a = (double*) mxGetData(pMxArray);
    size_t M_1 = mxGetM(pMxArray);
    size_t N_1 = mxGetN(pMxArray);
    
    for (int i=0; i<M_1; i++)
		for (int j=0; j<N_1; j++)
	    	printf("%f \t", a[M_1*j+i]);
        
    matClose(pmatFile);
    mxFree(a);
    cout << "OK! I get the a date!" << endl;

    

    return EXIT_SUCCESS;  
}  

CMakeList.txt文件:

cmake_minimum_required(VERSION 2.8)

project(main)

set(CMAKE_CXX_STANDARD 11)

include_directories("/usr/local/MATLAB/MATLAB_Runtime/v95/extern/include")

add_executable(main main.cpp)

target_link_libraries(main "/usr/local/MATLAB/MATLAB_Runtime/v95/bin/glnxa64/libmwmclmcr.so")

target_link_libraries(main "/usr/local/MATLAB/MATLAB_Runtime/v95/runtime/glnxa64/libmwmclmcrrt.so")

运行结果:

在这里插入图片描述

参考博客:
https://blog.csdn.net/lien0906/article/details/42921969
https://blog.csdn.net/left_la/article/details/8206645

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值