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.dllopencv_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 
    
    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 0;
    }

可视化

项目最终有可视化的需求,而用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 
     #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(1);
            }
            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>0 && col>0);
            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>0);
            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 
     #include "MatlabEngine.h"
     using namespace std;
    
    int main(void){
        MatlabEngine engine;
        double _x[] = { 1, 2, 3, 4, 5 };
        double _y[] = {1, 4, 9, 16, 25};
        mxArray* x = engine.matCreate(1, 5);
        mxArray* y = engine.matCreate(1, 5);
        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 0;
    }

你可能感兴趣的:(Windows,C/CPP,Matlab)