mex调用OpenCV项目工程文件

想要在MATLAB里面使用C/C++(OpenCV)编写好的工程文件?语言无国界,就需要通过mex创建动态链接库供MATLAB调用,这里介绍两种方法。一种是直接使用mex函数把你的cpp,h文件都打包进来,这里需要明确你的工程文件调用了那些opencv的库文件,头文件,是一种通用方法;另一种是用官方提供的 Computer Vision System Toolbox OpenCV Interface是第一种方法的扩展,使用函数mexOpenCV来代替mex函数编译,最大亮点在于提供了MATLAB和OpenCV之间的数据转换,也无需指定你项目中依赖的OpenCV库文件路径。目前第二种方法是用VS2012编译opencv的,其他版本的VS可能不兼容,这时最好用第一种通用方法。

一、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.csdn.net/shaoxiaohu1/article/details/37744309

http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/histograms/template_matching/template_matching.html

https://www.cnblogs.com/lukylu/p/3966871.html





猜你喜欢

转载自blog.csdn.net/cuixing001/article/details/78728262
Mex