1、 1 Matlab与 C混合编程的 方法研究与实现 摘要: 文章 探讨了 MATLAB与 VC+的优缺点, 介绍了 VC+与 Matlab混合编程的几种方法。通过二者的结合,既有效地利用了 MATLAB强大的数值计算能力和众多的函数,大大减少程序设计的工作量,又继承了 VC+良好的程序界面,证明是一种很好的程序设计方法。 具体说明了如何应用 Matlab引擎实现混合编程 以 及 如何 利用 MATCOM进行 MATLAB和 VC+混合编程 , 并 将两种方法 用于 数字 图像处理。 关键词: MATLAB; VC+; MATCOM; 引擎; 混合编程;图像处理 一、 引言 1、 数字图像处理简
2、介: 图像技术由高到低分为三个层次:图像处理、图像分析和图像理解。图像处理是比较底层的操作,它主要在图像像素级上进行处理,处理的数据量非常大。数字图像处理最基本的目的就是改善图像,主要是按需要进行适当的变换突出某些有用的信息,去除或消弱无用的信息,如改变图像的对比度,去除噪声或强调边缘的处理等,其基本方法有:直方图修正、灰度变换、图像的频域特性、图像平滑、图像锐化等。 直方图是图像的重要统计特征,是表示数字图像中每一灰度级与该灰度级出现的频率数间的统计关系。直方图能给出该图像的大 致描述,如灰度范围、灰度级的分布、整幅图像的平均亮度等,但它不能完整地描述一幅图像。通常用横坐标表示灰度级,纵坐标
3、表示频数。 通常一幅均匀量化的自然图像由于其灰度直方图分布集中在较窄的低值灰度区间,引起图像的细节看不清楚,为 使 图像变得清晰,我们 可以通过变换使图像的灰度范围拉开或使灰度分布在动态范围内趋于均匀化,从而增加反差,使图像的细节清晰,达到图像增强的目的。 灰度变换是图像增强的 一种重要手段,它可以使图像动态范围加大,使图像对比度扩展,图像更加清晰,特征更加明显。灰度变换可分为线性、分段线性、非线性以及 其他的灰度变换。线性灰度变换实际上使曝光不充分的图像中黑的部分更黑,白的部分更白,从而提高对比度。 图像中的边缘或者线条部分与图像频谱中的高频成分相对应,因此采用高通滤波的方法让高频分量顺利通
4、过, 使 低频分量受到抑制,就可以增强高频的成分,使图像的边缘或者线条变得清晰,实现图像的锐化。 图像的平滑主要目的是减少图像噪声,减少噪声的方法可以在空间域或者在频率域处理,即:在空间域中进行时,其基本方法是求像素的平均值或者中值;在频率域中则运用低通滤波技术。低通滤波,图像的噪声频谱一般位于空间频率较高的区域,而图像本 身的频率分量则处于空间频率较低的区域内,因此可以通过低通滤波的方法, 使 高频成分受到抑制,而 使 低频成分顺利通过,从而实现图像的平滑。 2、 混合编程在图像处理方面的应用 Matlab是一种应用广泛的编程工具,语法简单函数丰富,具有优秀的图形显示功能及强大的人机交互能力
5、。 Matlab在图象处理方面更有着明显的优势: ( a) 它具有强大的矩阵运算功能,在进行一些简单的图象变换时可以避免很多烦琐的计算; ( b) 图形显示方便,有专门的灰度及彩色图象显示函数,甚至在调试过程中也能随时观察图形的变化; ( c) 带有丰富的图象处理函数 库,如 wavelet toolbox、 image processing toolbox 等。然而由于图象处理的针对性很强,而被处理的对象又千变万化,不可避免地在2 用 Matlab 编程时会遇到一些其自带函数无法处理的问题,只能自己编程解决。这时便会遇到运算速度慢的问题,这是因为 Matlab 是一种解释性的编程语言,对程序
6、读一句执行一句,虽然可以很方便地实现编程过程中的交互,但在执行时速度慢也根源于此,这一问题在程序做循环运算时显得尤为严重。 C是 Windows平台下主要的应用程序开发环境之一,它是一种面向对象的 可视化编程语言,广泛用于图形与图像、网络与通信以及控制等领域。能方便实现软件开发,开发的程序文件小、执行速度快、实时性好,开发的系统具有接口友好、易维护和升级等优点。它已成为操作系统、设备驱动程序和系统级平台类软件的最佳开发工具。但缺乏对大量数据处理与分析、数据可视化方面的能力。在工程计算方面,和 Matlab相比编程显得复杂的多。 如上所述, Matlab的优点在于图像处理方面,而 C的优点在于可
7、视化界面的编程。由于 C与 Matlab的各自特点,因此在 Windows环境下实现两者的混合编程将是一种极为强大的编程手 段,更加有效地发挥 C与 Matlab各自的优点, 提高软件开发效率,使所开发的软件具有更高的性能,更大的应用范围,也可以为科学研究和工程技术提供更强的技术支持。 本 文 将通过 Matlab与 C的混合编程实现 上述 数字图像处理的基本工作。 二、几种混合编程方式简介 Matlab和 C混合编程的思路:在 C的集成开发环境下使用 Matlab,可以利用 Matlab的数学库将 Matlab的程序编译为 C编译器所能识别的源代码嵌入 C的环境。也可用 C的语法在 C的环境
8、里直接编写程序。不过, Matlab的数学库在开发时似乎倾向于编译独立的可 执行程序,把 C只作为一个编译和连接的工具,而没有过多地考虑在 C的集成环境下进行开发。这给混合编程带来了很大的不便。 Matlab与 C混合编程大概有如下四种方法:( 1)利用 Matlab引擎来实现,它允许用户在用其它软件编写的应用程序中对 Matlab中的数学运算工具函数进行调用;( 2)用 Matlab的 mcc将 .m 文件翻译为 cpp 源文件,然后在 C编译器中调用,也可以用 mcc编译为 exe文件,使用 C的外部函数进行调用;( 3) 运用mex文件使 Matlab直接调用 C编写的算法 ;( 4)用
9、 Matcom将 .m 文件翻译为 cpp代码,并编译为 exe或 dll文件。 Matlab和 C的 4种混合编程方法的优缺点:( 1)利用 Matlab引擎可节省大量的系统资源,应用程序整体性能较好,能最充分地利用 Matlab的功能,但不可脱离 Matlab的环境运行, 程序没有被编译,只是解释运行所以 运行速度较慢,但在一些特别的应用 (例如需要进行三维图形显示 )时可以考虑使用;( 2)用Matlab自带的 mcc编译器将相应的 .m文件转换为 cpp代码,转换的代码可读性不太好, 不能调用 Matlab工具箱中的函数 ,且不支持图形函数,不常使用,但该方法是 Matlab自身提供的
10、,较为方便;( 3)编写mex程序可在 Matlab中实现对 C代码的调用,当程序有多个模块时,需要多次使用 mex命令,操作很麻烦;( 4)用 Matcom进行转换非常简单、方便,生成的代码可读性很好,且在 C编译器编译后其代码的执行的速度比 Matlab下平均要快 1.5倍以上,可以认为是 Matlab和 C进行混合编程最为有效的途径。 本次课题笔者主要用了第 4 种方实现了图像的大部分预处理,由于 Matcom 无法对 Matlab 函数中的 eval,feval,clear 等语句实现 C的编译,所以涉及到类似情况的处理运用了 引擎的方法,具体见下文。 ( 函数句柄演算函数 feval
11、 在 Matcom 编译中不能通过 ,导致大部分图像处理函数不能通过编译) 运行环境: Matlab6.5,Matcom4.5, Visual C+6.0, WindowsXP. 三、 Matcom 下面将详细介绍一下利用 MATCOM进行 MATLAB和 VC+混合编程,并用于图像的直方图显示与均3 衡、灰度变换、低通与高通的滤波。 1. Matcom的工作原理 Matcom实际上 是 Mideva内核的 C+编译器,它可以生成 C-MEX独立应用程序 ,是 Mideva的核心。本 文以下将二者统一写作 Matcom。 Matcom包含了一组称为 Matrix的 C+库,它是 MATHTOO
12、LS公司开发的一个矩阵数学库,提供了一个双精度 Matrix类型 Mm。 这个库提供了绝大多数的关于矩阵类、矩阵操作函数、数值计算函数、数学函数等的定义,在 Matcom中是以 lib目录下的 *.lib以及 windows/system/对应名称的 dll文件提供的。 Matcom的另一大部分就是图形部分,它是用一种非常流行的绘图 OCX控件 Teechart来实现的,这种控件对于一般的绘图功能都可以实现,但也 存在一定缺陷。在 Matcom4.5版本中使用的是 TeeChart3.0。绘图函数功能主要在 lib文件和 window/system/ago*.dll中定义的。 Matcom编译
13、 .m文件是先将 .m文件按照与 Matcom的 Cpp库的对应关系,翻译为 CPP源代码,然后用对应版本的 C编译器将该 CPP文件编译为 exe或 dll文件,所以,在第一次运行时 让指定 C Complier的路径是必需的,否则将无法编译。指定好的 C Complier的信息写在 Matcom/bin/Matcom.ini文件中。 Matcom并 不是全能的,对于大多数 Matlab函数都可以进行 CPP实现,但有些由于其功能有限,只能期待以后的版本来不断补充了。总的来说, Matcom有以下缺欠: ( 1) 对 class数据类型部分支持 ( 2) eval,feval,clear等语
14、句不能在 C中实现 (如果实现的话,一个文本编辑器就可以成为一个 Matlab了 ) ( 3) 图形窗口有些不 尽 如人意,如 fill3,hide等语句无法实现, surf等语句也无法画出象 Matlab中哪样精细的图像来,特别是色彩比较难看等等 2、混合编程的实现 ( 1)通过外壳函数调用 Matcom可将 m文件转换为 exe文件,实现一种简单的混合编程方式。具体方法是利用外壳函数WinExec()或 ShellExecute()直接调用 exe文件。本次课题主要运用了函数 WinExec(),其原型是: UINT WinExec( LPCSTR lpCmdLine, /adress o
15、f command line UINT nCmdShow /window style for new application ); 其中, lpCmdLine为包含命令行参数的字符串, nCmdShow 用来控制窗口状态,常见的如SW_SHOW,SW_SHOWMAXIMIZED和 SW_SHOWMINIMIZED等。 通过外壳函数直接调用 exe文件的方法,实现简单,且无需链接头文件和库,但一般在程序中不能接收返回值,灵活性差。 ( 2) 运用 Matrix 通过 Matcom自动地将 m文件转换为 C、 CPP文件,然后将 C、 CPP代码拷贝到 Visual C+工程中,从而实现混合编程。
16、 这种方法的重点在于调用 Matcom的 Matrix C+ 库函数之前要用 语句initM(MATCOM- VERSION)初始化类库调用 ,并在调用结束时用语句 exitM()结束对类库的调用。在 MFC工程文件中 ,一般是在一个类 (如 CDipDoc)的构造函数中添加 initM(MATCOM-VERSION)以完成类库的4 初始化工作 ,在该类的构造函数中 添加 exitM()结束对类库的调用。 下面通过本次课题来具体说明上述两种方法 a.编程环境设置 : Matcom在安装时会提示选取 c/c+编辑器 ,还需要指定 Matlab,主要是为了编译文件中需要的一些系统函数来找到路径用的
17、。 Matcom提供了 易于使用的接口,可直接通过菜单 file/compile to exe/将 m文件转换成可执行文件,同时自动生成了相应的 c/cpp文件。 为了 Visual C+借助强大的集成调试环境,以便将生成的 c/cpp代码添加到 Visual C+的工程中,必须先进行必要的 设置 。主要有以下几步: 步骤一: 添加头文件。 matlib.h是 madeva提供的函数的头文件,它位于 c:Matcom45lib目录下。方法是通过 project-setting菜单,选取 c/c+选项卡,在 category中选取 preprocessor,然后在 additional incl
18、ude directory中添加目录 c:Matcom45lib。 步骤二: 添加库文件。通过 project-add to project选取 files,然后按提示选取 c:Matcom45lib目录下的 v4501v.lib文件。 b.图像的平滑 (利用 Buterworth低通滤波器) 步骤一: 编辑 m文件如下: Buterworth低通滤波器实现 图像的平滑 程 序 如下: I1=imread(miss.bmp); figure,imshow(I1, ); f=double(I1); g=fft2(f); %傅立叶变换 g=fftshift(g); %转换数据矩阵 N1,N2=si
19、ze(g); n=2; d0=50; n1=fix(N1/2); n2=fix(N2/2); for i=1:N1 for j=1:N2 d=sqrt(i-n1)2+(j-n2)2); h=1/(1+0.414*(d/d0)(2*n); %计算 Butterworth低通转换函数 result(i,j)=h*g(i,j); end end result=ifftshift(result); 5 X2=ifft2(result); X3=uint8(real(X2); figure,imshow(X3) 步骤二: 通过 Matcom菜单 file/compile to exe将 ditong.m
20、函数转换为 exe文件,同时生成 CPP文件,打开 ditong. CPP,代码如下: dMm(I1); dMm(f); dMm(g); dMm(N1); dMm(N2); dMm(n); dMm(d0); dMm(n1); dMm(n2); dMm(i_); dMm(i_ditong_v0); dMm(j_) ; dMm(j_ditong_v1); dMm(d); dMm(h); dMm(result); dMm(X2); dMm(X3); #line 3 “c:/Matlab6p5/work/ditong.m“ call_stack_begin; #line 3 “c:/Matlab6p5
21、/work/ditong.m“ _ I1 = imread(TM(“miss.bmp“); #line 4 “c:/Matlab6p5/work/ditong.m“ _ display(figure(); #line 4 “c:/Matlab6p5/work/ditong.m“ _ imshow(CL(I1),nop_M); #line 5 “c:/Matlab6p5/work/ditong.m“ _ f = mdouble(I1); #line 6 “c:/Matlab6p5/work/ditong.m“ _ g = fft2(f); #line 7 “c:/Matlab6p5/work/d
22、itong.m“ /傅立叶变换 #line 8 “c:/Matlab6p5/work/ditong.m“ _ g = fftshift(g); #line 9 “c:/Matlab6p5/work/ditong.m“ /转换数据矩阵 #line 10 “c:/Matlab6p5/work/ditong.m“ _ /*N1,N2 = */size(g,i_o,N1,N2); #line 11 “c:/Matlab6p5/work/ditong.m“ _ n = 2.0; #line 12 “c:/Matlab6p5/work/ditong.m“ _ d0 = 50.0; #line 13 “c:/Matlab6p5/work/ditong.m“ _ n1 = fix(N1/2.0); #line 14 “c:/Matlab6p5/work/ditong.m“ _ n2 = fix(N2/2.0); #line 15 “c:/Matlab6p5/work/ditong.m“ 6 _ i_ditong_v0 = colon(1.0,1.0,N1); int i_ditong_i0; for (i_ditong_i0=0;i_ditong_i0 ( 4)在应用程序中添加调用 Matlab 引擎的程序代码: