Qt 框架下 C++ 调用 MATLAB 程序

最近 Qt 项目中需要使用相对复杂的算法,因自身功力尚浅暂时无法使用 C/C++ 实现复杂算法,经过查找发现 Qt 可以通过某些途径实现 MATLAB 算法的调用,对于我这种算法小白十分友好,遂将 Qt 与 MATLAB 混合编程方法做一些简单记录。说是 QT 与 MATLAB 的混合编程,其实质仍是 C++ 对 MATLAB 程序的调用。

1、C++ 调用 MATLAB 的几种方法

在 Qt 框架下有多种 C++ 调用 MATLAB 程序的方法,下面进行简单介绍。

(1)调用 MATLAB 独立引擎

MATLAB Engine API 提供了 C++ 调用 MATLAB 程序的接口,C++ 程序通过 API 能够启动 MATLAB、调用 MATLAB 函数以及在 MATLAB 和 C++ 程序之间交换数据。通过查阅貌似这种方法比较适合于图表绘制,且运行时依赖 MATLAB 环境,比较受限。详细介绍可以参考 MATLAB Engine API for C++

(2)MATLAB 代码转换为 C/C++ 代码

MATLAB 中集成了 MATLAB Coder(编码器),用于将 MATLAB 代码转换为 C/C++ 代码,可以方便地将 MATLAB 程序移植到需要的平台上。具体介绍和实现方法参考 MATLAB Coder

(3)将 MATLAB 程序生成共享库

MATLAB Compiler 中包含 Library Compiler,可以将 MATLAB 程序打包生成动态共享库(DLL),方便在其他程序语言中调用使用MATLAB功能。

本篇文章主要围绕第三种方法展开,下面依次对 MATLAB 生成共享库,Qt 调用MATLAB DLL的具体方法进行介绍。

2、MATLAB 生成 DLL文件

2.1 编译环境配置

Qt 在 Windows 平台的编译环境一般有两种,分别为 MinGW 和 MSVC,为使 DLL 文件的编译平台与 Qt 保持一直,在配置时需要选择相同的编译器,且位数必须一致,比如我使用的环境均为MSVC2019 64bit。MSVC 可以通过安装 Visual Studio 进行配置,网上相关资料很多,不再赘述;MinGW 可以在 MATLAB 附加功能中安装,打开附加功能管理器后,直接搜索Mingw即可。

在 MATLAB 命令行窗口,使用mbuild –setup命令查看 MATLAB 中可以配置的编译环境。

如果没有可选编译器,需要自行配置后进行下一步操作。

输入命令后,会显示当前可配置的编译器,如下图所示。

根据自己的需要选择编译器,这里我选择 Microsoft Visual C++ 2019,并选择 C++ 语言,依次

点击相应选项,最终配置为如图所示即可。

上述两步也可以合并为一步,命令为 mbuild -setup C++,直接选择编译器。

2.2 打包生成 DLL 文件

为方便展示,先使用 MATLAB 编写一个两个数相加的函数,文件名为 add_matlab.m,具体代码如下:

1
2
3
function c = add_matlab(a,b)
c = a + b;
end

在 MATLAB 命令行窗口输入deploytool命令,弹出如下对话框。

选择Library Compiler编译器,如下图所示。

TYPE选择C++ Shared LibraryEXPORTED FUNCTIONS选择要编译的文件,这里选择前面编写好的add_matlab.m文件,如下所示。

选择完成后,点击Package按钮,选择编译后的文件放置位置,开始编译打包,稍等片刻即可完成,输出目录中有如下三个文件夹。

for_testing 目录下的文件,用于测试。

for_redistribution目录中程序MyAppInstaller_web.exe用于安装 MATLAB 运行时库和本项目生成的 DLL 、LIB 和 H 文件,将程序部署至没有 MATLAB 环境中电脑时,可以使用此方法。

for_redistribution_files_only目录中的 DLL 、LIB 和 H 文件,就是在 Qt 项目中要使用的文件。H 和 LIB 文件用于 Qt 程序调用,DLL 文件用于保障程序运行。有文章说 v2 目录中的 .ctf 文件在较低版本的 MATLAB 中影响 DLL 接口中的初始化函数,较高版本的MATLAB不需要。在无法初始化时,可以将该文件与 DLL 文件一同放入 debug 文件夹下尝试解决。

3、Qt 框架下 C++ 调用 DLL

3.1 创建 Qt 项目,添加外部库

创建一个 Qt 项目,在项目文件目录下新建一个名为matlab_libs(文件夹名可以自定义随便取),将 MATLAB 编译生成的for_redistribution_files_only目录下的文件全部拷贝至该文件夹下。

右键点击 Qt 项目目录名,选择添加库外部库

库文件选择Matlab_libs中的add_matlab.lib,点击下一步完成 Qt 外部库的添加。

完成后会在项目 .pro 文件中添加如下信息:

3.2 添加 MATLAB 其他依赖库和头文件路径

Qt 项目编译时,不仅需要自己添加的 MATLAB 编译后的库文件,还需要其他 MATLAB 依赖库文件,在工程 .pro 文件中添加如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# MATLAB 用到的.lib库文件 及其搜索路径
win32: LIBS += -LD:/Matlab/extern\lib/win64/microsoft/ -llibmx
win32: LIBS += -LD:/Matlab/extern\lib/win64/microsoft/ -llibmat
win32: LIBS += -LD:/Matlab/extern\lib/win64/microsoft/ -llibeng
win32: LIBS += -LD:/Matlab/extern\lib/win64/microsoft/ -lmclmcr
win32: LIBS += -LD:/Matlab/extern\lib/win64/microsoft/ -lmclmcrrt
win32: LIBS += -LD:/Matlab/extern\lib/win64/microsoft/ -llibmex

INCLUDEPATH += D:/Matlab/extern\lib/win64/microsoft
DEPENDPATH += D:/Matlab/extern\lib/win64/microsoft

# .h文件搜索路径
INCLUDEPATH += D:/Matlab/extern/include
INCLUDEPATH += D:/Matlab/extern/include/win64

上述路径根据自己安装位置进行替换,需要注意的是,文件路径中不得有空格,若有空格可以使用 quote(),如下:

1
INCLUDEPATH+=$$quote(D:/Matlab/extern/include/win64)

3.3 环境配置

本文中使用的 Qt 版本为 Qt5.9.9。

如果要发布程序或者运行在没有 MATLAB 环境的电脑需要安装 MATLAB 运行库,可以通过for_redistribution目录中MyAppInstaller_web.exe程序进行安装,也可以直接下载运行库安装程序,下载的运行库必须和生成 DLL 文件的 MATLAB 软件是同一个版本,MATLAB 运行库链接:https://ww2.mathworks.cn/products/compiler/matlab-runtime.html,
运行库的安装根据提示一直点击确定即可。

3.4 调用生成的 add_matlab DLL 库函数

(1)初始化库函数

编写一个加法窗口程序,在调用 add_matlab() 函数前,必须先使用 add_matlabInitialize() 函数初始化库函数。

(2)MATLAB 编译生成的 DLL 函数接口,保存在add_matlab.h文件中,add_matlab() 函数如下:

1
extern LIB_add_matlab_CPP_API void MW_CALL_CONV add_matlab(int nargout, mwArray& c, const mwArray& a, const mwArray& b);

nargout 为函数输出参数的个数,表示其后面紧跟着 nargout 个输出参数。

其他参数为 MATLAB 程序中自定义的输入输出参数,数据类型均为mwArray类。

(3)mwArray

mwArray类是用于将输入/输出参数传递给 MATLAB Compiler SDK 生成的 C++ 函数的类,具体可以参考mwArray Class

3.5 编译运行

具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

#include "add_matlab.h"

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);

if(!add_matlabInitialize()){
qDebug("add_matlab unsuccessfully initialized");
return;
}
}

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::on_pushButton_clicked()
{
QString result;

mwArray a(1,1,mxDOUBLE_CLASS);
mwArray b(1,1,mxDOUBLE_CLASS);
mwArray c(1,1,mxDOUBLE_CLASS);

a(1,1)=ui->LE1->text().toInt();
b(1,1)=ui->LE2->text().toInt();

add_matlab(1,c,a,b);
result = c.ToString();
ui->LE3->setText(result);
qDebug()<<result;
}

运行效果如下:

完整项目仓库地址:https://github.com/leafiness/Qt_MATLAB

参考:

[1] MATLAB Engine API for C++
[2] MATLAB Coder
[3] Library Compiler
[4] mwArray Class
[5] Qt调用MATLAB 生成的dll经验分享