首頁 > 軟體

C++的matlab介面轉換方法詳解

2022-03-30 13:00:37

由於matlab的運算速度較慢,因此常常需要使用c++對關鍵部分進行運算。Matlab針對這一需求提供了相應的api方便引數傳遞以及封裝。

這裡使用的vs工程,對檔案進行修改生成.mexw64檔案,對於matlab可識別的檔案。

這裡的操作都是針對vs進行設定和操作。

一.工程設定

1.設定生成檔案

右鍵->屬性->常規->設定型別 動態庫(.dll)

右鍵->屬性->高階->目標副檔名 .mexw64

2.設定附加目錄

右鍵->屬性->c++->附加包含目錄  新增$(Matlab_Dir)externinclude; 

其中$(Matlab_Dir)為matlab安裝地址

右鍵->屬性->連結器->附加庫目錄 新增$(Matlab_Dir)externlibwin64microsoft;;

其中$(Matlab_Dir)為matlab安裝地址

3.新增附加依賴項

右鍵->屬性->連結器->輸入->附加依賴項

輸入libmx.lib;libmex.lib;libmat.lib;libeng.lib;

二.介面編寫

1.新增標頭檔案

#include "mex.h"是matlab提供的標頭檔案,利用提供的api進行介面函數編寫

2.介面函數編寫

入口過程的名稱必須是mexFunction,並且包含四個引數

void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]);

nlhs 輸出引數個數,plhs 輸出引數指標 

nrhs 輸入引數個數,prhs 輸入引數指標 

注意: 輸出和輸入引數的操作都是通過指標的方式進行的MATLAB可以通過這些指標,存取記憶體中的資料

3.輸入引數獲取

介面過程要把引數傳遞給計算過程,還需要從prhs中讀出矩陣的資訊,這就要用到下面的mx-函數和mex-函數。

  • mxGetM(prhs[0]); 獲取其行數
  • mxGetN(prhs[0]); 獲取其列數
  • mxGetNumberOfDimensions(prhs[0]);獲取其維度

主要介紹的是資料獲取的兩個函數 mxGetData 和 mxGetPr。

mxGetData返回值為void型別的指標,必須轉換為正確資料型別的指標的指標。

mxGetPr返回值為double型別的指標,可以理解為它會自動轉換 mxGetData的輸出作為double指標。

在使用上這兩種都可以獲取引數內容。

還有一點需要注意的是,無法對未獲取的值進行操作。

下面的程式碼在偵錯時會報錯,無法對於未儲存的變數進行操作。

Number = ((double*)mxGetData(mxGetCell(prhs[0], 19)))[0]-1;

4.出錯資訊釋出函數mexErrMsgTxt,mexWarnMsgTxt

兩函數的具體格式如下:

#include "mex.h"

void mexErrMsgTxt(const char *error_msg);

void mexWarnMsgTxt(const char *warning_msg);

其中error_msg包含了要顯示錯誤資訊,warning_msg包含要顯示的警告資訊。兩函數的區別在於mexErrMsgTxt顯示出錯資訊後即返回到MATLAB,而mexWarnMsgTxt顯示警告資訊後繼續執行。

5.輸出引數設定

對於程式的返回結果需要將其儲存在plhs指標當中,而且儲存在plhs的返回指標型別必須是mxArray。

這裡介紹兩個api進行陣列,矩陣的建立。由於常用的資料型別為double,這裡列舉的均為double型別的陣列。

plhs[0] = mxCreateNumericArray(3, dims,mxDOUBLE_CLASS, mxREAL);
plhs[1] = mxCreateDoubleMatrix(n, n, mxREAL);    

6.引數轉置

由於matlab的資料儲存順序與c++不同,因此在資料輸入時需要對資料進行轉換。在資料輸出傳遞的時候,同樣也需要對陣列進行轉換。

matlab對於陣列儲存是按照列進行儲存的,而c++是按照行進行儲存,因此在資料計算時需要格外注意。

這裡是常用的行列轉換的程式碼。

template <class T1, class T2>
void cTranspose3d(T1* dst, T2* src, int srcRow, int srcCol, int channel)
{
	int i = 0, k = 0;
	T1* dst1 = NULL;
	T2* src1 = NULL;
	for (k = 0; k < channel; k++)
	{
		dst1 = dst + k * srcRow * srcCol;
		src1 = src + k * srcRow * srcCol;
		for (i = 0; i < srcRow * srcCol; i++)
		{
			dst1[i] = src1[(i % srcRow) * srcCol + (i / srcRow)];//th/ srcRow//src's  col -> dst's row,th%srcRow//src's   row -> dst's col
		}
	}
}

總結

至此整個介面書寫就結束了。該篇教學也是記錄一下自己整個學習過程,希望能夠看的人一點點幫助。


IT145.com E-mail:sddin#qq.com