基于OpenCV的C/C++和Matlab计算机视觉混合编程
2018-09-17李中科赵慧娟苏晓萍
李中科 赵慧娟 苏晓萍
摘 要: 在计算机视觉研究领域,目前很多Matlab开源代码会调用依赖于OpenCV采用C/C++语言编写编译生成的动态链接库。但因运行环境的差异, 这些代码的运行往往需要重新编译生成新的动态链接库。由于涉及Matlab和Visual Studio两个工具混合编程,同时还有对OpenCV库函数的依赖,重新编译相关的设置会给初学者带来很大的困扰。本文以具体实例给出几者混合编程和调试的步骤及注意事项,以期给初学者一个可操作的混合编程入门指导,使他们可以轻松实现混合编程,将更多的精力投入到实际问题的解决中,以提高研究工作的效率。
关键词: OpenCV; C/C++; Matlab; 混合编程; MEX; Visual Studio; 计算机视觉
中图分类号:TP391.41 文献标志码:A 文章编号:1006-8228(2018)07-69-04
Abstract: In the field of computer vision research, many researchers will open their Matlab source code, which calls dynamic link libraries written in the C/C++ language. A lot of these dynamic link libraries often are based on OpenCV. In most cases, the running environments of downloader's are different from the researchers', these C/C++ dynamic link libraries require recompiling to make it runnable on the downloader's running environments. Because the mixed programming involves two tools Matlab and Visual Studio, and dependents on OpenCV, the task of re-compilation generally causes great difficulties for beginners. This article takes an example to describe the steps and issues on the mixed programming, expecting to give the beginners an operational entry guide, so that they can devote themselves to research the problem itself.
Key words: OpenCV; C/C++; Matlab; mixed programming; MEX; Visual Studio; computer vision
0 引言
Matlab是目前世界上最强大的算法研究工具之一,可应用于众多科学计算及仿真领域,其强大的功能为众多的科学工作者提供了方便快捷的处理方式,由于其实现方法简单,编程速度快,故常被用于需要快速验证的算法研究、探索中。特别是Matlab以其在矩阵运算方面独有的优势在图像处理领域应用颇广[1]。但相比较C/C++,由于其是解释执行,对循环等操作执行效率很低,即便是研究探索中,特别是当其被用到诸如计算机视觉、视频处理等计算机量较大的领域时,就需要考虑执行效率的问题,否则程序的执行时间将不可接受[2-3]。
除Matlab外,对图像、视频技术研究者来说,开源的OpenCV也是广泛被认同的开源图像及视觉软件包之一[4],由于其开源软件的特性,任何开发人员都可以利用它来开发自己的图像或者视觉应用,其基于C++开发。OpenCV库有很多现成的库函数可供使用,方便快捷,更便于编写可商业化的软件。在基于C/C++的计算机视觉软件经常会调用OpenCV的库函数。
基于上面的事实,很多研究机构所公开的计算机视觉相关代码,往往是使用Matlab和C/C++混合编程,他们一般在涉及循环等计算量较大的功能模块使用C/C++编写,编译成动态链接库形式供Matlab调用。同时在C/C++程序编写的功能模块中往往会调用OpenCV的库函数。现实中, 这种Matlab和调用了OpenCV库函数的C/C++混合编程的情况十分常见, 同时由于各研究结构的软件运行环境(硬件,操作系统等)、编译环境等差异,要此类的开源代码真正能在本地执行,往往需要下载者根据本地的软硬件情况对原代码作适当修改和编译。因为涉及几个工具、引用库之间协作编译和调试,重新编译相关的设置工作往往会对初学者造成很大的困扰。互联网上的一些相关介绍很多并不能解决问题[5]。笔者本人在从事该领域研究之初也是花费了大量的精力,经历了很多的困惑和陷阱,才掌握了此类混合编程的方法,所以笔者将相关的经验整理成该文,以便于后来者在这个问题上少走弯路。
本文结合一个具体的图像处理相关的应用实例来描述整个设置和编译过程,该实例中Matlab程序会调用由Visual Studio 2012(下文中简称VS2012)编译生成的动态链接庫(mex文件,对64位系统就是“mexw64”类型的文件),将彩色图像转换为灰度图像,而动态链接库采用C/C++ 编写,其调用了OpenCV库函数来实现由彩色到灰度的转换。具体内容包括:
⑴ 编写一个C/C++程序实现彩色图像转为灰度图像,使用Visual Studio 2012将其编译成动态链接库(mexw64类型文件),供Matlab2015b中的程序(m类型文件)调用,该C/C++程序中引用OpenCV库函数;
⑵ Matlab调用编译好的动态链接库(mexw64类型文件),并结合Visual Studio 2012执行mexw64文件的调试。
本文涉及到的软件如下:Visual Studio 2012,Matlab R2015b,OpenCV-2.4.12。运行环境为:Windows 10(64位操作系统、基于x64处理器)
1 C++文件创建及编译
MEX是一种C/C++语言或Fortran语言的衍生程序,在Matlab中能够对其调用。用C/C++语言或Fortran语言编写出MEX 源文件, 之后经过Matlab自身的编译器或其他外部编译器进行编译,从而生成二进制文件(MEX类型文件),其属于动态连接程序的一种,Matlab解释器可以自动装载和执行此文件。MEX类型文件有着使用便利的特点,在Matlab中调用MEX类型文件的方式与内建函数一致,只需要将MEX文件名键入Matlab 命令提示符之下或直接在matlab文件中调用即可。
为了将C/C++ MEX源文件编译成MEX类型文件,可以使用Matlab自带的编译程序mex来编译,也可以使用外部编译器来编译。本文中我们直接在VS2012中将C/C++ MEX文件编译生成动态链接库MEX类型文件。
1.1 C/C++ Mex文件的创建
一般来说,一个C/C++ MEX源文件有两个组成部分[6]:第一,要有#include“mex.h”,该头文件包含所有MEX函数的原型声明;第二,mexFunction,即MEX源文件的入口函数。因為需要调用OpenCV的库函数,本示例中还需要引用包含OpenCV的头文件(opencv2/opencv.hpp),将该C/C++ MEX源文件命名为main.cpp,该文件内容如表1所示。
1.2 mex文件的编译
先在VS2012中新建一个win32 dll空项目, 本文以项目名RGBToGray为例。然后将上节中的main.cpp加入到该项目中。接着创建一个模块定义文件RGBToGray.def(名字任意), RGBToGray.def文件程序清单如下:
EXPORTS mexFunction;
然后打开项目属性页逐条配置属性。
⑴ C/C++ ->常规,在“附加包含目录”中加入Matlab安装目录下的\extern\include子路径和OpenCV安装目录下的\build\include子路径,以笔者本地运行环境为例,相关路径为:
D:\Program Files\MATLAB\R2015b\extern\include;
D:\opencv-2.4.12\opencv\build\include;
⑵ 链接器->常规,在“附加库目录“中 加入MATLAB安装目录下的\extern\lib\win64\ microsoft子路径和openCV安装目录下的\build\x64\vc11\lib子路径(X64指64位机,X86指32位机,vc11指VS2012)。以笔者本地运行环境为例,相关路径为:
D:\opencv-2.4.12\opencv\build\x64\vc11\lib;
D:\Program Files\MATLAB\R2015b\extern\lib\win64\microsoft
⑶ 链接器->输入,在“附加依赖项”中输入Matlab的四个lib文件(libmx.lib libeng.lib libmat.lib libmex.lib)和Matlab的lib文件(如果不能确认某几个lib文件,就将OpenCV安装目录下\build\x64\vc11\lib子目录中的所有lib文件)。
⑷ 常规,在“目标文件扩展名”中将扩展名由“.dll”改成“.mexw64”(32位系统相应改成“.mexw64”)。
⑸ 链接器->输入,将“模块定义文件”修改为RGBToGray.def。
接下来如果是64位系统还需要修改管理器,点击如图1所示中的“配置管理器…”:
进入配置管理器窗口,新建“活动解决方案平台” (如图2所示),在“键入或选择新平台中”选择“x64”。
至此,本win32 dll项目的属性配置完成。可以通过Visual Studio 2012的“生成(B)”菜单的“生成解决方案(B)” 编译生成mex文件(64位系统为“.mexw64”类型,32位系统为“.mexw32”类型)。以笔者本地编译环境为例,编译后可以在VC项目目录下的\x64\Debug子目录下找到以项目名称命名的RGBToGray.mexw64文件(即编译生成的MEX类型文件)。
2 MEX类型文件执行和联合调试
2.1 在Matlab中调用MEX类型文件
启动Matlab R2015b,将上节编译生成的RGBToGray.mexw64文件拷贝到Matlab调用代码所能及的目录下,或者通过Matlab的pathtool命令将VC项目存放RGBToGray.mexw64文件的子目录(VC项目目录下的\x64\Debug)增加到Matlab工作路径中。同时,还需要将OpenCV所有lib对应的dll文件 (在OPENCV安装目录下的\opencv\build\ x64\vc11\bin子目录)全拷贝到RGBToGray.mexw64文件所在的目录,或将OPENCV安装目录下的\opencv\build\x64\vc11\bin子目录添加到系统环境变量Path中,以便操作系统运行时可以找到相关的dll文件;否则,在Matlab程序中直接调用RGBToGray.mexw64会有问题(报“Invalid MEX-file 找不到指定的模块”的错误),原因是Matlab无法找到OpenCV的dll文件。
在Matlab中编写调用上述MEX类型文件的m类型文件,这里,将文件命名为test.m,其代码清单如下:
img=RGBToGray('ABC.jpg');
imshow(uint8(img));
其中RGBToGray函数的入参为任意彩色图片(代码中以'ABC.jpg'为例)。
此时在Matlab R2015b的命令窗口中输入上述m类型文件的名字“test”, 就可以将入参中指定的图片由彩色转化为灰色图片并显示出来。
2.2 Matlab和VS2012联调C/C++程序
由于C/C++程序编译生成的MEX类型文件是在Matlab程序中被调用,如果需要调试C/C++程序,则需要Matlab和VS协作调试。以本文示例的VS2012的 RGBToGray工程和Matlab程序test.m为例给出配置步骤。
⑴ 打开Matlab程序,将VS的编译目标目录(VS编译目标mexw64文件所在的Debug目录)添加到Matlab的工作路径中(可以通过上节讲到的Matlab pathtool工具添加)。
⑵ 在確保Matlab进程启动的前提下,在VS2012中的“工具”菜单的“添加到进程”进入“添加到进程“窗口,在“可用进程”列表中选择“MATLAB.exe”。
⑶ 源代码RGBToGray.cpp里设置有效断点。
⑷ 在matlab的命令行中输入test,启动test.m测试程序,待matlab程序运行到RGBToGray调用时,VS2012会在RGBToGray.cpp文件设置的有效断点处断住,然后可以在VS2012中执行单步调试。
注意,在每次修改MexFunction所在的RGBToGray.cpp文件后,重新编译生成解决方案前, 都需要先在Matlab命令行中清理RGBToGray.mexw64,命令如下:
clear RGBToGray.mexw64
否则,因Matlab在调用MEX函数后一直占用不释放,VS2012将无法成功生成解决方案。
同时,对每次重新编译生成的RGBToGray.mexw64,都需要重新执行步骤2才可以联合调试对应的C/C++程序。
3 结束语
本文结合一个将彩色图像转换为灰度图像的具体应用,给出一个基于OpenCV的C/C++ MEX源文件和Matlab混合编程的示例,详细描述了混合编程中相关的编译配置、调试步骤和注意事项,为初学者提供了一个可操作的混合编程入门指导, 使他们不必在混合编程的探索上花费过多精力。相似的编程任务,读者可将其分解为由Matlab编写的调用代码部分以及由C/C++编写的动态链接库部分(也即MEX源文件),参照文中介绍的配置和调试框架,快速实现相关的混合编程;对网上下载的需要重新编译才能运行的混合编程开源代码,读者可将其中依赖OpenCV的C/C++ MEX源文件部分按照文中介绍的内容重新编译生成MEX类型文件。
参考文献(References):
[1] 刘浩,韩晶.Matlab R2014a完全自学一本通[M].电子工业出版社,2015.
[2] 潘大夫,汪渤,周志强.Matlab与C/C++混合编程技术研究[J].计算机工程与设计,2009.30(2):465-468
[3] showlo, Matlab与C/C++混合编程、Visual C++与Matlab封装库互相调用相关要点[EB/OL],2017.https://zhuanlan.zhihu.com/p/25257137
[4] Bradski, Gary, and A. Kaehler. Learning OpenCV:Computer Vision with the OpenCV Library, ISBN 978-0-596-51613-0,2008.
[5] zouxy09@qq.com,Matlab与C++混合编程(依赖OpenCV)[EB/OL].2014.http://blog.csdn.net/zouxy09/article/details/20553007
[6] 刘维.精通Matlab与C/C++混合程序设计(第三版)[M].北京航空航天大学出版社,2012.