您的位置:首页 > 编程语言 > MATLAB

MATLAB和VS2010的混合编程需要注意的问题

2015-03-20 17:49 417 查看
接上一篇文章吧,虽然上一篇距离现在几个月了。2015年第一发。

对于BM3D算法,在作者的主页他们给出了MATLAB的代码,在MATLAB上跑了一下,果然很好很强大,同时也跑了跑实验验证了一下linux下的C++版代码,需要装libpng和fftw3这两个库。后来在师兄的帮助下实现了GPU版的程序,可以做到每秒5-10帧左右,又大幅的提升了算法的速度,但是由于自己太懒,于是想到借用MATLAB来进行对图像的IO操作,在不同域之间做变换以及计算性能。 因而在去年底和今年初的一个月时间摸索了一下MATLAB和VS2010混合编程互相调用的方法,写下来以纪念一下走过的弯路。虽然网上其他的地方都已经有很多格式的有关于此的教程,但是我在搜索的过程中发现这些教程要么就不全要么就一笔带过,这篇文章打算从自己实际项目的角度出发,写一写遇到的问题以及使用的方法。

一、在VS2010中调用MATLAB的方法:

1. 先是配置MATLAB,打开MATLAB 我用的是R2011b,在命令行中输入:
mex -setup

  然后根据提示选择编译器,我用的VS2010,然后一直选择y,完成之后,再在命令行中输入:    
mbuild -setup

  然后根据提示选择编译器,我用的VS2010,然后一直选择y,完成之后,MATLAB端就配置好了
2. 再配置VS2010,新建一个工程,比如matlab_demo,在工程名右键单击,选择:属性(property) --> 
       1). VC++目录 --> 
         (1). 包含目录 (加入matlab的外部接口目录, 比如 我的是:D:\Program Files\MATLAB\R2011b\extern\include)    
         (2). 库目录 (加入matlab的库目录, 比如 我的是:D:\Program Files\MATLAB\R2011b\extern\lib\win64\microsoft,注意需要根据操作系统位数选择win64还是win32)
       2). 链接器(linker) -->输入(input) --> 附加依赖项(Additional Dependencies)
         添加三个依赖库:libmat.lib        libeng.lib       libmx.lib
         (这三个库都在D:\Program Files\MATLAB\R2011b\bin\win64中)
   
3.在源代码中新建一个.cpp文件,加入代码(见下文)就可以调用了  
到这里配置完毕

二、在VS2010中调用MATLAB的代码:

1. 第一步是添加MATLAB在VS中的头文件以及lib库:

#include "matrix.h"
#include "libr2y.h"
#include "libtrans.h"
#include "mclmcr.h"
#include "mclcppclass.h"
#pragma comment( lib, "mclmcr.lib" )
#pragma comment( lib, "libmx.lib" )
#pragma comment( lib, "libmat.lib" )
#pragma comment( lib, "mclmcrrt.lib" )
#pragma comment( lib, "libtrans.lib")
#pragma comment( lib, "libr2y.lib")
#pragma comment( lib, "mclmcrrt.lib")


2. 以下是添加具有C风格的代码,
-添加变量:
   ①首先在c文件中new一个对象,可以任何数据类型
int* var = (int *)malloc(sizeof(int));

   ②在C中,能用于MATLAB操作的变量类型是mxArray  然后利用mxCreateDoubleMatrix()创建一个变量
mxArray *var_in_matlab = NULL;
var_in_matlab = mxCreateDoubleMatrix(row, col, type);

    三个参数分别是创建矩阵的行,列和类型,一般使用mxREAL类型
   ③最后利用memcpy函数将C/C++变量传递到MATLAB中:
memcpy( (void*)mxGetPr(var_in_matlab), (void *)var, sizeof(int) );

   经过以上三步就成功在cpp中建立了变量,接下来是把建立的变量传入到MATLAB中
-调用MATLAB
   把c代码中的变量传到MATLAB中去:只能传mxArray格式  
Engine *ep;
if ( !(ep = engOPen(NULL)) )
return -1;

      // c中变量叫var_in_matlab 与其对应的MATLAB变量名为variable
engPutVariable(ep, "variable", var_in_matlab);

      // engEvalString调用MATLAB引擎执行代码,引号内为满足MATLAB语法的代码
engEvalString(ep, "plot(variable)");

      // 操作完毕之后,释放内存
mxDestroyArray(var_in_matlab);
free(var);

      // 关闭MATLAB引擎链接
engClose(ep);


附个完整版:
</pre><pre>

#include "matrix.h"
#include "libr2y.h"
#include "libtrans.h"
#include "mclmcr.h"
#include "mclcppclass.h"
#pragma comment( lib, "mclmcr.lib" )
#pragma comment( lib, "libmx.lib"
4000
)
#pragma comment( lib, "libmat.lib" )
#pragma comment( lib, "mclmcrrt.lib" )
#pragma comment( lib, "libtrans.lib")
#pragma comment( lib, "libr2y.lib")
#pragma comment( lib, "mclmcrrt.lib")
int main()
{
Engine *ep;// 定义一个调用matlab的对象

if (!(ep = engOpen(NULL))) // 测试MATLAB能否被调用
{
fprintf(stderr, "\nCan't start MATLAB engine\n");
return EXIT_FAILURE;
}

/* matlab矩阵生成函数API
*
* mxCreateDoubleMatrix(row, col, type), 申请函数matlab引擎中使用mxArray数据类型
* \param row 申请矩阵的行数
* \param col 申请矩阵的列数
* \param type 矩阵元素的数据类型,mxREAL为双精度
*
* 申请完毕之后,使用memcpy函数给申请的数组赋值
**/
mxArray *T = NULL, *result = NULL;
T = mxCreateDoubleMatrix(1, Nsample, mxREAL);
memcpy( (void *)mxGetPr(T), (void *)t, Nsample*sizeof(t[0]) ); // 将t中的数据复制到T中

double *V = new double;*V = 20;
mxArray *v = NULL;
v = mxCreateDoubleMatrix(1, 1, mxREAL);
memcpy((void *)mxGetPr(v), (void *)V, sizeof(double));

engEvalString(ep,"path(path,'E:\\Nonlocal Solver Package')"); // 注意双斜杠
engPutVariable(ep, "v", v);
engEvalString(ep, "[PSNR, ImgRec] = NLS1(v)");

fgetc(stdin);

mxDestroyArray(v);
delete V;
engEvalString(ep, "close;");

engClose(ep);

return EXIT_SUCCESS;
}


3. 以下是添加具有C++风格的代码
1). 在matlab的命令行中输入以下命令
     mcc -W cpplib:libname -T link:lib filename.m


即可在matlab中编译生成filename文件对应的C++库。输入的命令中libname是生成的一系列C++库的文件名(包括.cpp .h .dll .lib .exp .exports 以及两个描述生成过程的文本文档),而filename.m则是需要生成C++库的matlab文件。
以上是生成的cpp的库, 如果是想要纯c的库就输入:

mcc c -W lib:libname -T link:lib filename.m
filename是对应的matlab源文件名。内容如下:



然后就会生成如下图的一些文件:



2). 生成了图中所示的文件之后。
-需要在VS工程用到的只有其中的三个(.h .lib 和 .dll)文件,将这三个文件拷到VS工程的目录下,然后在所建立的VS工程名处点击右键->添加->现有项->选中这三个文件->确    定
-并在VS的cpp代码最开始加上 
#include "libr2y.h"

和  
#pragma comment( lib, "libr2y.lib"  )//这里没有分号
3). 接下来就可以在VS中调用生成的函数了

三、在VS2010中调用MATLAB可能遇到的问题:

1. 在运行时丢失libeng.dll的情况
       # 系统环境变量path中添加:D:\Program Files\MATLAB\R2011b\bin\win64 (  即:你的MATLAB安装文件地址下的这个目录 )
2. 在#include "engine.h"中报错的情况
       # 没有配置好 重新配置
3. engOpen函数始终无法打开的情况
       # MATLAB组件没有在注册表中注册。
       # 注册方法:开始-->运行-->cmd 
          在命令行中把当前路径从C:\windows\system32修改到MATLAB的安装路径的bin下:
          比如我的是D:\Program Files\MATLAB\R2011b\bin, 然后在命令行中输入:     
matlab/regserver

  进行注册
          如果注册成功,会弹出MATLAB的命令行窗口      

4. 在VS 2010中调用matlab生成的C++风格的代码进行编程的时候,需要在main函数的最开始的地方执行以下代码:

if ( !mclInitializeApplication(NULL,0) )
{
printf("MCL Inittialized Failed!\n");
exit(EXIT_FAILURE);
}
     # 否则会报出异常,内存违规访问。因为这个话是用来检查是否已经对Mcl进行初始化,否则会出现内存异常,具体是Unhandled Exception C0X00...这是因为引用了未初始化的内存造成了异常。
PS:这个问题困扰了我很久,一直没找到解决的办法,后来在国外的一个网站的角落看到的。。。

5. 在.h文件中可以看到我们需要调用的函数的api,打开.h文件只需要看两个地方

   - 直接拉到文件末尾,这是我们需要使用的函数:



void类型的rgb2yuv()函数,这个函数有2个参数,他们分别的含义是:
const mwArray& src;  // 对应matlab程序中rgb2yuv.m中的src参数
const mwArray& sigma; // 对应matlab程序rgb2yuv.m中的sigma参数


- 另一个地方是



这两个函数分别对应了在VS中调用rgb2yuv()函数的初始化命令和结束命令。也就是说必须在这两个函数位置的中间调用rgb2yuv()才行,即在.cpp代码中应该按照下面的方式来写:

if ( !liby2vInitialize() )
{
rgb2yuv(src, SIGMA);
lib2yuvTerminate();
}


6. 数据的初始化和使用:
mwArray是MATLAB和VS交互变成中专门定义的数据对象,所有MATLAB生成的C++库函数的参数类型都是对它的引用,也就是所有的matlab矩阵类型都可以用它表示,使用方法如下:
// 用C++内存中的变量给matlab程序中的变量赋值
// 首先定义一个C++变量
int sigma[] = { 20 };
int chosen[] = { 1 };

// 再定义一个matlab对象
// 用默认构造函数初始化,三个参数分别是:SIGMA矩阵的行,列,每个元素的数据类型
mwArray SIGMA(1, 1, mxDOUBLE_CLASS);
mwArray src(1, 1, mxUINT8_CLASS);

// 对matlab的对象进行赋值
//  sigma是一个数组, 后面的1代表的是从数组起始位置开始数一共赋值几个值
SIGMA.SetData(sigma, 1);
src.SetData(chosen ,1);

// 加入 2.中的代码
if ( !liby2vInitialize() )
{
rgb2yuv(src, SIGMA);
lib2yuvTerminate();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  matlab vs2010 api 源代码