李中科 趙慧娟 蘇曉萍
摘 要: 在計算機視覺研究領域,目前很多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.