想要在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中调试。
再举另外一个例子,用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.youkuaiyun.com/shaoxiaohu1/article/details/37744309
https://www.cnblogs.com/lukylu/p/3966871.html