由于實驗室項目遺留問題,可能為了圖matlab繪圖友善,前面的開發人員在C++核心代碼外加了一層matlab外殼,在matlab裡調用C++方法,并使用matlab繪圖顯示。當我接手這份代碼之後,在Windows上調試發現了幾個難以忍受的問題,
1. matlab調用之前必須将c++代碼編譯成二進制檔案,如此一來在matlab裡就沒法調試,不得不使用Visual Studio的附加程序調試,需要頻繁來回切換VS和maltab;
2. 使用附加程序調試時如果C++程式崩潰,導緻matlab必須重新開機,而matlab重新開機速度之慢無法忍;
3. 全速運作起來速度之慢無法忍。
綜上所述,決定将代碼全部移植到C++下。綜合考慮,移植到C++下,可能存在以下兩個問題:圖像讀取與轉換和計算結果可視化。
圖像加載與轉換
項目是有關圖像處理的,matlab提供非常便捷的圖像轉換和處理庫,在C++下沒有這些API,也不可能自己從頭實作這些基礎功能,自然而然選擇了OpenCV這樣的第三方庫。
- 下載下傳OpenCV2.4.9 for Windows,解壓到OPENCV_ROOT(自定義路徑);
- 在VS2012裡指定頭檔案路徑為:
;庫檔案路徑:OPENCV_ROOT/build/include
;OPENCV_ROOT/build/x64/vc11/lib
- 從
拷貝OPENCV_ROOT/build/x64/vc11/bin
,opencv_core249d.dll
,opencv_core249.dll
和opencv_highgui249d.dll
到VS工程目錄(工程為x64,x86工程);opencv_highgui249.dll
- 在代碼中添加如下代碼表明用到的庫檔案
#ifdef _DUBUG #pragma comment(lib, "opencv_core249d.lib") #pragma comment(lib, "opencv_highgui249d.lib") #else #pragma comment(lib, "opencv_core249.lib") #pragma comment(lib, "opencv_highgui249.lib") #endif
- 加載和顯示圖像
#include <opencv2\highgui\highgui.hpp> int main(void){ cv::Mat img = cv::imread("test_image.jpg", CV_LOAD_IMAGE_GRAYSCALE); cv::namedWindow("imageWindow"); cv::imshow("imageWindow", img); cv::destroyWindow("imageWindow"); return ; }
可視化
項目最終有可視化的需求,而用C++做可視化成本太高,MATLAB在這方面獨特的優勢。在調試階段應該使用盡可能友善的方法驗證算法,于是決定在C++中調用MATLAB引擎繪圖。MATLAB引擎函數庫是MATLAB提供引擎方式接口的一系列程式的集合,它允許使用者用自己的C/C++語言或FORTRAN語言應用程式中對MATLAB進行調用。
engine.h
頭檔案中定義了9個引擎函數。在VS2012裡調用MATLAB引擎操作方式如下:
- 建立和MATLAB版本一緻的C++工程,如,我的MATLAB是x64的,就建立x64的C++工程,這樣才能保證調用的動态庫版本正确;
- 在VS2012中添加MATLAB的頭檔案路徑,如:
;添加庫檔案路徑,如:C:\Program Files\MATLAB\R2014a\extern\include
,添加可執行檔案路徑,如:C:\Program Files\MATLAB\R2014a\extern\lib\win64\microsoft
;C:\Program Files\MATLAB\R2014a\bin\win64
- 在代碼中調用MATLAB引擎函數,為了使用友善,我對部分引擎函數做了一些封裝,如下:
4.在main函數中執行個體化引擎類并調用引擎方法:/* * MatlabEngine.h * this file is a C++ wrap of some MATLAB engine methods. * it depends on the MATLAB installed on you machine. * DATE: 2016.05.15 * AUTHOR: Lai Shaofa * EMAIL: [email protected] */ # ifndef _MATLAB_ENGINE_H_ # define _MATLAB_ENGINE_H_ #include <stdio.h> #include "engine.h" #pragma comment(lib, "libeng.lib") #pragma comment(lib, "libmx.lib") #define MAX_BUFFFER_SIZE (1024) class MatlabEngine { private: Engine *ep; char buffer[MAX_BUFFFER_SIZE]; public: /* * constructor: open matlab engine and set engine input/output buffer */ MatlabEngine(){ if ((ep = engOpen("")) == NULL) { fprintf(stderr, "\nCan't start MATLAB engine\n"); exit(); } engOutputBuffer(ep, buffer, MAX_BUFFFER_SIZE); } /* * destructor: close matlab engine */ ~MatlabEngine() { engClose(ep); } /* * matCreate: create a matrix * @row: row of matrix * @col: column of matrix * NOTE: remember to call @matDestory to avoid memory leak */ mxArray* matCreate(const int32_t row, const int32_t col) { assert(row> && col>); return mxCreateDoubleMatrix(row, col, mxREAL); } /* * @matDestroy: destroy a matrix to release memory * @mat: matrix to be destroyed. */ void matDestroy(mxArray* mat) { assert(mat!=NULL); mxDestroyArray(mat); mat = NULL; } /* * matPutVariable: put a variable to matlab engine with the name @matName * @matName: name of variable,it used by matlab engine to identify the @mat * @mat: matrix to be put * @src: c/c++ source data pointer * @size: size of source data */ void matPutVariable(const char* matName, const mxArray* mat, const void* src, const size_t size) { assert(matName!=NULL); assert(mat!=NULL); assert(src!=NULL && size>); memcpy((void*)mxGetPr(mat), src, size); engPutVariable(ep, matName, mat); } /* * @matExecute: execute a matlab command in string format. * @cmd: command string. */ void matExecute(const char * cmd) { assert(cmd != NULL); engEvalString(ep, cmd); } char* matGetOutput() { return buffer; } };
#include <iostream> #include "MatlabEngine.h" using namespace std; int main(void){ MatlabEngine engine; double _x[] = { , , , , }; double _y[] = {, , , , }; mxArray* x = engine.matCreate(, ); mxArray* y = engine.matCreate(, ); engine.matPutVariable("x", x, _x, sizeof(_x)); engine.matPutVariable("y", y, _y, sizeof(_y)); engine.matExecute("plot(x, y, '-*b', 'linewidth', 1)"); engine.matExecute("grid on, axis equal"); engine.matDestroy(x); engine.matDestroy(y); return ; }