天天看點

C/C++與Matlab混合程式設計

由于實驗室項目遺留問題,可能為了圖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這樣的第三方庫。

  1. 下載下傳OpenCV2.4.9 for Windows,解壓到OPENCV_ROOT(自定義路徑);
  2. 在VS2012裡指定頭檔案路徑為:

    OPENCV_ROOT/build/include

    ;庫檔案路徑:

    OPENCV_ROOT/build/x64/vc11/lib

  3. OPENCV_ROOT/build/x64/vc11/bin

    拷貝

    opencv_core249d.dll

    ,

    opencv_core249.dll

    ,

    opencv_highgui249d.dll

    opencv_highgui249.dll

    到VS工程目錄(工程為x64,x86工程);
  4. 在代碼中添加如下代碼表明用到的庫檔案
    #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
               
  5. 加載和顯示圖像
    #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引擎操作方式如下:

  1. 建立和MATLAB版本一緻的C++工程,如,我的MATLAB是x64的,就建立x64的C++工程,這樣才能保證調用的動态庫版本正确;
  2. 在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

    ;
  3. 在代碼中調用MATLAB引擎函數,為了使用友善,我對部分引擎函數做了一些封裝,如下:
    /*
     * 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;
        }
    };
               
    4.在main函數中執行個體化引擎類并調用引擎方法:
    #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 ;
    }
               

繼續閱讀