matlab函数编译成库供C++调用(非常详细)以及采坑日志

原文链接:matlab函数编译成库供C++调用(非常详细)

采坑解答:Matlab2016 与vs2015 混编(生成dll动态链接库)

MATLAB具有着很高的计算性能,一些算法用MATLAB很容易实现,而用C++很难实现,如果想在C++中调用MATLAB编写的函数,可以将该函数编译成库文件,之后在C++中对其进行调用。

本文详细讲解如何将MATLAB函数编译成库,并在C++中进行调用。方法可行,本人亲测。

第一步、在MATLAB中的命令行窗口中输入mex -setup,会出现如下界面。

mex -setup


第二步、点击界面中的“mex -setup C++”,出现如下提示。

mex -setup C++


第三步、之后就是进行对MATLAB中的function的编译了。这里,我的函数名为phasecong,实现的是图像相位一致性的计算。如下图所示。

这个函数是一位大牛学者写的,原本是有多个输入和多个输出的,但是为了编译方便和后续调用方便,我把其他几个参数删掉了,只保留了一个输入矩阵和一个输出矩阵。

这样做的好处是可以减少编译和调用出错的概率。编译方法见第四步。

phasecong


第四步、下面就是对function进行编译了,编译的命令为:mcc -W cpplib:pc -T link:lib phasecong

这条命令中pc表示的是想要生成的库的名称,可以自己定,最后面的phasecong表示的是要编译的函数的名,注意函数名后面不要加.m后缀。其他的参数都不用改。

如下图所示。

编译


第五步、输入完上面的命令后就是等待MATLAB编译完成了,我当时编译好像用了30秒左右的时间。

编译完成后就会出现编译成功的提示,如下图所示。

需要注意的是,在编译时,当前文件夹一定要为function所在的文件夹。

编译成功


第六步、经过上面的编译后,在该文件夹下就会生成.h .cpp .lib .dll这四个文件,因为我设置的输出的库名称为pc,因此我这里生成pc.h pc.cpp pc.lib pc.dll这四个文件。

生成的文件


第七步、接下来就是将生成的这四个文件加入到我们的C++工程中了。

将这四个文件放在C++工程的文件夹中,最好在该文件夹中新建两个文件夹,分别命名为lib和include,因为后面我们还需要引入其他的库文件和头文件,这样做可以让文件更整齐。然后将pc.lib放入lib文件夹,将pc.h放入include文件夹。然后在VS中右键项目,点击属性,在属性中选择“配置属性”->“VC++目录”->“包含目录”,将刚才建立的include文件夹包含进去,如下图所示。其他的属性都不用改。

vs属性

这样我们就将头文件包含了进去,之后进行加载lib文件,这里我们使用静态加载方式,在工程文件中加入这样一条语句:

[cpp]  view plain  copy
  1. #pragma comment(lib, ".\\lib\\pc.lib" )  
对于pc.dll和pc.cpp文件,值需要将其放在工程目录下就可以,不用进行配置。

这样就完成了对这四个文件的配置。


第八步、配置好生成的这四个文件后就可以运行C++的程序了,但是点击运行后应该会报错(通常一定会报错),不要怕,这是因为我们前面生成的这四个文件是需要依赖其他的库和头文件才能工作的。我们根据报错的信息可以知道缺少的头文件,例如下图这个错误:


通过这个错误我们就可以知道,我们的项目中缺少mat.h这个头文件,这时我们就要找到这个头文件并将其加入到include文件夹中。到哪里去找呢,在这个文件夹中“D:\Program Files\MATLAB\R2014b\extern\include”。重复这一操作,直到不再提示这种错误。这一操作需要重复很多次,像我这个项目需要加入下图这么多的头文件。


之后还需要加入额外的lib库文件,具体加入哪些lib文件,需要根据上面的这些头文件而定,我们到文件夹“D:\Program Files\MATLAB\R2014b\extern\lib\win64\microsoft”中(因为我的MATLAB是64位的,所以在win64文件夹下,如果大家的MATLAB是32位的,那么估计是在win32文件夹下,大家自己找一下),寻找上面这些头文件同名的lib文件,不过并不是每个头文件都能找到同名的lib文件,不过不要紧,我们只要把能找到的lib文件复制到工程目录下的lib文件夹中即可,除了这些lib文件之外,还需要加上“libmat.lib”和“libmx.lib”这两个文件,这两个文件好像包括着必要的类型的定义之类的吧。搞定之后我的lib文件夹中有下图这些个文件。


这些lib的加载方式与之前我们说的pc.lib的加载方式相同,如下图所示。


进行到此,我们所有的配置就都搞定了,如果没有意外的话,C++的项目编译就可以通过了,

但是虽然编译通过了,在运行的过程中还是有可能提示缺少某个库文件,我们只需要采用同样的方法把那些库文件加到项目里即可,比如我这个程序还提示我缺少mclmcr.dll这个文件,我就把这个文件复制到工程目录下就可以了,所需的dll文件通常都在“D:\Program Files\MATLAB\R2014b\bin\win64”这个文件夹可以找到。

至此我们就完成了MATLAB函数的编译和C++调用的整个过程。


最后是几点提示:

1、我这里使用的是MATLAB2014a和vs2013。

2、如果使用的MATLAB是64位的版本,那么C++的程序也要在x64下配置!!!!!!!

      如果使用的MATLAB是32位的版本,那么C++的程序也要在win32下配置!!!!!!

      这点非常重要!!!!!!!!


3、MATLAB函数的输入和输出参数通常都是矩阵,在C++中矩阵变量使用mwArray这个类型,这个类的使用方法可以看我下面贴的代码,也可以在网上找教程。

4、在C++程序中,我们调用这个函数的名称与MATLAB中定义的函数名称相同,这个函数是在MATLAB编译后生成的头文件中进行的声明,例如我这里是在pc.h中。

5、在C++程序中,在定义输入数组和输出数组时,最好使用动态数组,因为传统的数组是在栈中分配内存,这样会造成内存溢出。

// pcproj.cpp : 定义控制台应用程序的入口点。  
//  
  
#include "stdafx.h"  
#include "pc.h"  
#include <iostream>  
#include <fstream>  
  
using namespace std;   
  
#pragma comment(lib, ".\\lib\\pc.lib" )  
#pragma comment(lib, ".\\lib\\mclmcrrt.lib")  
#pragma comment(lib, ".\\lib\\libmx.lib")  
#pragma comment(lib, ".\\lib\\libmat.lib")  
#pragma comment(lib, ".\\lib\\mclmcr.lib")  
  
#define WIDTH 512  
#define HEIGHT 512  
  
int _tmain(int argc, _TCHAR* argv[])  
{  
    //mclInitializeApplication(NULL, 0);  
    //mclmcrInitialize();  
  
    UINT8 *img_befor = new UINT8[WIDTH*HEIGHT];  
    DOUBLE *img_after = new DOUBLE[WIDTH*HEIGHT];  
  
    int data;  
    double ddata;  
    FILE *fp;  
  
    errno_t err = fopen_s(&fp, "pixel.txt", "r");  
    if (err!=0){  
        cout << "open pic fail!" << endl;  
        return 0;  
    }  
  
    for (int i = 0; i < WIDTH; i++){  
        for (int j = 0; j < HEIGHT; j++){  
            fscanf_s(fp, "%d", &data);  
            img_befor[i*WIDTH + j] = data;  
        }  
    }  
  
    fclose(fp);  
    fp = NULL;  
  
    pcInitialize();  
  
    mwArray img_input_array(HEIGHT, WIDTH, mxUINT8_CLASS, mxREAL);  
    mwArray img_output_array(HEIGHT, WIDTH, mxDOUBLE_CLASS, mxREAL);  
    int nargout = 1;  
  
    img_input_array.SetData(img_befor, HEIGHT*WIDTH);  
  
    phasecong(nargout,img_output_array,img_input_array);  
      
    img_output_array.GetData(img_after, HEIGHT*WIDTH);  
  
    pcTerminate();  
  
    //将结果写到文件  
    err = fopen_s(&fp, "pixel_after.txt", "w");  
    if (err != 0){  
        cout << "open pic_after fail!" << endl;  
    }  
    else{  
        //写文件  
        for (int i = 0; i < WIDTH; i++){  
            for (int j = 0; j < HEIGHT; j++){  
                ddata = img_after[i*WIDTH + j];  
                fprintf(fp, "%.4f ", ddata);  
            }  
            fprintf(fp, "\n");  
        }  
    }  
    fclose(fp);  
    fp = NULL;  
  
  
    return 0;  
}  

最后为了更直观的展示在C++中如何对这些个库文件进行的调用以及如何使用这个函数,我在这里贴上了C++程序的源代码。

采坑:以上是第一位博主的例子,正好我也做图像处理,见识过相位一致性PC的代码,想着拿过来完美复现一下,奈何代码运行到55行出错,老是提示

 run (line 70) 
未找到 D:\vlfeat-0.9.20\toolbox\vl_setup。 
出错 startup (line 1) 

这就使人很抓狂,当然是再来一遍,还是没解决。

第二天参考了第二篇博客,才明白问题之所在。

在这里也贴一下,权当记录自己的采坑日常吧。

出现这个问题的主要原因就是你Matlab文件夹下的某个工具箱访问出错,也就是你装了一个工具箱到Matlab ,并且这个工具箱(我这就是vl_feat工具箱)会会在matlab运行的时候直接启动,这样直接导致matlab生成的dll文件中也包含了这个文件,所以直接去matlab的 安装目录下找到toolbox\local 路径删除里面的 startup.m文件,然后在重新用matlab生成一下dll文件就可以了。

猜你喜欢

转载自blog.csdn.net/akenseren/article/details/80290020