现在的位置: 首页 > 综合 > 正文

Matlab混合编程

2018年02月12日 ⁄ 综合 ⁄ 共 12613字 ⁄ 字号 评论关闭

Matlab有着编程方便,工具丰富等优点,但同时也有着实时性比较差,通过与其他语言结合使用便可以达到很好的效果。

Matlab, C/C++,OpenCV之间的混合编程。

配置环境:

1)本程序只需要建立win32控制台空项目

2)调用的是Matlab计算引擎,故需要有Matlab环境

3)VS2008中需要在包含文件中加入D:\ProgramFiles\MATLAB\R2009b\extern\include(以后本人的MatlabC混合编程例子中将不再给出此注意点)

4)VS2008中需要在库文件中加入D:\ProgramFiles\MATLAB\R2009b\extern\lib\win32\microsoft(以后本人的MatlabC混合编程例子中将不再给出此注意点)

5)系统变量中加入三个路径:D:\ProgramFiles\MATLAB\R2009b\runtime\win32;D:\ProgramFiles\MATLAB\R2009b\bin\win32;D:\ProgramFiles\MATLAB\R2009b\extern\lib\win32\microsoft;注销后重进系统,以使路径生效

6)应该不会再有问题。【如果还有其他小问题(MainUnicode)网上找可以找到解决办法】

 

1 Matlab调用C语言

参考网址:

http://www.cnblogs.com/tjulxh/archive/2012/04/23/2467087.html

matlab调用C程序

通过把耗时长的函数用c语言实现,并编译成mex函数可以加快执行速度。

Matlab本身是不带c语言的编译器的,所以要求你的机器上已经安装有VC,BC或Watcom C中的一种。

如果你在安装Matlab时已经设置过编译器,那么现在你应该就可以使用mex命令来编译c语言的程序了。

如果当时没有选,就在Matlab里键入mex -setup,下面只要根据提示一步步设置就可以了。

 

为了测试你的路径设置正确与否,把下面的程序存为hello.c

?

/*hello.c*/

#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])

{ mexPrintf("hello,world!/n");

}

 假设你把hello.c放在了C:/TEST/下,在Matlab里用CD C:/TEST/ 将当前目录改为C:/ TEST/(注意,仅将C:/TEST/加入搜索路径是没有用的)。现在敲:
mex hello.c 
如果一切顺利,编译应该在出现编译器提示信息后正常退出。如果你已将C:/TEST/加入了搜索路径,现在键入hello,程序会在屏幕上打出一行:
hello,world! 

整个程序由一个接口子过程 mexFunction构成。
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 
前面提到过,Matlab的mex函数有一定的接口规范,就是指这
nlhs:输出参数数目 
plhs:指向输出参数的指针 
nrhs:输入参数数目 
例如,使用
[a,b]=test(c,d,e)
调用mex函数test时,传给test的这四个参数分别是
      2,plhs,3,prhs
其中: 
prhs[0]=c 
prhs[1]=d 
prhs[2]=e 
当函数返回时,将会把你放在plhs[0],plhs[1]里的地址赋给a和b,达到返回数据的目的。  
细心的你也许已经注意到,prhs[i]和plhs[i]都是指向类型mxArray类型数据的指针。 这个类型是在mex.h中定义的,事实上,在Matlab里大多数数据都是以这种类型存在。当然还有其他的数据类型,可以参考Apiguide.pdf里的介绍。 

 

//hello.c 2.0 
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 
{
int i; 
i=mxGetScalar(prhs[0]); 
if(i==1) 
  mexPrintf("hello,world!/n"); 
else
  mexPrintf("大家好!/n"); 
}

将这个程序编译通过后,执行hello(1),屏幕上会打出: hello,world! 
而hello(0)将会得到: 大家好!

用到了一个函数:mxGetScalar,调用方式如下: 
   I = mxGetScalar(prhs[0]); 
"Scalar"就是标量的意思。在Matlab里数据都是以数组的形式存在的,mxGetScalar的作用就是把通过prhs[0]传递进来的mxArray类型的指针指向的数据(标量)赋给C程序里的变量。这个变量本来应该是double类型的,通过强制类型转换赋给了整形变量i。

 

//hello.c 2.1 
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], 
int nrhs, const mxArray *prhs[]) 
{ 
int *i; 
i=mxGetPr(prhs[0]); 
if(i[0]==1) 
  mexPrintf("hello,world!/n"); 
else
  mexPrintf("大家好!/n"); 
} 

 

这样,就通过mxGetPr函数从指向mxArray类型数据的prhs[0]获得了指向double类型的指针。
但是,还有个问题,如果输入的不是单个的数据,而是向量或矩阵,那该怎么处理呢 ?通过mxGetPr只能得到指向这个矩阵的指针,如果我们不知道这个矩阵的确切大小,就 
没法对它进行计算。 
为了解决这个问题,Matlab提供了两个函数mxGetM和mxGetN来获得传进来参数的行数 和列数。下面例程的功能很简单,就是获得输入的矩阵,把它在屏幕上显示出来: 

//show.c 1.0 
#include "mex.h"
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 
{ 
double *data; 
int M,N; 
int i,j; 
data=mxGetPr(prhs[0]); //获得指向矩阵的指针
M=mxGetM(prhs[0]); //获得矩阵的行数
N=mxGetN(prhs[0]); //获得矩阵的列数
for(i=0;i<M;i++) 
{   for(j=0;j<N;j++) 
     mexPrintf("%4.3f  ",data[j*M+i]); 
     mexPrintf("/n"); 
  }
} 

 

编译完成后,用下面的命令测试一下: 
  a=1:10; 
  b=[a;a+1]; 
  show(a) 
  show(b) 
需要注意的是,在Matlab里,矩阵第一行是从1开始的,而在C语言中,第一行的序数为零,Matlab里的矩阵元素b(i,j)在传递到C中的一维数组大data后对应于data[j*M+i] 。 
输入数据是在函数调用之前已经在Matlab里申请了内存的,由于mex函数与Matlab共用同一个地址空间,因而在prhs[]里传递指针就可以达到参数传递的目的。但是,输出参数却需要在mex函数内申请到内存空间,才能将指针放在plhs[]中传递出去。由于返回指针类型必须是mxArray,所以Matlab专门提供了一个函数:mxCreateDoubleMatrix来实现内存的申请,函数原型如下: 
   mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag) 
   m:待申请矩阵的行数 
   n:待申请矩阵的列数 
为矩阵申请内存后,得到的是mxArray类型的指针,就可以放在plhs[]里传递回去了。但是对这个新矩阵的处理,却要在函数内完成,这时就需要用到前面介绍的mxGetPr。使用 mxGetPr获得指向这个矩阵中数据区的指针(double类型)后,就可以对这个矩阵进行各种操作和运算了。下面的程序是在上面的show.c的基础上稍作改变得到的,功能是将输  

 

 

//reverse.c 1.0 
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], 
    int nrhs, const mxArray *prhs[]) 
{ 
double *inData; 
double *outData; 
int M,N; 
int i,j; 
inData=mxGetPr(prhs[0]); 
M=mxGetM(prhs[0]); 
N=mxGetN(prhs[0]); 
plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL); 
outData=mxGetPr(plhs[0]); 
for(i=0;i<M;i++) 
  for(j=0;j<N;j++) 
   outData[j*M+i]=inData[(N-1-j)*M+i]; 
} 

 

当然,Matlab里使用到的并不是只有double类型这一种矩阵,还有字符串类型、稀疏矩阵、结构类型矩阵等等,并提供了相应的处理函数。本文用到编制mex程序中最经常遇到的一些函数,其余的详细情况清参考Apiref.pdf。 
通过前面两部分的介绍,大家对参数的输入和输出方法应该有了基本的了解。具备了这些知识,就能够满足一般的编程需要了。但这些程序还有些小的缺陷,以前面介绍的re由于前面的例程中没有对输入、输出参数的数目及类型进行检查,导致程序的容错性很差,以下程序则容错性较好

#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[],  int nrhs, const mxArray *prhs[]) 
{ 
double *inData; 
double *outData; 
int M,N; 
//异常处理
//异常处理
if(nrhs!=1) 
    mexErrMsgTxt("USAGE: b=reverse(a)/n"); 
  if(!mxIsDouble(prhs[0])) 
   mexErrMsgTxt("the Input Matrix must be double!/n"); 
   inData=mxGetPr(prhs[0]); 
   M=mxGetM(prhs[0]); 
   N=mxGetN(prhs[0]); 
   plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL); 
   outData=mxGetPr(plhs[0]); 
   for(i=0;i<M;i++) 
     for(j=0;j<N;j++) 
     outData[j*M+i]=inData[(N-1-j)*M+i]; 
  } 

 

在上面的异常处理中,使用了两个新的函数:mexErrMsgTxt和mxIsDouble。MexErrMsgTxt在给出出错提示的同时退出当前程序的运行。MxIsDouble则用于判断mxArray中的数据是否double类型。当然Matlab还提供了许多用于判断其他数据类型的函数,这里不加详述。 
需要说明的是,Matlab提供的API中,函数前缀有mex-和mx-两种。带mx-前缀的大多是对mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等等。而带mx前缀的则大多是与Matlab环境进行交互的函数,如mexPrintf,mxErrMsgTxt等等。了解了这一点,对在Apiref.pdf中查找所需的函数很有帮助。
至此为止,使用C编写mex函数的基本过程已经介绍完了。 

 

 

 

2 C/C++调用Matlab

参考网址:

http://www.cnblogs.com/caixu/archive/2011/06/24/2089126.html

直接给出步骤:

1)设置Matlab的编译器,见MATLABC的混合编程】之【MATLAB调用C程序】

2)编译m文件成dll.

2.1

---------建立MyAdd.m-------------

function[c] = MyAdd(a, b);
c = a + b;

-----------------------------------

2.2

Matlab中运行mcc -W cpplib:libMyAdd -T link:lib MyAdd

成功后,我们会发现目录下多了很多文件,其中libMyAdd.dlllibMyAdd.liblibMyAdd.h为有用文件,接下来要用到。

3)设置VS2008包含文件库文件,见MATLABC的混合编程】之【C程序调用Matlab计算引擎】(1)

4)编写C调用dll.

a)VS2008中建立win32控制台空项目

b)项目中加载libMyAdd.dlllibMyAdd.liblibMyAdd.h这三个文件;前两个放在C:\Documents
andSettings\Administrator\My Documents\Visual Studio 2008\Projects\Matlab_C\Debug
,后一个放在C:\Documents and Settings\Administrator\My Documents\Visual Studio2008\Projects\Matlab_C\Matlab_C

c)写代码,如下:

-----------------------------------------------------------------

#pragma comment( lib, "mclmcrrt.lib" )
#pragma comment( lib, "libmx.lib" )
#pragma comment( lib, "libmat.lib" )
#pragma comment( lib, "mclmcr.lib" )
#include "mclmcr.h"
#include "matrix.h"
#include "mclcppclass.h"
#include "libMyAdd.h"
#include <stdio.h>
#include <iostream>
using namespace std;
int main(void)
{
    double a = 6;
    double b = 9;
    double c;

    // initialize lib,这里必须做初始化!
    if( !libMyAddInitialize())
    {
        cout << "Could not initializelibMyAdd!" << std::endl;
        return -1;
    }

    // 为变量分配内存空间,可以查帮助mwArray
    mwArray mwA(1, 1, mxDOUBLE_CLASS); // 1
1表示矩阵的大小(所有maltab只有一种变量,就是矩阵,为了和Cpp变量接轨,设置成1*1的矩阵,mxDOUBLE_CLASS表示变量的精度)
    mwArray mwB(1, 1, mxDOUBLE_CLASS);
    mwArray mwC(1, 1, mxDOUBLE_CLASS);

    // set data,不用我解释了吧,很简单的,调用类里面的SetData函数给类赋值
    mwA.SetData(&a, 1);
    mwB.SetData(&b, 1);
    // using my add
,掉我自己写的函数
    MyAdd(1, mwC, mwA, mwB);
    // get data
,不用我解释了吧,很简单的,调用类里面的Get函数获取取函数返回值
    c = mwC.Get(1, 1);
    printf("c is %f\n", c);
    //
后面是一些终止调用的程序
    // terminate the lib
    libMyAddTerminate();
    // terminate MCR
    mclTerminateApplication();
    return 0;
}

 

先贴本人调试通过的代码:
#pragma comment(lib, "libmx.lib")
//#pragma comment(lib, "libmat.lib")//
注销了也没关系
#pragma comment(lib, "libeng.lib")
#include <math.h>
#include "engine.h"
#include <iostream>
using namespace std;
int main()
{
    const int N = 50;
    double x[N],y[N];
    int j = 1;
    for (int i=0; i<N; i++) //
计算数组xy
    {
        x[i] = (i+1);
        y[i] = sin(x[i]) + j * log(x[i]); //
产生-之间的随机数赋给xx[i];
        j*= -1;
    }
    Engine *ep; //
定义Matlab引擎指针。
    if (!(ep=engOpen(NULL))) //
测试是否启动Matlab引擎成功。
    {
        cout <<"Can't startMatlab engine!" <<endl;
        exit(1);//
可以思考下
    }

    //定义mxArray,为1行,N列的实数数组。
    mxArray *xx = mxCreateDoubleMatrix(1,N, mxREAL);
    mxArray *yy = mxCreateDoubleMatrix(1,N, mxREAL); //
同上。

    memcpy(mxGetPr(xx), x, N*sizeof(double)); //将数组x复制到mxarray数组xx中。
    memcpy(mxGetPr(yy), y, N*sizeof(double)); //
将数组x复制到mxarray数组yy中。

    engPutVariable(ep, "xx",xx); //mxArray数组xx写入到Matlab工作空间,命名为xx
    engPutVariable(ep, "yy",yy); //
mxArray数组yy写入到Matlab工作空间,命名为yy

    //【特色】向Matlab引擎发送画图命令。plotMatlab的画图函数,参见Matlab相关文档。
    engEvalString(ep, "plot(xx, yy); ");

    mxDestroyArray(xx); //销毁mxArray数组xxyy(注:Matlab工作空间中的xxyy变量在这里没有销毁)
    mxDestroyArray(yy);

    cout <<"Press any key to exit!"<<endl;
    cin.get();
    engClose(ep); //关闭Matlab引擎。
}

------------------------------------------------------------------------------------------

结果贴图:

Matlab中内存变量:
xx =
  Columns 1 through 22
     1     2    3     4     5    6     7     8    9    10    11   12    13    14   15    16    17   18    19    20   21    22
  Columns 23 through 44
    23    24   25    26    27   28    29    30   31    32    33    34   35    36    37   38    39    40   41    42    43    44
  Columns 45 through 50
    45    46   47    48    49    50
yy =
  Columns 1 through 13
    0.8415    0.2162   1.2397   -2.1431    0.6505  -2.0712    2.6029   -1.0901   2.6093   -2.8466    1.3979  -3.0215    2.9851
  Columns 14 through 26
   -1.6484    3.3583  -3.0605    1.8718   -3.6414   3.0943   -2.0828    3.8812  -3.0999    2.2893   -4.0836    3.0865  -2.4955
  Columns 27 through 39
    4.2522   -3.0613   2.7037   -4.3892    3.0299  -2.9143    4.4964   -2.9973   3.1272   -4.5753    2.9674  -3.3412    4.6274
  Columns 40 through 50
   -2.9438    3.5549  -4.6542    2.9294   -3.7665   4.6576   -2.9269    3.9737  -4.6395    2.9381   -4.1744

===========================================================================================

注意事项:

1)本程序只需要建立win32控制台空项目

2)调用的是Matlab计算引擎,故需要有Matlab环境

3)VS2008中需要在包含文件中加入D:\ProgramFiles\MATLAB\R2009b\extern\include(以后本人的MatlabC混合编程例子中将不再给出此注意点)

4)VS2008中需要在库文件中加入D:\ProgramFiles\MATLAB\R2009b\extern\lib\win32\microsoft(以后本人的MatlabC混合编程例子中将不再给出此注意点)

5)系统变量中加入三个路径:D:\ProgramFiles\MATLAB\R2009b\runtime\win32;D:\ProgramFiles\MATLAB\R2009b\bin\win32;D:\ProgramFiles\MATLAB\R2009b\extern\lib\win32\microsoft;注销后重进系统,以使路径生效

6)应该不会再有问题。【如果还有其他小问题(MainUnicode)网上找可以找到解决办法】

【引文】http://blog.sina.com.cn/s/blog_53c43ef90100q21r.html

 

 

 

3              Matlab调用OpenCV

参考网址:http://www.opencv.org.cn/forum/viewtopic.php?p=49434

C:\Documents andSettings\Administrator\Application Data\MathWorks\MATLAB\R2010b\mexopts.bat

 

 

 

     
Matlab调用cpp+opencv库心得

 bittnt »
2010-01-04 21:57

问题描述:
Matlab
调用CPP不新鲜,无非就是把写好的c语言编译成mex,然后直接调用呗。很多帖子和书都有描述。具体可以参考附录。这里描述的是如何用Matlab调用Opencv库支持的函数。

解决方法:
0
、当然,你得先设置好起码的mex-setup,就是指定编译器,如果在M¥中大家都设成VS2008VS2005之类的吧。
进入正题
1
、首先打开我的Matlab2009b,然后输入mex-v,可以发现清单中Optionsfile对应那项,直接选中那个文件名,在我这里差不多就是C:\Users\bit\AppData\Roaming\MathWorks\MATLAB\R2009b\mexopts.bat这个文件名,然后右键打开所谓open
selection

2
、进入编辑状态后,找到所谓PAPTHINCLUDELIB等地方,和在VisualStudio中设置options中那个VC
diectory
目录一样。
3
、然后还得改LINKFLAGS=后面一大堆。如我这里把这个地方一行加成这样子
set LINKFLAGS=/dll /export:%ENTRYPOINT% /LIBPATH:"%LIBLOC%"cxcore200d.lib cv200d.lib highgui200d.lib ml200d.lib cvaux200d.lib libmx.liblibmex.lib libmat.lib /MACHINE:X86 kernel32.lib user32.lib gdi32.libwinspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib
oleaut32.libuuid.lib odbc32.lib odbccp32.lib /nologo /incremental:NO/implib:"%LIB_NAME%.x"/MAP:"%OUTDIR%%MEX_NAME%%MEX_EXT%.map"
其实就是和调用Opencv里面设置lib那一大堆文件一样。
4
、这不算完,然后在VS中新建一个project,选择建立DLL动态链接库工程,最好都是空的。按照正常方式设置好opencv。然后在sourcefiles下添加你的code,比如我这里添加了Wrapper.cpp的程序。往里面填代码。其具体方式给个例子:
#include "mex.h"
#include <cv.h>
#include <highgui.h>
#include <cvaux.h>
#include <cxcore.h>
#include <ml.h>
using namespace cv;
void mexFunction (int nlhs, mxArray *plhs[], //
输出参数个数,及输出参数数组
int nrhs, const mxArray *prhs[]) //
输入参数个数,及输入参数数组
{
int m, n;
double *params, *des, *loc;
char name[256];
int buflens = mxGetNumberOfElements(prhs[0]);
mxGetString(prhs[0], name, buflens+1);
params = mxGetPr(prhs[1]);
loc = mxGetPr(prhs[2]);
m = mxGetM(prhs[2]);
n = mxGetN(prhs[2]);
if (mxGetM(prhs[1]) != 9 || mxGetN(prhs[1]) != 1)
{
mexErrMsgTxt("Error in parameter\n");
}
if (m <= 0 || n != 2)
{
mexErrMsgTxt("Error in location\n");
}
if (!mxIsChar(prhs[0]))
{
mexErrMsgTxt("First parameter must be string\n");
}
//mexPrintf(name);
IplImage * img = cvLoadImage(name, 1);
Mat mat(img);
//Mat mat = imread(name, 1);
if (mat.data == NULL)
{
mexErrMsgTxt("Error in image\n");
}
NamedWindows("1",1);
imshow("1",mat);
WaitKey(0);
return;
}
当然同目录下还得加入一个Wrapper.def文件,这个里面内容最好是如下:
LIBRARY Wrapper
EXPORTS mexFunction
6
、这不算完,打开Tools->options,然后看到Projectand solutions后往下面找VC++Directories中那个Excutablefiles,变更为IncludeFiles,然后添加你的matlab根目录\extern\include\win32还有include两个目录。此外,添加Libraryfiles中根目录\extern\lib\win32\microsoft。以及在Sourcefiles下添加Opencv2.0\Vc2008\src这个路径。
跑到Proejctproperty下面找additionaldependencies,在opencv一大堆lib后面继续添加libmex.liblibmx.lib
libmat.lib

7
、编译这个文件。然后开始debug,不出意外,会打开一个matlab2009b的主程序,这样子后。找到你的vsproject下面,然后在命令框输入mexWrapper.obj,然后再输入Wrapper('lena.jpg');,这样子就可以调用opencv中那个函数了。

There is awill, there is a way!
http://hi.baidu.com/bittnt

 

这个帖子是比较好的。但是在设置一些东西的时候注意些。

 set MSDevDir=%MSDevDir%
set VSINSTALLDIR=C:\Program Files\Microsoft Visual Studio
set OPENCVDIR=C:\Program Files\OpenCV
set VCINSTALLDIR=%VSINSTALLDIR%\VC98
set PATH=%VCINSTALLDIR%\BIN;%VSINSTALLDIR%\Common\msdev98\bin;%OPENCVDIR%\bin;%PATH%
set INCLUDE=%VCINSTALLDIR%\INCLUDE;%VCINSTALLDIR%\MFC\INCLUDE;%VCINSTALLDIR%\ATL\INCLUDE;%OPENCVDIR%\cv\INCLUDE;%OPENCVDIR%\cxcore\INCLUDE;%OPENCVDIR%\cvaux\INCLUDE;%OPENCVDIR%\ml\INCLUDE;%OPENCVDIR%\otherlibs\highgui;%OPENCVDIR%\otherlibs\cvcam\INCLUDE;%INCLUDE%
set LIB=%VCINSTALLDIR%\LIB;%VCINSTALLDIR%\MFC\LIB;%OPENCVDIR%\LIB;%LIB%
set MW_TARGET_ARCH=win32

 

这两个地方都加入了一些修改,修改的过程中注意脚本的格式。

 

抱歉!评论已关闭.