感覺這篇比上一篇講得更清楚,尤其是有關API介面的函數
Visual C++是當前主流的應用程式開發環境之一,開發環境強大,開發的程式執行速度快。但在科學計算方面函數庫顯得不夠豐富、讀取、顯示資料圖形不方便。Matlab是一款將數值分析、矩陣計算、訊號處理和圖形顯示結合在一起,包含大量高度整合的函數可供調用,適合科學研究、工程設計等眾多學科領域使用的一種簡潔、高效的編程工具。不過由於Matlab使用的是解釋性語言,大大限制了它的執行速度和應用場合。基於VC和Matlab混合編程是很多熟悉VC++編程而又需要進行科學計算、資料模擬的科研人員常用的一種方式,其中最簡單也最直接的方法就是調用Matlab引擎。本文以下部分將詳細介紹通過VC++6.0調用Matlab6.5引擎來達到VC++與Matlab資料共用編程的方法。
1. 什麼是Matlab引擎
所謂Matlab引擎(engine),是指一組Matlab提供的介面函數,支援C/C++、Fortran等語言,通過這些介面函數,使用者可以在其它編程環境中實現對Matlab的控制。可以主要功能有:
★ 開啟/關閉一個Matlab對話;
★ 向Matlab環境發送命令字串;
★ 從Matlab環境中讀取資料;
★ 向Matlab環境中寫入資料。
與其它各種介面相比,引擎所提供的Matlab功能支援是最全面的。通過引擎方式,應用程式會開啟一個新的Matlab進程,可以控制它完成任何計算和繪圖操作。對所有的資料結構提供100%的支援。同時,引擎方式開啟的Matlab進程會在工作列顯示自己的表徵圖,開啟該視窗,可以觀察主程式通過engine方式控制Matlab啟動並執行流程,並可在其中輸入任何Matlab命令。
實際上,通過引擎方式建立的對話,是將Matlab以ActiveX控制項方式啟動的。在Matlab初次安裝時,會自動執行一次:
matlab /regserver
將自己在系統的控制項陳列庫中註冊。如果因為特殊原因,無法開啟Matlab引擎,可以在Dos命令提示字元後執行上述命令,重新註冊。
2. 配置編譯器
要在VC中成功編譯Matlab引擎程式,必須包含引擎標頭檔engine.h並引入Matlab對應的庫檔案libmx.lib、libmat.lib、libeng.lib。具體的說,開啟一個工程後,做如下設定(以VC6為例):
1) 通過菜單工程/選項,開啟設定屬性頁面,進入Directories頁面,在目錄下拉式清單方塊中選擇Include files,添加路徑:"C:/matlab/extern/include"(假定matlab安裝在C:/matlab目錄)。
2) 選擇Library files,添加路徑:C:/matlab/extern/lib/win32/microsoft/msvc60。
3) 通過菜單工程/設定,開啟工程設定屬性頁面,進入Link頁面,在Object/library modules編輯框中,添加檔案名稱libmx.lib libmat.lib libeng.lib。
以上步驟1)、2)只需設定一次,而步驟3)對每個工程都要單獨設定,對於其它C++編譯器如Borland C++ Builder,設定大體相同,不再贅述。
3. 引擎API詳解
在調用Matlab引擎之前,首先應在相關檔案中加入一行:#include "enging.h",該檔案包含了引擎API函數的說明和所需資料結構的定義。可以在VC中調用的引擎函數分別如下:
3.1 引擎的開啟和關閉
engOpen-開啟Matlab engine
函式宣告:
| Engine *engOpen(const char *startcmd); |
參數startcmd是用來啟動Matlab引擎的字串參數,在Windows作業系統中只能為NULL。
函數傳回值是一個Engine類型的指標,它是在engine.h中定義的engine資料結構。
EngClose-關閉Matlab 引擎
函式宣告:
| int engClose(Engine *ep); |
參數ep代表要被關閉的引擎指標。
函數傳回值為0表示關閉成功,返回1表示發生錯誤。
例如,通常用來開啟/關閉Matlab引擎的代碼如下:
Engine *ep; //定義Matlab引擎指標。 if (!(ep=engOpen(NULL))) //測試是否啟動Matlab引擎成功。 { MessageBox("Can't start Matlab engine!" ); exit(1); } . ………… engClose(ep); //關閉Matlab引擎。 |
3.2 向Matlab發送命令字串
engEvalString-發送命令讓Matlab執行。
函式宣告:
| int engEvalString(Engine *ep, Const char *string); |
參數ep為函數engOpen返回的引擎指標,字串string為要matlab執行的命令。
函數傳回值為0表示成功執行,返回1說明執行失敗(如命令不能被Matlab正確解釋或Matlab引擎已經關閉了)。
3.3 擷取Matlab命令視窗的輸出
要在VC中獲得函數engEvalString發送的命令字串被Matlab執行後在matlab視窗中的輸出,可以調用engOUtputBuffer函數。
函式宣告:
| int engOutputBuffer(Engine *ep, char *p, int n); |
參數ep為Matlab引擎指標,p為用來儲存輸出結構的緩衝區,n為最大儲存的字元個數,通常就是緩衝區p的大小。該函數執行後,接下來的engEvalString函數所引起的命令列輸出結果會在緩衝區p中儲存。如果要停止儲存,只需調用代碼:engOutputBuffer(ep, NULL, 0)。
3.4 讀寫Matlab資料
3.4.1從Matlab引擎工作空間中擷取變數。
| mxArray *engGetVariable(Engine *ep, const char *name); |
參數ep為開啟的Matlab引擎指標,name為以字串形式指定的數組名。
函數傳回值是指向name數組的指標,類型為mxArray*(mxArray資料類型在本文第4節詳細簡介)。
3.4.2 向Matlab引擎工作空間寫入變數。
| int engPutVariable(Engine *ep, const char *name, const mxArray *mp); |
參數ep為開啟的Matlab引擎指標,mp為指向被寫入變數的指標,name為變數寫入後在Matlab引擎工作空間中的變數名。
函數傳回值為0表示寫入變數成功,傳回值為1表示發生錯誤。
3.5 調用引擎時顯示/隱藏Matlab主視窗
預設情況下,以engine方式調用Matlab的時候,會開啟Matlab主視窗,可在其中隨意操作。但有時也會干擾應用程式的運行,可用以下設定是否顯示該視窗。
| int engSetVisible(Engine *ep, bool value); |
參數ep為開啟的Matlab引擎指標,value為是否顯示的標誌,取值true(或1)表示顯示Matlab視窗,取值false(或0)表示隱藏Matlab視窗。
函數傳回值為0表示設定成功,為1表示有錯誤發生。
要獲得當前Matlab視窗的顯示/隱藏情況,可以調用函數:
| int engGetVisible(Engine *ep, bool *value); |
參數ep為開啟的Matlab引擎指標,Value為用來儲存顯示/隱藏情況的變數(採用指標方式傳遞)。
函數傳回值為0表示擷取成功,為1表示有錯誤發生。
4. 資料類型mxArray的操作
在上節的Matlab引擎函數中,所有與變數有關的資料類型都是mxArray類型。資料結構mxArray以及大量的mx開頭的函數,廣泛用於Matlab 引擎程式和Matlab C數學庫中。mxArray是一種很複雜的資料結構,與Matlab中的array相對應,我們只需熟悉Matlab的array類型和幾個常用的mxArray函數即可。
在VC中,所有和Matlab的資料互動都是通過mxArray來實現的,在使用mxArray類型的程式中,應包含標頭檔matrix.h,不過在引擎程式中,一般會包含標頭檔engine.h,該檔案裡面已經包含了matrix.h,因此無需重複包含。
4.1 建立和清除mxArray型資料
Matlab有很多種變數類型,對應於每種類型,基本上都有一個函數用於建立,但它們都有相同的資料結構,就是mxArray。
數組的建立採用mxCreatexxx形式的函數,例如建立一個double類型數組,可用函數mxCreateDoubleMatrix,函數形式如下:
| mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag); |
參數m和n為矩陣的函數和列數。ComplexFlag為常數,用來區分矩陣中元素是實數還是複數,取值分別為mxREAL和mxCOMPLEX。
例如,建立一個3行5列的二維實數數組,可用如下語句:
| mxArray *T = mxCreateDoubleMatrix(3, 5, mxREAL); |
對應的,要刪除一個數組mxDestroyArray,該函式宣告如下:
| void mxDestroyArray(mxArray *array_ptr); |
參數array_ptr為要刪除的數組指標。
例如,要刪除上面建立的數組T,可用如下語句:
類似的建立函數還有:
| mxArray *mxCreateString(const char *str); |
建立一個字串類型並初始化為str字串。
一般的在VC與Matlab互動中,以上兩種類型就夠了,其它類型數組的建立這裡不再介紹。
4.2 管理mxArray資料類型
4.2.1 管理mxArray資料大小
要獲得mxArray數組每一維上元素的個數,可以用mxGetM和mxGetN函數。其中mxGetM用來獲得數組第一維的元素個數,對於矩陣來說就是行數。
int mxGetM(const mxArray *array_ptr); //返回array_ptr對應數組第一維的元素個數(行數) int mxGetN(const mxArray *array_ptr); //返回array_ptr對應數組其它維的元素個數,對於矩陣來說是列數。對於多維陣列來說是從第2維到最後一維的各維元素個數的乘積。 |
要獲得某一特定維的元素個數,則要用函數:
| const int *mxGetDimensions(const mxArray *array_ptr); |
該函數返回array_ptr各維的元素個數儲存在一個int數組中返回。對於常用的矩陣來說,用mxGetM和mxGetN兩個函數就可以了。
另外還可以通過mxGetNumberOfDimensions來獲得數組的總的維數,用mxSetM、mxSetN設定矩陣的行數和列數,函數說明如下:
mxGetNumberOfDimensions(const mxArray *array_ptr); //返回數組的維數
void mxSetM(mxArray *array_ptr, int m); //設定數組為m行
void mxSetN(mxArray *array_ptr, int n); //設定數組為n列
4.2.2 判斷mxArray數群組類型
在對mxArray類型的變數進行操作之前,可以驗證以下其中的數組的資料類型,比如是否為double數組、整數、字串、邏輯值等,以及是否為某種結構、類、或者是特殊類型,比如是否為空白數組,是否為inf、NaN等。常見的判斷函數有:
bool mxIsDouble(const mxArray *array_ptr); bool mxIsComplex(const mxArray *array_ptr); bool mxIsChar(const mxArray *array_ptr); bool mxIsEmpty(const mxArray *array_ptr); bool mxIsInf(double value); …… …… |
這些函數比較簡單,意義自明,不再解釋。
4.2.3 管理mxArray數組的資料
對於常用的double類型的數組,可以用mxGetPr和mxGetPi兩個函數分別獲得其實部和虛部的資料指標,這兩個函數的聲明如下:
double *mxGetPr(const mxArray *array_ptr); //返回數組array_ptr的實部指標 double *mxGetPi(const mxArray *array_ptr); //返回數組array_ptr的虛部指標 |
這樣,就可以通過獲得的指標對mxArray類型的數組中的資料進行讀寫操作。例如可以用函數engGetVariable從Matlab工作空間讀入mxArray類型的數組,然後用mxGetPr和mxGetPi獲得資料指標,對並其中的資料進行處理,最後調用engPutVariable函數將修改後的數組重新寫入到Matlab工作空間。具體實現見第5節程式執行個體。
5. 程式執行個體
對大部分軟體研發人員來說利用VC編程方便、高效,但是要顯示資料圖形就不那麼容易了,這時候不防藉助Matlab引擎輔助畫圖做資料分析。下面通過執行個體示範如何利用VC調用Matlab繪圖,程式的主要功能是在VC中對數組x計算函數值y=sin(x) ±log(x),然後調用Matlab繪製y對x的圖形。
在VC中建立工程,編寫代碼如下:
#include <iostream> #include <math.h> #include "engine.h" using namespace std; void main() { const int N = 50; double x[N],y[N]; int j = 1; for (int i=0; i<N; i++) //計算數組x和y { x[i] = (i+1); y[i] = sin(x[i]) + j * log(x[i]); //產生-之間的隨機數賦給xx[i]; j *= -1; } Engine *ep; //定義Matlab引擎指標。 if (!(ep=engOpen(NULL))) //測試是否啟動Matlab引擎成功。 { cout <<"Can't start Matlab engine!" <<endl; exit(1); } //定義mxArray,為行,N列的實數數組。 mxArray *xx = mxCreateDoubleMatrix(1,N, mxREAL); mxArray *yy = mxCreateDoubleMatrix(1,N, mxREAL); //同上。 memcpy(mxGetPr(xx), x, N*sizeof(double)); //將數組x複製到mxarray數組xx中。 memcpy(mxGetPr(yy), y, N*sizeof(double)); //將數組x複製到mxarray數組yy中。 engPutVariable(ep, "xx",xx); //將mxArray數組xx寫入到Matlab工作空間,命名為xx。 engPutVariable(ep, "yy",yy); //將mxArray數組yy寫入到Matlab工作空間,命名為yy。 //向Matlab引擎發送畫圖命令。plot為Matlab的畫圖函數,參見Matlab相關文檔。 engEvalString(ep, "plot(xx, yy); "); mxDestroyArray(xx); //銷毀mxArray數組xx和yy。 mxDestroyArray(yy); cout <<"Press any key to exit!" <<endl; cin.get(); engClose(ep); //關閉Matlab引擎。 } |
6. 小結
本文詳細的介紹了Matlab引擎使用方法並示範了一個簡單的利用VC調用Matlab畫圖的程式執行個體。大多數時候,程式員可以利用Matlab強大的資料讀寫、顯示能力和VC編程的高效率。例如,在Matlab中要讀入一幅任意格式的映像均只需一條命令i=imread('test.jp');映像資料矩陣便存放在了二維數組i中,可以通過VC讀入該數組進行相關處理再調用Matlab顯示,這種混合編程方式能大大提高工作效率。
當然,利用VC編譯的Matlab引擎程式,運行環境中還必須Matlab的支援,如果要編譯完全脫離Matlab的程式,可採用其它方式,如利用第三方Matcom程式編譯獨立的可執行程式等
From:http://hi.baidu.com/kenter83/blog/item/153275d9b1ef88ef3b012f60.html