超详细基于Qt平台实现C/C++调用Matlab函数全流程

07-17 1003阅读

超详细基于Qt平台实现C/C++调用Matlab函数全流程

  • Matlab和QT混合编程注意事项
  • Chapter1 超详细基于Qt平台实现C/C++调用Matlab函数全流程
    • 1. 基本调用方式介绍
    • 2. 环境配置
    • 3. 将Matlab程序写成函数形式
    • 4. Matlab配置C编译器,将.m文件转换成动态链接库
      • 4.1 首先检查mcc编译器是否可用
      • 4.2 在Matlab命令行分别输入
      • 4.3 导出动态链接库
      • 5. Qt调用
        • 5.1 在pro文件中添加matlab其他依赖库和头文件搜索路径
        • 5.2 在pro文件中添加外部库
        • 5.3 在工程的头文件中添加生成的matlab库的头文件
        • 6. 在Qt中编写使用DLL内函数代码
        • 7. 遇到问题及解决
        • Chapter2 【Matlab】Qt Matlab混合编程——以曲线拟合为例
          • 一、概要
          • 二、环境介绍
          • 三、Matlab C++链接库的生成
            • 1.配置编译器
            • 2.编写函数
            • 3.编译matlab函数,生成C++可调用的链接库
            • 四、Matlab C++链接库的使用
              • 1.Qt工程的建立
              • 2.Qt程序的编写
              • 3.运行测试
              • 五、总结
              • Chapter3 QT与MATLAB混合编程
              • Chapter4 QTCreater调用MatLab生成的.dll文件
              • Chapter5 Qt与Matlab混合编程中mwArray数组使用详解
              • Chapter6 Matlab中 的 mxArray 和 mwArray
              • Chapter7 [Matlab] MxArray 与 MwArray 使用区别
              • Chapter8 QT与matlab混编及完整错误详解

                Matlab和QT混合编程注意事项

                1.初始化函数一定要先调用。

                2.初始化函数有点耗时。

                3.初始化函数只能调用一次,多次调用只有第一次成功。而且一个exe进程只需要初始化一次就行。

                4.函数中涉及中文的要转toLocal8bit。

                5.大量的警告可以在pro文件中加入DEFINES += QT_DEPRECATED_WARINGS来屏蔽。

                原文链接:https://blog.csdn.net/dongshengya9679/article/details/124765252

                Chapter1 超详细基于Qt平台实现C/C++调用Matlab函数全流程

                原文链接:https://blog.csdn.net/m15279530607_163/article/details/129471386

                1. 基本调用方式介绍

                基于Qt平台实现C/C++调用Matlab函数有三种方式:

                (1)将Matlab函数封装成.dll文件,再在Qt平台上调用.dll文件实现;

                (2)将Matlab函数导出成.exe可执行程序,再在Qt平台上调用.exe可执行程序;

                (3)直接在Qt平台上调用Matlab Engin引擎,这种方法需要计算机上安装有Matlab软件。

                本文是通过第一种方式,将MATLAB代码转成C/C++代码和相关动态链接库进行实现的,其他两种方式具体可以参考:

                Qt调用MATLAB引擎混合编程

                2. 环境配置

                QT调用matlab需要编译器位数一致!!!!!!!不然会出现函数未定义等错误。

                1. QT 5.14.2

                2. MATLAB2020b

                3. MinGW64

                3. 将Matlab程序写成函数形式

                超详细基于Qt平台实现C/C++调用Matlab函数全流程

                在matlab中尝试调用一下看是否正确

                4. Matlab配置C编译器,将.m文件转换成动态链接库

                配置MATLAB的C编译器与Qt的C编译器为MinGW。可以临时设置MinGW环境变量,但是关闭MATLAB后该变量就消失了,下次启动MATLAB需要重新设置。

                4.1 首先检查mcc编译器是否可用

                命令行输入:

                >>!mcc
                

                正常结果如下:

                超详细基于Qt平台实现C/C++调用Matlab函数全流程

                4.2 在Matlab命令行分别输入

                mbuild -setup,选择mex -setup C++ -client MBUILD
                

                超详细基于Qt平台实现C/C++调用Matlab函数全流程

                mex –setup,选择C++
                

                超详细基于Qt平台实现C/C++调用Matlab函数全流程

                需要注意的是,matlab每次重启后,都要重新按以上步骤进行mbuild -setup/mex -setup的配置。

                4.3 导出动态链接库

                超详细基于Qt平台实现C/C++调用Matlab函数全流程

                超详细基于Qt平台实现C/C++调用Matlab函数全流程

                超详细基于Qt平台实现C/C++调用Matlab函数全流程

                5. Qt调用

                5.1 在pro文件中添加matlab其他依赖库和头文件搜索路径

                INCLUDEPATH += D:/Matlab_2020_anzhuang/extern/include
                INCLUDEPATH += D:/Matlab_2020_anzhuang/extern/include/win64
                LIBS += D:/Matlab_2020_anzhuang/extern/lib/win64/mingw64/libeng.lib
                LIBS += D:/Matlab_2020_anzhuang/extern/lib/win64/mingw64/libmat.lib
                LIBS += D:/Matlab_2020_anzhuang/extern/lib/win64/mingw64/libmx.lib
                LIBS += D:/Matlab_2020_anzhuang/extern/lib/win64/mingw64/libmex.lib
                LIBS += D:/Matlab_2020_anzhuang/extern/lib/win64/mingw64/mclmcr.lib
                LIBS += D:/Matlab_2020_anzhuang/extern/lib/win64/mingw64/mclmcrrt.lib
                (根据自己MATLAB安装位置来修改)
                

                5.2 在pro文件中添加外部库

                在工程文件上右键,选择添加库

                超详细基于Qt平台实现C/C++调用Matlab函数全流程

                超详细基于Qt平台实现C/C++调用Matlab函数全流程

                超详细基于Qt平台实现C/C++调用Matlab函数全流程

                点击浏览选择库,之后勾掉Linux和Mac,且勾掉为debug版本添加’d’作为后缀。

                点击下一步,会发现你的.pro文件中多了几行:

                win32: LIBS += -L$$PWD/./ -ldetect_anomaly_11
                INCLUDEPATH += $$PWD/.
                DEPENDPATH += $$PWD/.
                

                5.3 在工程的头文件中添加生成的matlab库的头文件

                超详细基于Qt平台实现C/C++调用Matlab函数全流程

                6. 在Qt中编写使用DLL内函数代码

                1. DLL初始化

                2. 函数的输入输出参数

                mwArray是MATLAB的数组类,MATLAB编译生成的DLL的接口函数的参数都是采用mwArray类型。

                在调用时,需要将输入输出参数用到的mwArray定义,才能使用。

                3. mwArray类使用

                参考:mwArray类使用

                7. 遇到问题及解决

                参考问题解决

                Chapter2 【Matlab】Qt Matlab混合编程——以曲线拟合为例

                原文链接:https://blog.csdn.net/spiremoon/article/details/112234360

                一、概要

                在编写Qt应用时,若想用到比较复杂的算法,如拟合、FFT等,没有现成的C/C++库。而这些在Matlab中都是很容易实现的,那么有没有一种方法可以让Qt“不劳而获”得调用Matlab的算法呢?

                其实方法有两种:

                1. 对于不同编程语言,完全可以通过【公共内存】的方式实现交互,这类似于进程间通讯。简单来说,可以Qt与Matlab共同读写同一文件,比如Qt将原始数据放入文件,Matlab检测到后对原始数据进行计算,然后将结果放到这个文件中供Qt读取。
                2. Matlab的m文件可以编译为Qt可以调用的.lib .dll C++链接库,Qt加载链接库并包含头文件后,可以在C++环境下实现m文件同样的计算效果。这也是本文主要讲解的方式。

                二、环境介绍

                编译器:MingW64 C++

                Qt:Qt5.13.0

                Matlab:2018b

                首先说明下为什么使用MingW64编译器。安装Qt时要选择安装MingW64,通常为了使应用程序能跨平台运行,一般选择MingW编译器来编译,而不是微软平台的MSVS。同时,Qt和Matlab混编时,若使用MSVS编译器,还需要安装VS2013等,耗费十几G硬盘空间,并且Qt使用MSVS编译器会出现各种各样的问题,不建议使用。

                再说下matlab版本,实测过2018b和2020a都可以实现混编,其实只要安装完matlab后,只要在安装目录下的bin\win64\mexopts文件夹中含有mingw64.xml即可。这在较早版本中是不支持的,如2014版本。所以想要混编最好使用2018及以上的版本。

                三、Matlab C++链接库的生成

                1.配置编译器

                安装Qt时选了MingW64之后,在Qt的安装目录下会有mingw730_64文件夹,如

                D:\Qt5.13\Tools\mingw730_64
                

                这个文件夹就是mingw64的编译器,我们只需要配置matlab让其找到编译器即可的。

                添加编译器目录到环境变量,如下图所示。

                超详细基于Qt平台实现C/C++调用Matlab函数全流程

                此时在matlab命令行中输入

                mbuild -setup
                

                就能看到mingw的编译器了。如果还不行,那么可以手动在matlab命令行中配置环境变量:

                setenv('MW_MINGW64_LOC','D:\Qt5.13\Tools\mingw730_64')
                

                之后输入mbuild -setup则会出现mingw编译器,如下所示:

                >> mbuild -setup
                MBUILD 配置为使用 'MinGW64 Compiler (C)' 以进行 C 语言编译。
                要选择不同的语言,请从以下选项中选择一种命令:
                 mex -setup C++ -client MBUILD 
                 mex -setup FORTRAN -client MBUILD
                

                因为我们要以C++编译,所以要点击下面的mex -setup C++ -client MBUILD ,之后MBUILD就被配置为mingw64 C++的编译器了,如下:

                >> mbuild -setup
                MBUILD 配置为使用 'MinGW64 Compiler (C)' 以进行 C 语言编译。
                要选择不同的语言,请从以下选项中选择一种命令:
                 mex -setup C++ -client MBUILD 
                 mex -setup FORTRAN -client MBUILD
                MBUILD 配置为使用 'MinGW64 Compiler (C++)' 以进行 C++ 语言编译。
                

                之后,在命令行输入

                mex -setup
                

                同mbuild,将mex配置为mingw64 C++编译器,如下所示:

                >> mex -setup
                MEX 配置为使用 'MinGW64 Compiler (C)' 以进行 C 语言编译。
                警告: MATLAB C 和 Fortran API 已更改,现可支持
                	 包含 2^32-1 个以上元素的 MATLAB 变量。您需要
                	 更新代码以利用新的 API。
                	 您可以在以下网址找到更多的相关信息:
                	 https://www.mathworks.com/help/matlab/matlab_external/upgrading-mex-files-to-use-64-bit-api.html。
                要选择不同的语言,请从以下选项中选择一种命令:
                 mex -setup C++ 
                 mex -setup FORTRAN
                MEX 配置为使用 'MinGW64 Compiler (C++)' 以进行 C++ 语言编译。
                警告: MATLAB C 和 Fortran API 已更改,现可支持
                	 包含 2^32-1 个以上元素的 MATLAB 变量。您需要
                	 更新代码以利用新的 API。
                	 您可以在以下网址找到更多的相关信息:
                	 https://www.mathworks.com/help/matlab/matlab_external/upgrading-mex-files-to-use-64-bit-api.html。
                

                需要注意的是,matlab每次重启后,都要重新按以上步骤进行mbuild -setup/mex -setup的配置。

                2.编写函数

                以一次多项式拟合为例,编写以下函数:

                function [a, b, rsquare] = mat_fit( xData, yData )
                    [xData, yData] = prepareCurveData( xData, yData );
                    % Set up fittype and options.
                    ft = fittype( 'poly1' );
                    % Fit model to data.
                    [fitresult, gof] = fit( xData, yData, ft );
                    
                    a = fitresult.p1;
                    b = fitresult.p2;
                    rsquare = gof.rsquare;
                    % Plot fit with data.
                    figure( 'Name', 'poly1 fit' );
                    h = plot( fitresult, xData, yData );
                    legend( h, 'raw point', 'fit line', 'Location', 'NorthEast' );
                    % Label axes
                    xlabel x
                    ylabel y
                    grid on
                end
                

                一次函数形式为y = a * x + b,函数的输出a,b则是一次多项式中的系数,rsquare为确定系数,越接近于1说明拟合得越准。

                函数的输入则为x、y坐标,最后,通过plot打印出拟合的函数以及原始数据。在matlab中运行一下,如

                >> [a b r] = mat_fit(1:5,6:10)
                

                结果如下:

                >> [a b r] = mat_fit(1:5,6:10)
                a =
                   1.000000000000000
                b =
                     5
                r =
                     1
                

                同时绘图如下:

                超详细基于Qt平台实现C/C++调用Matlab函数全流程

                3.编译matlab函数,生成C++可调用的链接库

                在matlab主界面点击APP,在下拉框中选中Liberty Complier,在TYPE中选择C++链接库,然后点击加号选择函数所在的m文件,之后点击Package等待即可。

                超详细基于Qt平台实现C/C++调用Matlab函数全流程

                编译完成后,会自动打开编译生成的文件,我们只需要.dll .h .lib这三个文件即可,这三个文件在输出目录的for_redistribution_files_only文件夹中。

                四、Matlab C++链接库的使用

                至此我们已经生成了.dll .lib链接库,以及库的.h头文件,那么我们在Qt工程中包含头文件,且添加库后,就可以编程序调用刚刚编写的matlab函数了。

                1.Qt工程的建立

                这里文明建立一个Qt Widgets Application工程,并根据测试需求进行简单的UI界面设计,如下图所示。

                超详细基于Qt平台实现C/C++调用Matlab函数全流程

                重点是Qt 的pro文件的配置,我们需要在pro文件中加入以下内容:

                DEFINES += __MW_STDINT_H__
                INCLUDEPATH += $$quote(G:/Matlab2018b/extern/include)
                INCLUDEPATH += $$quote(G:/Matlab2018b/extern/include/win64)
                LIBS+=-L$$quote(G:/Matlab2018b/extern/lib/win64/microsoft) -llibmx
                LIBS+=-L$$quote(G:/Matlab2018b/extern/lib/win64/microsoft) -llibmx
                LIBS+=-L$$quote(G:/Matlab2018b/extern/lib/win64/microsoft) -llibmat
                LIBS+=-L$$quote(G:/Matlab2018b/extern/lib/win64/microsoft)  -llibeng
                LIBS+=-L$$quote(G:/Matlab2018b/extern/lib/win64/microsoft)  -lmclmcr
                LIBS+=-L$$quote(G:/Matlab2018b/extern/lib/win64/microsoft)  -lmclmcrrt
                

                主要是让qt能够找到matlab的头文件,以及链接库,其中的matlab路径按各人的安装路径填写即可,注意路径中的斜杠是斜杠/,而不是windows路径中使用的反斜杠。

                然后将上面生成的.lib .h文件复制到Qt工程目录下,之后在Qt中右击工程,选择添加库。

                超详细基于Qt平台实现C/C++调用Matlab函数全流程

                在弹出来的界面中选择【外部库】,点击下一步,之后按如下配置,点击浏览选择库,之后勾掉Linux和Mac,且勾掉为debug版本添加’d’作为后缀。

                超详细基于Qt平台实现C/C++调用Matlab函数全流程

                接下来,将.h头文件添加到Qt工程中即可。

                2.Qt程序的编写

                一下为全部代码,即点击【曲线拟合】按钮后调用matlab库对编辑框中的x、y点进行拟合,然后将一次多项式的两个系数输出,同时输出确定系数来反馈拟合效果。当然,必要的防错也要考虑。

                主要注意以下几点:

                (1).mat_fitInitialize()为库的初始化函数,一般放在程序一开始执行,需要消耗10秒左右的时间;

                (2).mwArray为参数类,实例化时需要配置参数。如

                mwArray in_x(1,x.size(),mxDOUBLE_CLASS,mxREAL);
                

                这里的1,x.size()配置该变量为一行x.size()列,后边配置为双精度浮点实数。

                (3).mat_fit为真正的调库函数,第一个参数为函数的输出变量个数,这要与m文件中的输出个数一致。后边即是输出、输入等,都要与m文件中的函数严格对应。

                (4).mwArray类函数的设置、取值等通过阅读代码即可了解。

                #include 
                #include 
                #include "mainwindow.h"
                #include "ui_mainwindow.h"
                #include "mat_fit.h"
                MainWindow::MainWindow(QWidget *parent) :
                    QMainWindow(parent),
                    ui(new Ui::MainWindow)
                {
                    ui->setupUi(this);
                    mat_fitInitialize();
                }
                MainWindow::~MainWindow()
                {
                    delete ui;
                }
                void MainWindow::on_pushButton_clicked()
                {
                    int i;
                    double *arr = nullptr;
                    QString res;
                    QStringList x = ui->lineEdit->text().split(" ");
                    QStringList y = ui->lineEdit_2->text().split(" ");
                    if(x.size() != y.size())
                    {
                        ui->textEdit->append(QString("x y坐标长度不相等"));
                    }
                    else if(x.size() textEdit->append(QString("请输入最少两个点"));
                    }
                    else
                    {
                        mwArray in_x(1,x.size(),mxDOUBLE_CLASS,mxREAL);
                        mwArray in_y(1,y.size(),mxDOUBLE_CLASS,mxREAL);
                        mwArray out_a(1,1,mxDOUBLE_CLASS,mxREAL);
                        mwArray out_b(1,1,mxDOUBLE_CLASS,mxREAL);
                        mwArray out_r(1,1,mxDOUBLE_CLASS,mxREAL);
                        arr = (double *)malloc(x.size() * sizeof(double));
                        if(arr == nullptr)
                        {
                            ui->textEdit->append("内存申请错误");
                            goto exit;
                        }
                        for(i = 0;i textEdit->append(res);
                    }
                exit:
                    if(arr != nullptr)
                    {
                        free(arr);
                    }
                }
                

                3.运行测试

                运行后输入x坐标为1-5,y坐标为6-10,得出拟合结果为y = 1.000000 * x + 5.000000 ,确定系数为rsquare = 1.000000,且弹出plot绘图,与预期相符

                超详细基于Qt平台实现C/C++调用Matlab函数全流程

                五、总结

                有了这个方法后,就可以在Qt中轻松得使用matlab支持的大量的复杂算法,比如滤波、快速傅里叶、拟合、矩阵运算等,能够把算法功能强有力得集成在Qt应用中,还是比较实用的。

                Chapter3 QT与MATLAB混合编程

                原文链接:https://blog.csdn.net/weixin_57306958/article/details/120724119

                Chapter4 QTCreater调用MatLab生成的.dll文件

                原文链接:https://blog.csdn.net/Fight_adu/article/details/126083394

                Chapter5 Qt与Matlab混合编程中mwArray数组使用详解

                原文链接

                Chapter6 Matlab中 的 mxArray 和 mwArray

                mwArray和mxArray有什么区别?

                首先,

                mxArray:Matlab C 函数库的结构体

                mwArray:Matlab C++ 函数库中对mxArray的包装类

                其次,二者的内存管理方式不同。

                mxArray的内存管理方式比较松散,由于是C函数库,没有数据封装,必须对临时阵列和约束阵列的概念极为明确,并且须小心地防止内存泄漏(要多写好多代码)。尽管有自动内存管理机制(mlfEnterNewContext,mlfReleasePreviousContext),仍然要处处调用mlfAssign,麻烦得很。

                mwArray就好的多,一切交给C++对象去搞定,你只要放心地用就可以了。不过Matlab C++函数库为了防止频繁内存分配和释放重写了内存分配和释放等函数。你会发现对于mwArray a,b; a=b;实际上并没有生成两个相同数据块,只是指针,只有发成数据改变时才copy完整数据。

                再次,这两个东西各自有一套与之相对应的函数。函数的返回值类型不同,需要多加注意。

                最后,用的时候mxArray要使用指针,而mwArray直接当类对象使。如果你不是Hardcore级的牛人或具有Hardcore倾向的潜牛人,我强烈建议你使用后者!

                举一个简单的例子:如果你需要计算c=a+b那么两者的区别是这样的:

                [cpp] view plaincopy
                01.//----------对于mxArray:------------  
                02.void fun()  
                03.{  
                04.……  
                05.double d_a=1,d_b=2;  
                06.mxArray *a,*b,*c;  
                07.mlfEnterNewContext(0,0);  
                08.mlfAssign(&a,mlfScalar(d_a));  
                09.mlfAssign(&b,mlfScalar(d_b));  
                10.mlfAssign(&c,mlfPlus(a,b));  
                11.……  
                12.mlfReleasePreviousContext(0,0);  
                13.mxDestroyArray(a);  
                14.mxDestroyArray(b);  
                15.mxDestroyArray(c);  
                16.}  
                17.  
                18.//----------对于mwArray:--------------  
                19.void fun()  
                20.{  
                21.……  
                22.mwArray a,b,c;  
                23.a=1;  
                24.b=2;  
                25.c=a+b;  
                26.……  
                27.}  
                

                另外一个说法:

                声明:
                mxArray:   mxArray *a;
                mwArray:   mwArray a;
                销毁
                mxArray:  mxDestroyArray a;
                mwArray:  mwArray类的析构函数自动销毁对象
                变量传递
                mxArray:memcpy(dest_ptr,source_ptr,MAX_SIZE);
                mwArray:mwArray in1(3, 3, mxDOUBLE_CLASS, mxREAL); 
                mwArray in2(3, 3, mxDOUBLE_CLASS, mxREAL);        
                in1.SetData(data, 9); 
                in2.SetData(data, 9);
                

                比较而言,

                1.mwArray的声明更简洁,不用考虑指针

                2.mwArray不用手动释放内存

                下面是这个例子用到的m代码。它定义了一个名为test的函数,保存在test.m文件中:

                [cpp] view plaincopy
                01.function y=test(x)  
                02.  y=sin(x);  
                03.  plot(x,y,'*');  
                04.  end   
                

                首先把这个函数编译成C++接口的DLL:

                mcc -W cpplib:dlltest -T link:lib test.m
                

                得到包含dlltest.dll,dlltest.ctf,dlltest.h,dlltest.lib等在内的一些文件。

                接下来我们只需要这四个文件。

                此时,打开dlltest.h看看,在文件的最下面我们可以发现C++接口的函数定义。仔细观察过后,我们可以发现,这个接口函数的参数是按照这样的顺序定义的:输出参数的个数、输出参数、以及输入参数。

                然后在VC6中创建一个VC++工程,工程中加入头文件:dlltest .h vc工程加入代码如下

                [cpp] view plaincopy
                01.#include "mclmcr.h" // mwArray声明  
                02.#include "dlltest.h"  
                03.void CVCMATLABDlg::OnButton1()  
                04.{  
                05.    mclInitializeApplication(NULL,0);  
                06.    dlltestInitialize();  
                07.    mwArray x(10,10,mxDOUBLE_CLASS);  
                08.    double *xData;xData = new double[100];  
                09.    for(int i=0; i
VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]