发信人: fork (撒哈拉沙漠的沙), 信区: Matlab
标 题: 分析:解决m程序转化成cpp程序的编译问题【小波工工?
发信站: 哈工大紫丁香 (Sat Nov 29 21:32:06 2003), 站内信件
背景:有一个朋友想用小波变换对图像处理,利用现成的matlab的小波工具箱中的
程序。但是他导师要求将所有的matlab程序转化成c语言程序并在VC环境下编译。
其实,用matlab的程序转化为cpp文件并独立编译存在着很大的局限性。首先对于
很多已编译好的mex程序,虽然能够编译通过但通常会得到这个警告:
“the "XXX" function is only available in MEX mode. A run-time error
will occur if this code is executed in stand-alone mode.”这会引起一个
运行时错误,仔细检查会发现这样的mex文件是以dll形式存在,对应的m文件
只是一个幌子而已,m文件的存在仅仅是为了提供使用说明而已;即使你用到的
所有函数都是以m文件存在,有时候还是有问题,请看下面的程序:
%%%%%%%%%%%%%
function simon()
[X,map]=imread('simon.bmp');
x=X;
colormap(map);
x=double(x);
h=wavedecnd(x,2,'haar')
image(h{1});
%%%%%%%%%%%%%
该程序对simon.bmp做'haar'小波变换并显示第一块。
编译它:mcc -B sglCpp simon
运行编译后自动生成的simon.exe,发生错误:
“Exception! File: handler.cpp, Line: 73
Variables are not supported by EVAL in compiled code.”
这段话表示函数"eval"不支持cpp编译,但是我们并没有显式的调用过这个函数
啊,那么肯定是在我们调用的其他函数中间接的调用了这个函数。于是打开
wavedecnd函数一个一个的检查所有它直接或间接调用过的函数,最后在
wavemngr.m中找到了对eval的三次调用:
“eval(['load ' bin_file ' -mat'],'err = 1;');”
如何来解决这个问题呢?mathworks给出了答案,参见:
http://www.mathworks.com/support/tech-notes/1100/1103.shtml
我选择了用“try catch”结构替换eval的间接调用:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% eval(['load ' bin_file ' -mat'],'err = 1;');
try
load(bin_file,' -mat');
catch
err=1;
end
if err
err = 0;
% eval(['load ' bin_ini_file ' -mat'],'err = 1;');
try
load(bin_ini_file,' -mat');
catch
err=1;
end
.......................................
% eval(['save ' bin_file ' Wavelets_Info'],'err = 1;');
try
save(bin_file,' Wavelets_Info');
catch
err=1;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
完成后,再一次编译:mcc -B sglCpp simon
运行程序,又出错:
“Exception! File: handler.cpp, Line: 73
Reference to unknown function 'dbwavf' from FEVAL in stand-alone mode.”
意思是在feval中调用了未知函数“dbwavf”,于是找到在wfilters.m中有这样
一处调用:
“F = feval(fname,wname);”
而fname来自于该文件中的一句:
“[wtype,fname] = wavemngr('fields',wname,'type','file');”
追查!打开wavemngr.m看到了这样的语句:
“files = ...
{...
'dbwavf';
'dbwavf';
'symwavf';
'coifwavf';
'biorwavf';
'rbiowavf';
'meyer';
'dmey.mat';
'gauswavf';
'mexihat';
'morlet'
'cgauwavf';
'shanwavf';
'fbspwavf';
'cmorwavf'
};
”
于是解决的方法也就出来了,分析出错的原因在于文件中用feval间接的调用
了函数“dbwavf”,feval只是将它作字符串而不是文件名处理而之前的代码
中又没有显式的声明过该函数,因而编译器也就不知道还需要在生成的cpp代
码中加上对该函数的声明了,也不会额外的将dbwavf.m转化成cpp文件,解决
的办法有两个:
1,直接用“F = dbwavf(wname)”来替代“F = feval(fname,wname);”
再编译,运行,没问题了:)
2,读者一定发现第一个办法中问题了,如果是调用的symwavf,或者morlet
或者任何别的函数呢?那么这个方法就降低原程序的灵活性,解决的方法
(呵呵,想到这个方法实在需要些灵感!)就是在wfilters.m中该调用
“F = feval(fname,wname);”之前对所有有可能要调用到的函数做一次
伪声明(之所以叫伪声明是因为matlab中似乎没有声明一说,而这么做的
实质等同于c语言中的声明),即在“F = feval(fname,wname);”之前
加上一句:“dbwavf('haar');”
现在成了:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
dbwavf('haar');
if wtype==1 % orth. wavelet
if ~isempty(mat_f)
F = eval(wname);
else
F = feval(fname,wname);
%F=dbwavf(wname);
end
..................................
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
注意,我只加了一句:“dbwavf('haar');”,因为我知道它只会调用
这一个函数,如果它要调用多个函数,只要依样画葫芦就行了。
编译,运行,ok了:)
剩下的事情就是将生成的cpp文件和hpp文件加入到VC中的工程里,修改相应
的编译和连接参数,编译出一个独立的exe程序了。