QT与MatLab混编

该篇介绍QT下调用MatLab编译好的运行库
环境:Windows10,QT5.12.6,MatLab r2018b 64位
MatLab的安装可以看这篇文章MatLab安装
一、打开MatLab,先设置编译器,在命令行输入:

>> mbuild -setup C++

结果如下:
MBUILD configured to use 'Microsoft Visual C++ 2017' for C++ language compilation.
即设置C++编译器,如果设置C编译器可以输入 mbuild -setup
二、编译.m文件,命令行输入>> deploytool ,出现下图结果:

QT与MatLab混编_第1张图片

选择Library Complier,配置如下:

QT与MatLab混编_第2张图片

等待打包…
打包完成,输出如下:

QT与MatLab混编_第3张图片

for_redistribution目录下是MyAppInstaller_web.exe,这个是MATLAB运行时库的和本项目的安装文件,运行后可从网上下载MATLAB的运行时库进行安装,还会安装本项目生成的dll、lib和h文件。

for_redistribution_files_only目录下是编译生成的.dll 、.lib和.h文件,其中.lib和.h文件是在Qt项目编译时需要用到的,.dll文件是程序运行时需要用到的。

for_testing  目录下是用于测试的。

该段引自:https://blog.csdn.net/HongAndYi/article/details/79433623
三、在QT中配置项目需要的动态库
右击项目:

QT与MatLab混编_第4张图片

选择Add Library:

QT与MatLab混编_第5张图片

先在QT项目下,新建include文件夹,把MatLab编译好的.lib和.h复制过来:

QT与MatLab混编_第6张图片

而.dll文件要放在项目生成的debug目录下:

QT与MatLab混编_第7张图片

然后添加lib文件,路径是刚才建立在QT项目下的include下的lib:

QT与MatLab混编_第8张图片

之后会在QT项目的.pro文件生成如下代码:
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/include/ -lpso
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/include/ -lpso
else:unix: LIBS += -L$$PWD/include/ -lpso

INCLUDEPATH += $$PWD/include
DEPENDPATH += $$PWD/include

目前是把Matlab编译好的库文件包含进来的,但是还没完,还需要把MatLab需要的运行库包含进来:
INCLUDEPATH += $$quote(C:/Program Files/MATLAB/R2018b/extern/include)
INCLUDEPATH += $$quote(C:/Program Files/MATLAB/R2018b/extern/include/win64)

INCLUDEPATH += $$quote(C:/Program Files/MATLAB/R2018b/extern/lib/win64/microsoft)
DEPENDPATH += $$quote(C:/Program Files/MATLAB/R2018b/extern/lib/win64/microsoft)

LIBS += -L$$quote(C:/Program Files/MATLAB/R2018b/extern/lib/win64/microsoft/) -llibmex
LIBS += -L$$quote(C:/Program Files/MATLAB/R2018b/extern/lib/win64/microsoft/) -llibmx
LIBS += -L$$quote(C:/Program Files/MATLAB/R2018b/extern/lib/win64/microsoft/) -llibmat
LIBS += -L$$quote(C:/Program Files/MATLAB/R2018b/extern/lib/win64/microsoft/) -llibeng
LIBS += -L$$quote(C:/Program Files/MATLAB/R2018b/extern/lib/win64/microsoft/) -lmclmcr
LIBS += -L$$quote(C:/Program Files/MATLAB/R2018b/extern/lib/win64/microsoft/) -lmclmcrrt
之所以加quote是因为路径中包含空格,比如Program Files,这种情况就需要加quote包含进来,否则会出错。
四、在QT项目下调用MatLab编译好的pso.dll中的函数,先说一下QT中的编译器,我的有MinGW也有MSVC编译器(手动配置的,但是实际运行没用到),我用的MinGW,为了避免不必要的问题,建议MatLab的c++编译器和QT编译器要版本一致,

QT与MatLab混编_第9张图片

我的MSVC编译器是手动配置的,因为之前装过vs2017,所以配置起来比较方便,只需要安装debugger就可以,CDB安装可以在官网下载Debugging Tools for Windows 10 (WinDbg)

QT与MatLab混编_第10张图片

我的初衷是使用MSVC但是项目运行的时候却无法选择MSVC只能用MinGW,我不清楚具体是怎么个问题。
另外如果想把MATLAB中的C++编译器调成和QT中的编译器一样的,可以通过MATLAB中的控制台来设置:①输入mex -setup,如果有的话就会显示出可以用的编译器。②没有的话就要安装一个,选择的是MinGW编译器,下载地址sourceforge.net/projects/mingw-w64/files/latest/download,然后安装,一定记得选择符合自己操作系统位数的。③等待安装结束后,添加新的环境变量MW_MINGW64_LOC,值为MinGW的安装路径 ④设置完环境变量之后,在Matlab命令行运行setenv(‘MW_MINGW64_LOC’,folder),folder为MinGW的安装位置(跟环境变量路径一致即可),要加单引号;如果每次重启Matlab后还是没有发现编译器,而且每次都要重新编译,此时就要看看MinGW的安装目录是不是空格,很多人默认安装在C:\Program File\下,结果就运行不了,因为这其中有空格,此时有两种方法可以解决,第一种就是重新安装到没有空格的文件夹里面,当然这得重新安装,比较麻烦;第二种就是,直接在环境变量那里,把Program File改为Progra~1。链接:https://www.jianshu.com/p/621cba9a8417来源:简书
另外也可以看这篇文章:MATLAB如何安装配置MinGW-w64 C/C++编译器,
我的调用代码如下:
#include "pso.h"
//下面是调用MatLab编译好的粒子群算法
    QLibrary myLib("pso.dll");
    typedef bool MW_CALL_CONV(*Fun)(int,class mwArray const &,class mwArray const &,class mwArray const &,class mwArray const &,class mwArray const &,class mwArray const &);
    Fun myFunc = Fun(myLib.resolve("?PSO@@YAXHAEAVmwArray@@000AEBV1@1@Z"));

    if(!psoInitialize())                                  //必须要初始化成功
    {
     
        qDebug()<<"could not initialize psodll\n";
        exit(0);
    }

    mwArray coor(str.size(),4,mxDOUBLE_CLASS);            //输入值
    mwArray v(1,1,mxDOUBLE_CLASS);

    mwArray x(1,1,mxDOUBLE_CLASS);                        //输出值
    mwArray y(1,1,mxDOUBLE_CLASS);
    mwArray z(1,1,mxDOUBLE_CLASS);
    mwArray t(1,1,mxDOUBLE_CLASS);

   
    coor.SetData(adjustToArray,4*str.size());             
    v(1,1)=WAVEVELOCITY;

    myFunc(4,x,y,z,t,coor,v);

    XRESULT=x.ToString();
    YRESULT=y.ToString();
    ZRESULT=z.ToString();
    TRESULT=t.ToString();
注:
需要说明的是由于matlab使用vs的msvc编译器生成的dll文件,生成后我们使用mingW调用,但生成的头文件中指定各种编译器对应的情况,但唯独没有MinGW,这就导致了在使用MinGW编译器时我们在.pro文件中添加:

DEFINES += MW_STDINT_H

使用msvc编译器调用matlab生成的dll时,编译器会自动识别函数名,因此也不需要使用resolve函数。

这段话引自:https://blog.csdn.net/China_Rocky/article/details/104592488
比如:
Fun myFunc = Fun(myLib.resolve("?PSO@@YAXHAEAVmwArray@@000AEBV1@1@Z"));
上述resolve中的值来自pso.dll(即刚才matlab编译好的运行库),我们可以利用Dependency Walker 2.2该软件查看dll文件,然后找到入口函数,后边跟着的值就是这个resolve中的值。可以在matlab编译生成的.h文件中查看项目生成的调用函数,比如:
extern LIB_pso_CPP_API void MW_CALL_CONV PSO(int nargout, mwArray& x, mwArray& y, mwArray& z, mwArray& t, const mwArray& sample, const mwArray& v);
说明:
1)DLL的初始化

在使用pso.dll里的函数之前,必须先初始化。psoInitialize()是matAdd.h文件里面的库初始化函数。

(2)PSO函数的输入输出参数

mwArray是MATLAB的数组类,MATLAB编译生成的DLL的接口函数的参数都是采用mwArray类型,例如:extern LIB_pso_CPP_API void MW_CALL_CONV PSO(int nargout, mwArray& x, mwArray& y, mwArray& z, mwArray& t, const mwArray& sample, const mwArray& v); 

int  nargout 是输出参数个数,比如我这里是4,那么,后面x,y,z,t变量是输出参数,
mwArray  &sample,  const mwArray  &v是输入参数

(3)mwArray类的使用

mwArray coor(str.size(),4,mxDOUBLE_CLASS);  
定义mwArray类型的变量coor时,利用构造函数传递了数组的行数、列数、元素类型、实数或复数类型语句

coor.SetData(adjustToArray,4*str.size());  将一维向量adjustToArray的数据内容赋值给coor,元素个数为4*str.size(),等于行数*列数。使用SetData赋值时,输入adjustToArray必须是一个向量,是逐列存储的。

注意:mwArray数组的下标都是从1开始的,与C/C++的数组元素下标从0开始不同。

这段话修改自:https://blog.csdn.net/HongAndYi/article/details/79433623
另外mwArray的详细用法如下:
.矩阵赋值
<1>mwArray 定义矩阵变量

  mwArray  A(rows, cols, type)

参数说明:
   A   :变量名
   rows:行数
   col :列数
   type:数t据类型

type类型有:
typedef enum
{
     
    mxUNKNOWN_CLASS = 0, //未知类型
    mxCELL_CLASS, //细胞类型
    mxSTRUCT_CLASS, //结构类型
    mxLOGICAL_CLASS, //布尔类型
    mxCHAR_CLASS,  //字符串类型
    mxVOID_CLASS,  //void类型
    mxDOUBLE_CLASS, 
    mxSINGLE_CLASS, //单精度浮点数
    mxINT8_CLASS, //
    mxUINT8_CLASS,
    mxINT16_CLASS,
    mxUINT16_CLASS,
    mxINT32_CLASS,
    mxUINT32_CLASS,
    mxINT64_CLASS,
    mxUINT64_CLASS,
    mxFUNCTION_CLASS, //函数类型
    mxOPAQUE_CLASS, //
    mxOBJECT_CLASS  //对象类型
}

整体含义是:定义矩阵A,行数为:rows,列数为:cols,类型为:type
注: 如果参数不是矩阵,只是一个数,令 rows=1,cols=1即可。

<2>矩阵赋初值:

int a[6] = {
     1,2,3,4,5,6}
mwArray A(2,3,mxINT32_CLASS);  
A.SetData(a,6); //第二个参数为要设置的数的个数,大小可设为rows*cols

注:该过程相当于把1*6的矩阵,转化为2*3的矩阵,matlab转化顺序是,先排第一列,由上到下为a[0] a[1],然后排第二列,由上到下为a[2] a[3],即转化后的A为:
1     3      5
2     4      6
如果要使A为:
1      2     3
4      5     6
需这样赋值:
<pre name="code" class="cpp">int a[6] = {
     1,2,3,4,5,6}
mwArray A(3,2,mxINT32_CLASS);  //修改此处:行列数互换
A.SetData(a,6); //第二个参数为要设置的数的个数,大小可设为rows*cols

此时生成的A为:
1      4
2      5
3      6
该矩阵转置之后,既可以达到所需形式,转置过程可以在matlab的.m文件中添加,先修改.m,然后在生成dll、lib、h文件。
尤其是,在图像处理时,如果传递的矩阵为图像数据矩阵,要采用后一种方法赋值,否则,图像会严重变形失真。
二、字符串赋值
char str[5] = "abcd";
//或 CString str = "abcd"
mwArray mwA(str);

该段转载自:https://blog.csdn.net/hong__fang/article/details/43307701
仅用于学习使用

你可能感兴趣的:(QT,matlab,qt5)