跳至主要內容

Qt C++ Matlab 混合编程测试使用文档

CK...大约 7 分钟技巧总结QtC++Matlab混合编程

Qt C++ Matlab 混合编程测试使用文档

环境版本

  • Qt:5.9.0
  • MSVC 2017 64bit 编译器
  • Matlab:R2019b (64bit)
  • Windows 11 64位

开发步骤

本文就介绍使用 Qt 5.9 和 Matlab 进行混合编程的基本流程,主要包括:

  • 如何在Matlab中将m文件编译为C++语言的DLL文件
  • 如何在Qt项目中加入自定义DLL相关的LIB文件,以及MATLAB相关的LIB文件和H文件搜索路径
  • 如何在Qt中调用自定义DLL中的函数,如何通过mwArray类传递输入输出参数

Matlab 动态链接库的生成

Matlab 函数的编写

在 Matlab 中编写函数,这里编者以两个矩阵相加函数 matAdd 作为测试函数。并保存为 matAdd.m 文件。

function  C= matAdd(A,B)
% C= matAdd(A,B),  两个矩阵相加
C=A+B;
end

注意:需要多个 Matlab 函数时,需要将各个文件保存到不同的Matlab文件中,在下面的步骤中统一集合成相关动态链接库和头文件。

设置MATLABCompiler 编译器

在 Matlab 命令行输入下面的内容。

>>  mbuild -setup C++
MBUILD 配置为使用 'Microsoft Visual C++ 2017' 以进行 C++ 语言编译。

注意:编者采用 'Microsoft Visual C++ 2017' 进行 C++ 编译,和 Qt 编译器保持一致,暂不清楚不同编译器是否会对结果造成影响。电脑上安装了Visual Studio 2017,MATLAB会自己查找可用的编译器。

Library Compiler

在 Matlab 命令行输入下面的内容:

>> deploytool

并选择 ‘Library Compiler’ :“ApplicationCompiler”用于将m文件编译为exe文件直接运行,“Library Compiler”用于将m文件编译为DLL、COM组件等形式。我们要生成DLL文件,所以选择“Library Compiler”。

image-20220313203717850

‘TYPE’ 部分选择 C++ Shared Library ,“EXPORTED FUNCTIONS” 选择待添加的文件(这里可以添加多个函数文件)。右侧是MATLAB运行时库的安装打包方式,在本机上测试可选择“Runtime downloaded from web”。添加完毕后点击‘Package’ 进行编译和打包。

image-20220313203953140
image-20220313203953140

Qt 调用环境配置

打包完毕后,项目文件 matAdd.prj 目录下生成与其项目同名的子目录,即 \matAdd,该目录下有 3 个文件夹。我们主要需要 matAdd\for_redistribution_files_only 目录下是编译生成的.dll 、.lib和.h文件。其中.lib和.h文件是在Qt项目编译时需要用到的,.dll文件是程序运行时需要用到的。

image-20220313204821142
image-20220313204821142

这三个文件,需要复制到 Qt 的 pro 目录下。

image-20220313204929658
image-20220313204929658

matAdd.lib 文件的加入

image-20220313205154849
image-20220313205154849

打开 pro 库,右键选择添加库,选择添加外部库,加入目录中的 matAdd.lib 文件,其他选择如图所示:

image-20220313205440314

在 pro 文件中,将会出现下面几段代码:

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

win32:!win32-g++: PRE_TARGETDEPS += $$PWD/./matAdd.lib
else:win32-g++: PRE_TARGETDEPS += $$PWD/./libmatAdd.a

为了方便查看matAdd.h的内容,还可以将matAdd.h文件添加到项目中,但是要注意不要修改matAdd.h文件的内容。

Matlab 依赖库和头文件搜索路径的加入。

除了自己编译生成的DLL相关的.lib文件和头文件,要编译此Qt项目,还需要用到MATLAB的几个.lib文件和.h文件。

我的电脑上,MATLAB2019b安装在 D:/Program/matlab2019 目录下,在 testAdd.pro 文件中需要加入如下的设置:

INCLUDEPATH += 'D:/Program/matlab2019/matlab/extern/include'
INCLUDEPATH += 'D:/Program/matlab2019/matlab/extern/include/win64'

win32: LIBS += -L'D:/Program/matlab2019/matlab/extern/lib/win64/microsoft/' -llibmex
win32: LIBS += -L'D:/Program/matlab2019/matlab/extern/lib/win64/microsoft/' -llibmx
win32: LIBS += -L'D:/Program/matlab2019/matlab/extern/lib/win64/microsoft/' -llibmat
win32: LIBS += -L'D:/Program/matlab2019/matlab/extern/lib/win64/microsoft/' -llibeng
win32: LIBS += -L'D:/Program/matlab2019/matlab/extern/lib/win64/microsoft/' -lmclmcr
win32: LIBS += -L'D:/Program/matlab2019/matlab/extern/lib/win64/microsoft/' -lmclmcrrt

INCLUDEPATH += 'D:/Program/matlab2019/matlab/extern/lib/win64/microsoft'
DEPENDPATH += 'D:/Program/matlab2019/matlab/extern/lib/win64/microsoft'
INCLUDEPATH += 'D:/Program/matlab2019/matlab/extern/lib/win64'
DEPENDPATH += 'D:/Program/matlab2019/matlab/extern/lib/win64'

注意:注意,若路径名称中含有空格,需要使用quote(),如

#INCLUDEPATH+=$$quote(D:/MATLAB2017b/extern/include)

系统环境变量的配置

若是程序发布到没有安装MATLAB的电脑上,需要用Matlab Compiler编译生成的安装包,本例就是 matAdd\for_redistribution目录下的MyAppInstaller_web.exe。

若只是要独立安装MATLAB运行时库,在MATLAB 命令行里输入 mcrinstaller可以得到离线的MATLAB运行时库安装文件的路径。

>> mcrinstaller

更多相关内容见:在没有安装MATLAB的电脑上运行MATLAB程序open in new window

C++ 对 Matlab 函数调用

测试设计 UI 界面如下所示:

image-20220313210921486
image-20220313210921486

所用到的控件如下图所示:

image-20220313211030231

matAdd.dll 的初始化

在使用 matAdd.dll 函数之前,需要调用 matAdd.h 里的函数 matAddInitialize 进行初始化

我们将初始化在窗口的构造函数里完成。下面是构造函数的代码:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 不执行matAddInitialize()会报错,注意matAdd为文件名
    if(matAddInitialize())
    {
        ui->TextEdit->setText("matlab程序DLL初始化成功.");
    }
    else
    {
        ui->TextEdit->setText("*** matlab程序DLL初始化失败");
        return;
    }
}

mwArray 类的使用

(1)构造函数如下所示:

   mwArray(num_rows,num_cols,mxID,cmplx=mxREAL)
  • num_rows表示行数, mwSize是整数类型

  • num_cols表示列数

  • mxID是mxClassID类型,表示元素的基本数据类型,常见的有如下的一些取值mxLOGICAL_CLASS

 mxCHAR_CLASS

 mxDOUBLE_CLASS 

 mxSINGLE_CLASS

 mxINT8_CLASS  

 mxUINT8_CLASS   

 mxINT16_CLASS  

 mxUINT16_CLASS 

 mxINT32_CLASS  

 mxUINT32_CLASS 

 mxINT64_CLASS

 mxUINT64_CLASS
  • cmplx是mxComplexity类型,有mxREAL和mxCOMPLEX两种取值,标书数组元素是实数或复数,缺省为mxREAL

(2)mwArray数组的赋值

mwArray:: SetData(mxUint64* buffer, mwSizelen) 

其中,buffer必须是一维数组,即便mwArray变量是一个二维数组,len是一维数组的元素个数,等于行数乘以列数。在给二维数组赋值时,buffer必须按列存储数据(见代码内容)。

void MainWindow::on_pushButton_clicked()
{// 两个矩阵相加, C=A+B
//读取矩阵A
       int   rowCntA=ui->spinBoxA_Row->value();
       int   colCntA=ui->spinBoxA_Col->value();
       int   elementCntA=rowCntA*colCntA; //元素个数
       //一维数组,用于C++向 MATLAB数组传递数据
       double   *arrayA=new double[elementCntA];

        int N=0; //C++的一维数组的元素索引号
          for(int i=0;i<ui->tableA->columnCount();i++) //逐列读取,序列化存储到一维数组
             for (int j=0; j<ui->tableA->rowCount();j++)
             {
                arrayA[N]=ui->tableA->item(j,i)->text().toDouble();
                N++;
             }
         //定义数组,行,列,double类型
          mwArray matrixA(rowCntA,colCntA,mxDOUBLE_CLASS, mxREAL);
         //将C++ 的一维数组arrayA存储到 MATLAB的二维数组matrixA
          matrixA.SetData(arrayA,elementCntA); 

(3)mwArray数组元素的读取

可以使用mwArray::Get()函数读取数组的元素,

例如,对于二维数组,采用Get()函数读取数据的代码一般是

int dim=2; // 二维数组
double   value=matrixA.Get(dim,j,i); //按照dim维数数组读出,第j行, 第i列

也可以不用行号、列号,而用序号读取,如

int dim=2; // 二维数组
double   value=matrixA.Get(dim,N); //按照dim维数数组读出,第N个元素

这里的N是按列排列的元素的总的序号。对于二维数组,还是按照行号、列号更直观一些。

也可以直接使用mwArray的“()”操作符读取数组元素,如

   double   value=matrixC(j,i); //直接用数组下标索引,第j行,第i列
   double   value=matrixC(N); //直接按元素序号读取, 第N个元素

Matlab 函数的调用

在我们已经通过上述方式进行 mwArray 进行 数组的定义与赋值后,我们可以直接通过 Matlab 函数文件的原函数名进行函数的调用,需要传入的参数为:

  • nargout:输出变量个数
  • matrixC: 保存返回矩阵的 mwArray类,需要指定相关属性。
  • matrixA、matrixB:matlab 原函数中的两个参数矩阵。
          //计算, C=A+B
            int   rowCntC=rowCntA;
            int   colCntC=colCntA;
		//定义数组,行,列,double类型
             mwArray matrixC(rowCntC,colCntC,mxDOUBLE_CLASS, mxREAL);
             int nargout=1;//输出变量个数
		// 调用函数,计算 C = A + B
             matAdd(nargout,matrixC,matrixA,matrixB);

其他官方文档及常见问题

mwArray 类官方文档

Class used to pass input/output arguments to C++ functions generated by MATLAB Compiler SDKopen in new window

常见问题

错误使用 mbuild (line 166) Unable to complete successfully. 未找到支持的编译器。open in new window

Qt与Matlab混合编程细节总结open in new window

学习笔记:Qt与Matlab混合编程及遇到的诸多问题(附DEMO)open in new window

以上链接内容仅供参考,实际操作过程会遇到无数的坑。。。下面的网址可以解决百分之八九十的问题: