想要在MATLAB里面使用C/C++(OpenCV)编写好的工程文件?语言无国界,就需要通过mex创建动态链接库供MATLAB调用,这里介绍两种方法。一种是直接使用mex函数把你的cpp,h文件都打包进来,这里需要明确你的工程文件调用了那些opencv的库文件,头文件,是一种通用方法;另一种是用官方提供的
Computer Vision System Toolbox OpenCV Interface ,是第一种方法的扩展,使用函数mexOpenCV来代替mex函数编译,最大亮点在于提供了MATLAB和OpenCV之间的数据转换,也无需指定你项目中依赖的OpenCV库文件路径。目前第二种方法是用VS2012编译opencv的,其他版本的VS可能不兼容,这时最好用第一种通用方法。
文件名为LaneDetectCV.cpp。其中上面LaneDetect函数用到了OpenCV里面的函数,这些函数主要在core,improc模块里面。而且另外还有自己写的实现文件,用了2个文件夹存储,即Hough和LaneDetect文件夹。调用关系是LaneDetect函数-->LaneDetect文件夹里面CPP-->Hough文件夹里面CPP。
编译完成后生成LaneDetectCV.mexw64的库文件。这时运行会出错,还需要把额外依赖的opencv_core249.dll、opencv_imgproc249.dll拷贝到当前目录即可完美运行与C/C++一样的结果(或者加入到系统的环境变量重启)。
然后在命令行窗口输入mexOpenCV matchTemplateOCV.cpp,生成“matchTemplateOCV.mexw64”就可以到MATLAB测试了。 测试文件“test.m”如下
src.jpg,template.jpg及运行测试文件“test.m”后的结果图如下:
一、mex
根据你自己的工程文件,编写mexFunction函数,该函数是C/C++与matlab的入口函数,相当于C/C++里面的main函数,架起了两门语言的桥梁,在该函数里面写入你要用到的C/C++接口接入方式。下面以一个例子说明。
#include "LaneDetect/LaneDetect.h" #include "mex.h" #include "matrix.h" #include "opencv2/opencv.hpp" void checkInputs(int nrhs, const mxArray *prhs[]) { // Check number of inputs if (nrhs != 1) { mexErrMsgTxt("Incorrect number of inputs. Function expects 1 inputs."); } // Check image data type if (!mxIsUint8(prhs[0])) { mexErrMsgTxt("Template and image must be UINT8."); } } void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { // 输入参数检查 checkInputs(nrhs, prhs); // 把MATLAB数据类型转换为OpenCV的Mat cv::Mat src; uchar * inputPr = (uchar *)mxGetData(prhs[0]); int m = mxGetM(prhs[0]); int n = mxGetN(prhs[0]); src = cv::Mat::zeros(m, n, CV_8UC1); int number = 0; for (size_t i = 0; i < m; i++) { for (size_t j = 0; j < n; j++) { src.at<uchar>(i,j) = inputPr[j*m+i]; } } // 调用自己opencv写的接口 std::vector<cv::Vec4i> vecLines = LaneDetect(src); // 输出转换为Mat类型,每行是一个Vec4i,行的个数是检测到的线条数(m*4列矩阵) cv::Mat matOut = cv::Mat(vecLines.size(), 4, CV_32S); for (size_t i = 0; i < vecLines.size(); i++) { int* data = matOut.ptr<int>(i); for (size_t j = 0; j < 4; j++) { data[j] = vecLines[i][j]; } } // 转换成mxArray int rows = vecLines.size(); int cols = 4; plhs[0] = mxCreateDoubleMatrix(rows, cols, mxREAL); double *imgMat; imgMat = mxGetPr(plhs[0]); for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) *(imgMat + i + j * rows) = (double)matOut.at<signed>(i, j); return; }
文件名为LaneDetectCV.cpp。其中上面LaneDetect函数用到了OpenCV里面的函数,这些函数主要在core,improc模块里面。而且另外还有自己写的实现文件,用了2个文件夹存储,即Hough和LaneDetect文件夹。调用关系是LaneDetect函数-->LaneDetect文件夹里面CPP-->Hough文件夹里面CPP。
然后可写一个mex通用的转化make.m文件,为MATLAB文件。
% Notice: first use "mex -setup" to choose your c/c++ compiler clear; %% ------------------------------------------------------------------- %% get the architecture of this computer is_64bit = strcmp(computer,'MACI64') || strcmp(computer,'GLNXA64') || strcmp(computer,'PCWIN64'); %% ------------------------------------------------------------------- %% the configuration of compiler % You need to modify this configuration according to your own path of OpenCV % 注意:你的VS OpenCV平台一定要匹配Matlab 64位的! out_dir='./';% 当前目录 CPPFLAGS = ' -g -I./Hough/NewHough.h -I./LaneDetect/LaneDetect.h -IF:\opencv\mybuild\install\include -IF:\opencv\mybuild\install\include\opencv -IF:\opencv\mybuild\install\include\opencv2'; % your OpenCV "include" path LDFLAGS = ' -LF:\opencv\build\x64\vc12\lib'; % 用OpenCV release版本的"lib"路径 LIBS = ' -lopencv_core249 -lopencv_imgproc249'; % release版本的lib,无后缀,系统会自动加上去 if is_64bit CPPFLAGS = [CPPFLAGS ' -largeArrayDims']; end %% add your files here! compile_files = [ % the list of your code files which need to be compiled 'LaneDetectCV.cpp',' ./LaneDetect/LaneDetect.cpp',' ./Hough/NewHough.cpp' ]; %------------------------------------------------------------------- %% compiling... str = compile_files; fprintf('compilation of: %s\n', str); str = [str ' -outdir ' out_dir CPPFLAGS LDFLAGS LIBS]; args = regexp(str, '\s+', 'split'); mex(args{:}); fprintf('Congratulations, compilation successful!!!\n');
编译完成后生成LaneDetectCV.mexw64的库文件。这时运行会出错,还需要把额外依赖的opencv_core249.dll、opencv_imgproc249.dll拷贝到当前目录即可完美运行与C/C++一样的结果(或者加入到系统的环境变量重启)。
二、mexOpenCV
采用这种方法就就比较简洁了,比如第一部分的mexFunction可以改下如下形式:
#include "LaneDetect/LaneDetect.h" #include "opencvmex.hpp" void checkInputs(int nrhs, const mxArray *prhs[]) { // Check number of inputs if (nrhs != 1) { mexErrMsgTxt("Incorrect number of inputs. Function expects 1 inputs."); } // Check image data type if (!mxIsUint8(prhs[0])) { mexErrMsgTxt("Template and image must be UINT8."); } } void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { // Check inputs to mex function checkInputs(nrhs, prhs); // Convert mxArray inputs into OpenCV types cv::Ptr<cv::Mat> imgCV = ocvMxArrayToImage_uint8(prhs[0], true);// 把MxArray转换为Mat,类型为uint8,一句话搞定 std::vector<cv::Vec4i> vecLines = LaneDetect(*imgCV); // 输出转换为Mat类型,每行是一个Vec4i,行的个数是检测到的线条数(m*4列矩阵) cv::Mat matOut = cv::Mat(vecLines.size(), 4, CV_32S); for (size_t i = 0; i < vecLines.size(); i++) { int* data = matOut.ptr<int>(i); for (size_t j = 0; j < 4; j++) { data[j] = vecLines[i][j]; } } // 输出到matlab plhs[0] = ocvMxArrayFromMat_int32(matOut);// 把Mat转换为MxArray,一句话搞定 }
然后在MATLAB中输入mexOpenCV -g LaneDetectCV.cpp LaneDetect.cpp NewHough.cpp即可完成相同的步骤。-g表示带调试文件生成,有错误可以进入VS中调试。
扫描二维码关注公众号,回复:
148087 查看本文章
再举另外一个例子,用OpenCV里面的matchTemplate函数。文件名"matchTemplateOCV.cpp",内容如下:
#include "opencvmex.hpp" #define _DO_NOT_EXPORT #if defined(_DO_NOT_EXPORT) #define DllExport #else #define DllExport __declspec(dllexport) #endif /////////////////////////////////////////////////////////////////////////// // Check inputs /////////////////////////////////////////////////////////////////////////// void checkInputs(int nrhs, const mxArray *prhs[]) { const mwSize * tdims, *fdims; // Check number of inputs if (nrhs != 2) { mexErrMsgTxt("Incorrect number of inputs. Function expects 2 inputs."); } // Check input dimensions tdims = mxGetDimensions(prhs[0]); fdims = mxGetDimensions(prhs[1]); if (mxGetNumberOfDimensions(prhs[0])>2) { mexErrMsgTxt("Incorrect number of dimensions. First input must be a matrix."); } if (mxGetNumberOfDimensions(prhs[1])>2) { mexErrMsgTxt("Incorrect number of dimensions. Second input must be a matrix."); } if (tdims[0] > fdims[0]) { mexErrMsgTxt("Template should be smaller than image."); } if (tdims[1] > fdims[1]) { mexErrMsgTxt("Template should be smaller than image."); } // Check image data type if (!mxIsUint8(prhs[0]) || !mxIsUint8(prhs[1])) { mexErrMsgTxt("Template and image must be UINT8."); } } /////////////////////////////////////////////////////////////////////////// // Main entry point to a MEX function /////////////////////////////////////////////////////////////////////////// void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { // Check inputs to mex function checkInputs(nrhs, prhs); // Convert mxArray inputs into OpenCV types cv::Ptr<cv::Mat> templateImgCV = ocvMxArrayToImage_uint8(prhs[0], true); cv::Ptr<cv::Mat> imgCV = ocvMxArrayToImage_uint8(prhs[1], true); // Allocate output matrix int outRows = imgCV->rows - templateImgCV->rows + 1; int outCols = imgCV->cols - templateImgCV->cols + 1; cv::Mat outCV((int)outRows, (int)outCols, CV_32FC1); // Run the OpenCV template matching routine cv::matchTemplate(*imgCV, *templateImgCV, outCV, CV_TM_CCOEFF_NORMED ); // Put the data back into the output MATLAB array plhs[0] = ocvMxArrayFromImage_single(outCV); }
然后在命令行窗口输入mexOpenCV matchTemplateOCV.cpp,生成“matchTemplateOCV.mexw64”就可以到MATLAB测试了。 测试文件“test.m”如下
%% Setup % Set up test data src = rgb2gray(imread('src.jpg')); template = rgb2gray(imread('template.jpg')); %% Compute % Invoke mex function to search for matches between an image patch and an % input image. result = matchTemplateOCV(template, src); %% Show Results % Show the input image and the result of normalized cross correlation subplot(1,2,1); imshow(src); title('Input Image'); subplot(1,2,2); imshow(result,[]); title('Result of running matchTemplateOCV()'); truesize; % make the figure tight % Mark peak location [~, idx] = max(abs(result(:))); [y, x] = ind2sub(size(result),idx(1));%行列 hold('on'); plot(x,y,'ro'); % Plot approximate outline of the onion template bbox = [x,y,size(template,2),size(template,1)] - [size(template,2)/2,size(template,1)/2,0,0]; rectangle('Position', bbox,'EdgeColor',[1 0 0]); % Show the template image in a separate window figure; imshow(template); title('Template');
src.jpg,template.jpg及运行测试文件“test.m”后的结果图如下:
Reference:
http://blog.csdn.net/shaoxiaohu1/article/details/37744309
https://www.cnblogs.com/lukylu/p/3966871.html