Windows 64 + Matlab 64 MEX混合编程初步



说明

记录本人在Windows下,使用Matlab 64-bit 版进行混合编程时遇到的问题,主要记录编译器的安装与简要的混编过程。

  • Matlab版本:Matlab R2014a 64-bit、Matlab R2015b 64-bit
  • 操作系统版本:Windows 8.1 64-bit、Windows10 64-bit
  • 编译器:Microsoft Windows SDK 7.1(C/C++) 和 GNU编译器(有MinGW(Minimalist GNU for Windows,仅32位)、MinGW64(64位和32位)、TMD-GCC(非官方的编译器包)、CygWin等等,它们间的区别与联系参见GCC_Cygwin_MinGW_TDM-GCC

Matlab混合编程

下载与安装编译器

Microsoft Windows SDK 7.1(C/C++)

点此Microsoft Windows SDK for Windows 7 and .NET Framework 4 (ISO)打开下载页面,是镜像文件,选择64-bit版,文件大小500M+,全部安装需占磁盘近2G。

下载完成后根据提示安装即可,如果出现问题,安装失败,参考:Problem&Solution 部分。

TDM-GCC(gcc/g++)

For Matlab 2015

Matlab 2015已经开始支持GNU编译器,具体参见:Supported and Compatible Compilers for R2015b,安装方法参见:Install MinGW-w64 Compiler

  • 注意,MATLAB 2015现仅支持GCC4.9.2,在安装TMD-GCC时,不要勾选更新,如下图:
    安装TMD-GCC注意事项

  • 然后,还需注意的是安装路径不能有空格;

  • 需要添加系统环境变量MW_MINGW64_LOC=your tdm-gcc path
  • 重启系统和MATLAB后,输入mex -setup显示:
    MATLAB2015 MinGW64

至此完成!

For Matlab 2014

如下文章针对于MATLAB 2014a。

点此tmd-gcc打开下载页面,选择64位版本,40M+,全部安装占用400M+磁盘空间。

根据以前使用经验,安装路径最好不要有空格中文。

安装完成后,开始 -> 运行 -> cmd打开Windows命令窗口,输入gcc -v,如下图所示,显示安装信息,说明安装成功:
安装成功

最后的战斗:
因为Matlab不支持GNU的编译器,还得做点事,下面的方法来自Using GCC (MinGW) as MATLAB’s MEX compiler 中的Bogdan的解答:

下面的代码是从Bogdan主页上下载的mexopts.bat文件代码,使用时需要做一点小小的改动。

在下面的代码中找到:set MINGWPATH=p:\mingw64这句代码,将其中的路径p:\mingw64替换成你的TMD-GCC-64的安装目录,如我的是:E:\devtools\TDM-GCC-64,然后保存并将mexopts.bat文件copy到计算机如下路径(复制下面的路径地址,粘贴到资源管理器窗口地址栏,回车即可):

%USERPROFILE%\AppData\Roaming\Mathworks\MATLAB\R2014a\

下面是代码:

@echo off

:: NOTE: this is actually not a proper .bat file executed by Windows. MEX
::       parses it and only understands a very reduced set of commands:
::       "set" and "rem" apparently, everything else is ignored (behaves as
::       "rem"), so don't do any fancy batch stuff in here. There are some
::       undocumented special vars you can set here that will trigger MEX
::       to do fancy stuff.

:: You can use MinGW64 builds (win32 threads + seh unwinding) from here:
:: http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/

:: Tested with the following:
:: http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/4.9.1/threads-win32/seh/x86_64-4.9.1-release-win32-seh-rt_v3-rev1.7z

:: Set this to your Mingw64 top folder, where you extracted the above
set MINGWPATH=p:\mingw64

:: Leave these alone unless you know what you're doing.
set PATH=%MINGWPATH%\bin;%PATH%
set PRELINK_CMDS=echo.>%TEMP%\mexstaticlibs

:: You can have MEX run some commands before calling the linker.
:: The two examples below will cause gcc to output the full path to some
:: static libraries so you can link statically to them (see the
:: LINGFLAGSPOST special var below). You can set any command here, however.
rem set PRELINK_CMDS1=gcc -print-file-name=libwinpthread.a >> %TEMP%\mexstaticlibs
rem set PRELINK_CMDS2=gcc -print-file-name=libquadmath.a >> %TEMP%\mexstaticlibs
rem set PRELINK_CMDS3=...

:: You can have MEX run some commands also after calling the linker
:: (e.g. upx compress the output .mex)
rem set POSTLINK_CMDS1=upx -9 "%OUTDIR%%MEX_NAME%%MEX_EXT%"
rem set POSTLINK_CMDS2=...

:: You can change these if you really need to.
set COMPILER=g++
set COMPFLAGS=-c -I"%MATLAB%\extern\include" -DMATLAB_MEX_FILE
set OPTIMFLAGS=-O3 -funroll-loops -DNDEBUG
set DEBUGFLAGS=-g
set NAME_OBJECT=-o

set LINKER=g++
set LINKFLAGS=-shared -static-libstdc++ -static-libgcc -L"%MATLAB%\bin\win64" -L"%MATLAB%\extern\lib\win64\microsoft" -lmex -lmx -leng -lmat -lmwlapack -lmwblas

set LINKFLAGSPOST=@%TEMP%\mexstaticlibs
set NAME_OUTPUT=-o "%OUTDIR%%MEX_NAME%%MEX_EXT%"


:: EXAMPLES
:: ========

:: You can compile simple files using "mex file.cpp". To support more than 2^32 elements, use
:: "mex -largeArrayDims file.cpp" ... use this by default, unless you know what you're doing.

:: To add include dirs, lib dirs, or compile/link flags, do:
:: mex COMPFLAGS="$COMPFLAGS -std=gnu99 -Ix:/include/dir" LINKFLAGS="$LINKFLAGS -Lx:/libs/dir -lmylib" -largeArrayDims file.cpp

选择编译器

  1. 查看可用编译器:使用mex -setup查看可选择的编译器,如果没有需要自己安装,如果已安装且只安装了编译器Microsoft Windows SDK 7.1(C/C++),显示如下结果:
    查看可用编译器

  2. 选择编译器:使用mex -setup lang选择编译器,如mex -setup C++选择C++编译器,如下图:
    选择编译器

  3. 如果你也按上面TDM-GCC(gcc/g++) 中讲的方法,配置了TDM-GCC-64位的编译器,那么,你会发现结果如下:
    没有显示TDM-GCC-64编译器
    刚开始我也以为不能用,后来试着编译了一下,竟然可以!
    使用TDM-GCC-64编译器编译
    DT.c文件中重复定义了无穷大,注释掉,就没有提示啦!

编写c/cpp文件

与普通的C文件的编写有两点不同:

  1. 包含mex.h头文件,即:#include "mex.h"

  2. 编写mexFunction函数。

下面以一个求和的例子说明:

#include "mex.h" // 使用MEX文件必须包含的头文件
// 执行具体工作的C函数
double add(double x, double y)
{
    return x + y;
}
// MEX文件接口函数
void mexFunction(int nlhs,mxArray *plhs[], int nrhs,const mxArray *prhs[])
{
    double *z;
    double x, y;
    plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);
    z = mxGetPr(plhs[0]);
    x = *(mxGetPr(prhs[0]));
    y = *(mxGetPr(prhs[1]));
    *z = add(x, y);
}

Matlab命令窗口输入mex add.cpp,运行结果如下图:
编译结果

在Windows上编译后生成mexw32mexw64文件,在Linux上编译会生成mexa32mexa64文件。

mexFunction函数介绍

mexFunction函数接口如下:

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

可见,是没有返回值的,其实是通过指针数组plhs传递的。它共有四个参数,即左边的输出参数及数目和右边的输入参数及数目,具体参数意义如下:

参数 意义 英文全称 类型
nlhs 左边输出参数的数目 number of left-hand side 整型(int)
plhs 指向输出参数的指针 pointer of left-hand side 指针数组
nrhs 右边输入参数的数目 number of right-hand side 整型(int)
prhs 指向输入参数的指针 pointer of right-hand side 指针数组

详情参考:

  1. Matlab参考-MEX库

  2. MATLAB中mexFunction函数的接口规范(转载)

  3. Matlab与C语言程序的应用编程接口

  4. matlab和C/C++混合编程–Mex

编译多个c/cpp文件

假设A.c调用B.cB.c调用C.c
可以使用如下命令编译:

mex C.c
mex B.c
mex A.c

或者

mex A.c B.c C.c

一些实例

MATLAB2015编译MeanShift

MeanShift分割源码包,可以从这里下载,也可以从本人网盘(含MATLAB接口,和编译好的mexw32mexw64mexa64)下载。

原本代码中没有适用于Windows64和MATLAB64位的mexw64文件,需要自己编译生成,方法很简单,运行文件夹中的compile_edison_wrapper.m文件即可。

然后,读入一幅图像,调用edison_wrapper程序实现分割,注意要使edison_wrapper文件夹处于当前路径。如读入一幅Lena RGB图像,分割结果如下:

I=imread('D:\DataSets\oi\nsi\classical\LenaRGB.bmp');
[fimage, labels] = edison_wrapper(I, @RGB2Luv);
figure
subplot(121)
imshow(I)
title('Orignal RGB image')
subplot(122)
imagesc(labels)
axis image % 坐标轴与图像尺寸一致
title('Segmentation result:labels')

MeanShift分割

Problem&Solution

找不到编译器或SDK

Problem

提示:“未找到支持的编译器或 SDK”,如下图:
未找到支持的编译器

Solution

根据Matlab的提示,安装:Microsoft Windows SDK for Windows 7 and .NET Framework 4 (ISO),在下载页面,有三个ISO文件可以选择,如下表选择第三个,即amd64

名称 版本
GRMSDK_EN_DVD.iso x86
GRMSDKIAI_EN_DVD.iso Itanium
GRMSDKX_EN_DVD.iso amd64

注意

如果安装Microsoft Windows SDK for Windows 7 and .NET Framework 4 (ISO)时出现如下错误:

A problem occurred while installing selected Windows SDK components.

Installation of the “Microsoft Windows SDK for Windows 7” product has reported the following error: Please refer to Samples\Setup\HTML\ConfigDetails.htm document for further information.

Please attempt to resolve the problem and then start Windows SDK setup again. If you continue to have problems with this issue, please visit the SDK team support page at http://go.microsoft.com/fwlink/?LinkId=130245.

Click the View Log button to review the installation log.
To exit, click Finish.

如下图:
A problem occurred while installing selected Windows SDK components.

解决办法
出现此问题,很可能是你的PC机已经安装了:Microsoft Visual C++ 2010,而在安装Microsoft Windows SDK for Windows 7 and .NET Framework 4 (ISO)时默认选择安装Microsoft Visual C++ 2010,如下图,造成的冲突,可以卸载已经安装的,注意32和64位的都要卸载

Windows SDK 安装选项

卸载完成后从新安装即可!!!

error C2143: syntax error

Problem

提示错误:error C2143: syntax error : missing ‘;’ before ‘type’,如下图所示:
错误提示

Solution

出现这种现象,很可能是你在用VC的编译器编译GNU的C语言写的代码,两个编译器中的C标准不一样。

一种方法是将文件后缀名.c,改成.cpp,重新编译,但可能还会有其它的错误。

如果源文件是GNU的C代码,建议安装相应的编译器,然后编译,可参考TDM-GCC(gcc/g++)

一些有用的总结

注意系统平台和文件路径

MATLAB 匹配查找文件的方式是这样的:

先从当前目录寻找,假如没有,再到搜索路径中从顶层寻找,如果在同一目录下找到了函数名相同的.m文件、.mex…文件,如果.mex…文件和平台匹配,则执行之,反之执行.m文件。

系统平台

假如你有这样一个工具包tools,文件结构如下,tools为当前目录
tools目录结构示意

其中,func.m函数为MATLAB版,同时又用C语言写了类似的函数,并mex混编生成了Linux平台下的:mexa32、mexa64;Windows平台下的:mexw32、mexw64以及MAC平台下的:mexmac文件,如上图。

  • 假如你现在处于Windows系统,并且MATLAB版本为64位,那么,你只能成功调用func.mfunc.mexw64两个文件,并且会优先选择func.mexw64,而“mexw32”和“mexa64”都是不能用的。
  • 假如你现在处于Windows系统,并且MATLAB版本为32位,那么,你只能成功调用func.mfunc.mexw32两个文件,并且会优先选择func.mexw32,“mexw64”和“mexa32”都是不能用的。

文件路径

依然如上图tools目录结构示意所示,tools为当前目录,不同的是:

  • 你删除了func.mexw32func.mexw64文件,你的运行环境是Windows下的MATLAB,那么你调用成功的是func.m文件,而不是“mex”文件夹中的func.mexw32func.mexw64,因为MATLAB第一匹配到“func”函数的是func.m

运行效率对比

实验说明:

主要对比MATLAB与C的(mex函数)分别在32和64位MATLAB上的执行效率。

实验环境:ThinkPad E430c + Windows 10 + MATLAB 2015a(32bit)/ MATLAB 2015b(64bit)。

  • 实验1:循环N次,N=2×108

test.m 源码:

N = 2*10e8;
tic
func(N)
toc

tic
for i=0:N-1
end
toc

混编C代码(func.c):

#include "mex.h" // include head files
// function
double loopN(double N)
{
    int i = 0;
    for(i = 0; i< N; i++); 
    return i;
}
// interface
void mexFunction(int nlhs,mxArray *plhs[], int nrhs,const mxArray *prhs[])
{
    double *z;
    double N;
    plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);
    z = mxGetPr(plhs[0]);
    N = *(mxGetPr(prhs[0]));
    *z = loopN(N);
}
  • 实验2:提取图像特征,工具包 matlabPyrTools

测试MATLAB代码:

N = 20;
I=imread('D:\DataSets\oi\nsi\classical\BaboonRGB.bmp');
time_using = cputime;
grayimg = double(rgb2gray(uint8(I)));
for i = 1:N
    [pyr,pind] = buildSpyr(grayimg,3,'sp3Filters');
    pyramids = getSpyr(pyr,pind);
end
time_using = cputime - time_using;
time_using = time_using/N;
disp(time_using)
  • 实验3:MeanShift分割,工具包 edison_wrapper,含MATLAB interface。

测试MATLAB代码:

N = 20;
I=imread('D:\DataSets\oi\nsi\classical\BaboonRGB.bmp');
time_using = cputime;
for i = 1:N
    [fimage, labels] = edison_wrapper(I, @RGB2Luv);
end
time_using = cputime - time_using;
time_using = time_using/N;
disp(time_using)
  • 实验4:MeanShift分割,工具包 edison_wrapper,含MATLAB interface,对用matlabPyrTools提取的金字塔特征进行分割。

测试MATLAB代码:

N = 20;
I=imread('D:\DataSets\oi\nsi\classical\BaboonRGB.bmp');
time_using = cputime;
for i = 1:N
    [fimage, labels] = edison_wrapper(I, @ExtractFeature,  'SpatialBandWidth', 7, 'RangeBandWidth', 12, 'MinimumRegionArea', 200);
end
time_using = cputime - time_using;
time_using = time_using/N;
disp(time_using)

实验结果:

单位:s

实验序号 MATLAB(32) MATLAB(64) C(MEX, 32) C(MEX, 64)
1 4.91 7.42 4.54 1.43
2 - - 0.9953 0.4453
3 - - 4.10 4.98
4 - - 11.64 17.63

实验结果很不可思议!

  1. 实验1:64位MATLABfor循环竟然比32位的慢了好些,而mex的C则相反(正常表现),不过可以看出C语言要比MATLAB快;
  2. 实验2:正常表现;
  3. 实验3:有些反常;
  4. 实验4:64位竟然慢了那么多!

对于实验4,观察返回值labels,即超像素的标签,发现32位和64位结果并不一致,但大致相同,图形显示如下:
labels结果(MATLAB 32位和64位)

MATLAB 32位和64位下得到的labels的部分值:
labels32和labels64部分值


发布了84 篇原创文章 · 获赞 131 · 访问量 41万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览