C++编程相比于matlab具有更高的效率,更适用于工程上的应用。matlab比较适合做数据分析,调试方便,语言简洁。为了更好的利用这两种工具,MEX混合编程是不可或缺的一项技能。本篇博客主要是记录我自己的一个小小的混合编程实践项目。
- 环境配置(MATLAB+Visual studio)
首先matlab需要安装C++的编译器,可以选择windows 自带的,如果你装了visualstudio的话(安装的时候,记得选择C++选项以及C++相关的包),建议直接选用visual studio的。使用mex -setup 命令来为matlab建立相关的环境。相关的博文可以参考https://blog.youkuaiyun.com/zaishuiyifangxym/article/details/81669673
由于工作需要,我在C++程序中可能需要用到opencv等视觉相关的库,所以在安装了visual studio之后,还需要配置一下opencv的环境。这里可以参见我的另外一篇博文:https://mp.youkuaiyun.com/postedit/84975188。同时还需要把matlab自带的MEX文件库包含到路径中去:
包含目录: C:\Program Files\MATLAB\R2017b\extern\include
C:\Program Files\MATLAB\R2017b\extern\include\win64
库目录 : C:\Program Files\MATLAB\R2017b\extern\lib\win64\microsoft
但是,这并不算完,我们需要在创建的工程中,建立一个混编的C++文件
2. MEX编程起步
配置好环境之后,就可以来着手编程了,其实要掌握这项技能很简单,把握好以下两点:
- MEX编程语法
- 编译方法
a. MEX中用过mexFunction 代替了C++中的main函数
#include "mex.h"
#include <opencv/cv.h>
#include <opencv/cxcore.hpp>
#include <opencv2\features2d\features2d.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include "stdio.h"
#include <iostream>
//nlhs是输出的参数个数,plhs为左边指数指针,nrhs为右边输入参数的个数,prhs为输入参数的指针
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[])
{
}
四个参数分别用来输出和输入数据: nlhs 输出参数个数,plhs 输出参数指针 (nrhs和prhs是输入参数相关的)。
注意: 我们对输出和输入参数的操作都是通过指针的方式进行的。而且默认的传递的数据都是double类型的矩阵,矩阵不同于C语言中的按行存储,这里传入的矩阵是按列来存储的,所以访问格式上会与我们常用的方式有所区别:
uchar *pData = (uchar *)mxGetPr(prhs[1]);//prhs[1]是第二个输入参数,同时强转为uchar
// 复制数据
cv::Mat im(rows, cols, CV_8U);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
im.at<uchar>(i, j) = pData[rows*j + i];//按列访问数据
}
}
常用的一些函数:
short rows = mxGetM(prhs[1]);//矩阵的行
short cols = mxGetN(prhs[1]);//矩阵的宽度
double *label= (double *)mxGetPr(prhs[0]);//获取数据的指针
//定义输出的变量
mwSize dim[2] = { im.cols,im.rows };//定义输出的尺寸变量
plhs[0] = mxCreateNumericArray(2, dim, mxUINT8_CLASS, mxREAL);//创建
memcpy(mxGetPr(plhs[0]), im.data, sizeof(uchar)*im.cols*im.rows);//拷贝数据
b.编译
如果没有使用第三方库的话,直接在matlab里面使用mex **.cpp就可以进行编译了,但是比如我使用了opencv,那么就需要自己写一个编译文件,包含所需要用的库和头文件:
cd D:\专业学习\程序代码\mex\test\src
OpenCV_INLCUDE_DIR = '-ID:\opencv\opencv\build\include -ID:\opencv\opencv\build\include\opencv -ID:\opencv\opencv\build\include\opencv2 ';
OpenCV_LIBRARY_DIR = '-LD:\opencv\opencv\build\x64\vc12\lib -lopencv_core2413 -lopencv_imgproc2413 -lopencv_highgui2413 -lopencv_contrib2413 -lopencv_legacy2413';
%对于库的包含,不懂的可以看一看doc mex,里面有写
eval(['mex matlabcvline.cpp ' OpenCV_INLCUDE_DIR OpenCV_LIBRARY_DIR]);
最后附上一个例程,以供自己复习
1.mex文件:
#include "mex.h"
#include "stdio.h"
#include <opencv/cv.h>
#include <opencv/cxcore.hpp>
#include <opencv2\features2d\features2d.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[])
{
//实现a+b
//plhs输出参数,prhs输入参数
//double *a = mxGetPr(prhs[0]);
//double *b = mxGetPr(prhs[1]);
//plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);
//double *c = mxGetPr(plhs[0]);
//*c = *a + *b;
printf("hello my first mex.cpp\n");
cv::VideoCapture cam(0);
cv::Mat im;
cam >> im;
cv::imshow("im", im);
cv::waitKey(1);
//cam.release();
}
2. 编译文件
cd D:\专业学习\程序代码\mex\test\src
OpenCV_INLCUDE_DIR = '-ID:\opencv\opencv\build\include -ID:\opencv\opencv\build\include\opencv -ID:\opencv\opencv\build\include\opencv2 ';
OpenCV_LIBRARY_DIR = '-LD:\opencv\opencv\build\x64\vc12\lib -lopencv_core2413 -lopencv_imgproc2413 -lopencv_highgui2413 -lopencv_contrib2413 -lopencv_legacy2413';
%对于库的包含,不懂的可以看一看doc mex,里面有写
eval(['mex test.cpp ' OpenCV_INLCUDE_DIR OpenCV_LIBRARY_DIR]);
3. matlab调用文件
clc;
clearvars;
close all;
addpath('D:\专业学习\程序代码\mex\test\src\');%mex文件
while 1
test;
end