VC++如何利用Matlab的圖形引擎
在Visual C++ 2015 工程中使用 Matlab2014b 提供的圖形引擎進行繪圖的詳細過程。
問題來源:
有時候用C++寫一些演示程序,有數據可視化的需求。一般來講,在Window下無非這么幾種解決方案:用MFC,QT之類的框架,用GDI之類的系統API,用DirectX API或者Open GL。非主流一點的把數據寫成Json寫成私有格式,然后前端技術BlahBlah之類的玩意以網頁的方式可視化。當然也可以用一些別的軟件提供的API,比如,Matlab。
為啥有這個需求呢?首先上面那些亂七八糟的東西,用來做可視化演示都不能叫重復造輪子了,簡直就是在種橡膠樹。如果你看過MSDN上用DirectX2D畫長方形的演示,就會知道什么叫蛋疼了,到處充斥着細節,如果只是用來做個算法演示,模擬之類的東西真是殺雞用牛刀,蛋疼無比。Matlab的高級圖形引擎早就提供了一整套完整的解決方案,不用真是太可惜了。尤其是Matlab2014b里面,圖形引擎換過了,畫出來的圖比以前漂亮多了。用來做Demo簡直不能更方便。
新版圖形引擎的效果:
前期准備:
我的測試環境是: Window Technical Preview(Win10) + Visual Studio 2015 Preview + Matab 2014 64位; 當然其實Win8+VS2013的組合肯定也可以。
我猜大多數試過的這種繪圖方式的人,都層掉進過平台,編譯、裝載、鏈接的大坑里。因此在此分享掉坑經驗,以便他人少走彎路。
原理:
用C++調用Matlab圖形引擎,主要是利用COM組件服務。將Matlab作為COM Server,接受Client應用程序的請求。Matlab的m腳本是一種解釋性語言,因此大多數調用都是直接通過傳遞命令字符串的eval方法實現的。那么具體流程呢,就是用戶的C++ 程序,Include了Matlab提供的頭文件engine.h;參考了Matlab提供的靜態庫文件libeng.lib,libmx.lib;引用了Matlab提供的動態鏈接庫文件(位於…..\MATLAB\R2014b\bin\win64中的一大票Dll文件)。頭文件,靜態庫文件,動態鏈接庫文件是什么,這個就不科普了。推薦《程序員的自我修養》。
具體過程:
廢話不多說,讓我們來試一試吧,先把測試用的代碼貼出來好了。
1 #include<cstdlib> 2 #include <cstdio> 3 #include<cstring> 4 #include"engine.h" 5 6 const int BUFFER_SIZE = 1024; 7 char buffer[BUFFER_SIZE]; 8 9 void test() 10 { 11 Engine* ep; 12 mxArray *x1 = NULL; 13 mxArray *y1 = NULL; 14 if ((ep = engOpen("")) == NULL) 15 { 16 printf("Engine Fail"); 17 } 18 engOutputBuffer(ep, buffer, BUFFER_SIZE); 19 printf("Init Success"); 20 21 double x[5] = { 1.0, 2.5,3.7,4.4,5.1 }; 22 double y[5] = { 3.3,4.7,9.6,15.6,21.3 }; 23 x1 = mxCreateDoubleMatrix(1, 5, mxREAL); 24 y1 = mxCreateDoubleMatrix(1, 5, mxREAL); 25 26 memcpy((void *)mxGetPr(x1), (void *)x, sizeof(x)); 27 memcpy((void *)mxGetPr(y1), (void *)y, sizeof(y)); 28 29 engPutVariable(ep, "x", x1); 30 engPutVariable(ep, "y", y1); 31 32 engEvalString(ep, "plot(x,y)"); 33 getchar(); 34 engClose(ep); 35 } 36 37 int main() 38 { 39 test(); 40 }
但是不要急,直接復制黏貼進一個新項目直接Build是鐵定Fail的。實際上項目屬性的配置,要比單純寫代碼麻煩多了。
第一步:
確認你的Matlab版本,是64位還是32位的。32位不用改,不過一般Matlab裝的都是64位的吧?那么,就在Build – Configuration Manager中建立一個新的配置文件:Active Solution Paltform活動平台記得選擇x64,下面選擇復制自Win32不用管它。

這一步是一個大坑,因為絕大多數Visual C++程序都是以32位平台作為目標編譯的,所以如果有32位平台相關的代碼,Build就會尿掉。所以注意一下自己用到的庫吧,如果你知道自己在做什么那是最好了。
第二步:
設置VC++目錄。在解決方案管理器中選中當前的項目,點右鍵菜單-屬性,或者直接Alt+Enter打開屬性面板。總之選中VC++ 目錄,右邊就會出來一大堆要你填的東西。要關注的東西有三個:第一個 可執行程序目錄,第二個 包含目錄, 第四個,庫目錄。這三個東西分別對應dll文件的位置,頭文件的位置,lib文件的位置。

具體位置呢,可以看圖中,我的Matlab是安裝到默認位置的,安裝到別的位置可以改一下前綴。這些目錄地址就是告訴編譯器和鏈接器到哪兒去找要用的東西。
C:\Program Files\MATLAB\R2014b\bin\win64;
C:\Program Files\MATLAB\R2014b\extern\include;
C:\Program Files\MATLAB\R2014b\extern\lib\win64\microsoft;
看名字就知道了,bin,include,lib。
第三步:
C++還有個壞毛病,你得手動告訴鏈接器我用了哪些庫文件。上面填庫目錄那里只是告訴鏈接器,如果需要庫文件,你來這些地方找一找。不過鏈接器確實還需要知道你用的庫的名字。這里Matlab繪圖需要用到兩個庫: libeng.lib和libmx.lib。一個是Matlab引擎,一個是Matlab的矩陣庫。怎么弄呢?在項目屬性中選擇Linker(鏈接器) -> Input 在右邊的額外依賴項中加上兩個:libeng.lib , libmx.lib就可以了。

第四步
基本上改了平台,填了目錄,填了庫名,就可以萬事大吉了。但是有時候往往還是會有各種破事,比如提示libeng.dll找不到啊之類的。這時候呢,可以通過修改環境變量的方式來解決這個問題。C:\Program Files\MATLAB\R2014b\bin\win64; 把原來可執行程序的目錄加入到系統的PATH環境變量中,然后記得重啟。。。。就可以解決問題了。
第五步
配置問題到此已經解決了,現在終於可以試試身手了。在項目中新建一個cpp文件,把代碼復制進去。Run一下看看?Matlab的C引擎API非常簡單。數來數去就是那么幾個方法,都以eng開頭:
engOpen, engClose一看就知道干嘛用的。engPutVariable, engGetVariable是用來存取工作區的變量的。然后就是萬能的engEvalString。參數就是一個Engine指針和命令字 符串。就跟在Matlab里面敲的命令一樣。
然后如果需要用Get/Put Variable,需要用到矩陣庫libmx.lib中的內容,就是創建一個double數組,創建一個mxArray對象,一看就能明白的東西是吧,詳細的內容Matlab的Doc里都有,就不贅述了。

噢吼吼,是不是很棒啊。雖然只是很簡單的效果。不過用好了卻是妙用無窮啊,可以自己寫個類包裝一下方便以后使用。
另外呢,還有一個小技巧。每次運行你的小程序的時候吧,總是會開一個新的Matlab COM server實例。冷啟動得快十秒,熱啟動也要好幾秒。真是慢的可以。有一個解決方案呢,就是啟動一個Matlab Automation Server。這樣每次運行程序時,它就會主動鏈接到這個手動啟動的實例上請求服務而不是自己搞出個新的出來了,會快很多。
怎么做呢?很簡單,啟動Matlab,加個命令行參數/Automation。在CMD或者Powershell中輸入matlab /Automation 就行了。
大概就是這樣。
