您的位置:首页 > 编程语言 > MATLAB

matlab opencv C++ mex

2016-06-16 16:10 453 查看
前言:前面写过一篇 “Matlab OpenCV混合编程” 提到了三种方法。其他两种方法用起来比较方便,但速度就上不去,至少在我的电脑跑的感觉是这样。这一个星期一直在用mex cpp的方法,可参考了网上很多博客,但按照他们的方法来,并修改相应的路径就是出不来结果。现在记录下遇到的问题和“解决方法”,但也有一些想不明白的地方。

系统及软件配:

windows7:64位

VS2013

matlab2015a 64位

opencv2.4.9

1、路径等相关配置

这里自行搜索怎么添加 opencv 的系统路径,以及在VS配置相关路径,这里提供一个参考的链接1吧 

参考连接去配置就好,注意改成自己相应的地址跟版本号,链接中提到,如果找不到opencv_core249d.dll等类似的文件,就重启下电脑,或者按照链接中的第六步去做。

如果要用相对路径的话,可以参考链接2

问题:找不到各种头文件,如“highgui.hpp” 

解决思路和方法:

一般加入的都是这三个路径

...\opencv\build\include

...\opencv\build\include\opencv

...\opencv\build\include\opencv2 

注意看opencv和opencv2下面的头文件
如果引用头文件 “cv.h”, "highgui.h", "cxcore.h"等都没问题,因为这些 ".h" 的头文件直接就在opencv中,但如果直接#include "highgui.hpp" 则会出现找不到头文件的问题

因为“highgui.hpp” 文件是在opencv2中highgui文件夹下面,这时候应该改成#include "opencv2\highgui\highgui.hpp" 。

其他相应的头文件而根据上面的例子去改吧。

参考文献:

http://blog.csdn.net/poem_qianmo/article/details/19809337

http://blog.csdn.net/ggz631047367/article/details/37914681

2、mex

a)之前在windows编译 tld 的源程序,本来想在tld上面直接改的,发现有问题;

b)另外,有不少教程说修改mexopt.bat文件,但新版本matlab没有这个文件了,虽然也可以通过在matlab的命令窗口执行 “fullfile(prefdir,'mexopts.bat')”命令来找到mexopt.bat的路径,但被另外一个文件替代了。这个路径是被隐藏起来的。

c)后面参考了其他的博客等,都能编译出文件来,但总是出不来结果。后面看到文献[3] ,虽然也出不来结果,但猜测了一下,再修改就没问题了。下面直接给出make文件的写法再来说明自己遇到的坑

% This cppmake.m is for MATLAB
% Function: compile c++ files which rely on OpenCV for Matlab using mex

% Matlab and C++ mixed programming(dependent on opencv library)
% First step(before exeuting this program): use "mex -setup" to choose your c/c++ compiler
clear all;
clc;

% 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
% Notice: if your system is 64bit, your OpenCV must be 64bit!
out_dir='./';
CPPFLAGS = ' -O -DNDEBUG -I.\ -IC:\opencv\build\include -IC:\opencv\build\include\opencv -IC:\opencv\build\include\opencv2'; % your OpenCV "include" path
LDFLAGS = ' -LC:\opencv\build\x64\vc12\lib'; % your OpenCV "lib" path
LIBS = ' -lopencv_calib3d249d -lopencv_contrib249d -lopencv_core249d -lopencv_features2d249d -lopencv_flann249d -lopencv_gpu249d -lopencv_highgui249d -lopencv_imgproc249d -lopencv_legacy249d -lopencv_ml249d -lopencv_nonfree249d -lopencv_objdetect249d -lopencv_photo249d -lopencv_stitching249d -lopencv_ts249d -lopencv_video249d -lopencv_videostab249d';
%LIBS = ' -lopencv_calib3d249 -lopencv_contrib249 -lopencv_core249 -lopencv_features2d249 -lopencv_flann249 -lopencv_gpu249 -lopencv_highgui249 -lopencv_imgproc249 -lopencv_legacy249 -lopencv_ml249 -lopencv_nonfree249 -lopencv_objdetect249 -lopencv_photo249 -lopencv_stitching249 -lopencv_ts249 -lopencv_video249 -lopencv_videostab249';
if is_64bit
CPPFLAGS = [CPPFLAGS ' -largeArrayDims'];
end

% add your files here!!
compile_files = {
%the list of your code files which need to be compiled
% 'RGB2Gray.cpp'
% 'OpenImage.cpp'
};

%----------------------------------------------------------------------------------------------
%% compiling
for k = 1 : length(compile_files)
str = compile_files{k};
fprintf('compilation of: %s\n', str);
str = [str ' -outdir ' out_dir CPPFLAGS LDFLAGS LIBS];
args = regexp(str, '\s+', 'split');
mex(args{:});
end
fprintf('Congratulations, compilation successful!!!\n');

相应的修改CPPFLAGS变量中opencv的路径

根据系统和编译器的版本修改LDFLAGS变量中的路径,说明:如果是64位系统则是x64,否则x86,vc12表示用的是VS2013

注意:这里提供了两个LIBS,可以看到一个是带d后缀的,一个是不带d后缀的,这两个都可以mex成功,不会报错,但有一个可以出来你要的结果,一个不行。很多博主都直接写不带d后缀的,直到看到文献[3] ,我的问题才迎刃而解,非常感谢!当然,你可以需要的就是不带d的。

我用的是带d后缀的那个LIBS,下面有个OpenImage.cpp的例子,如果我用不带d的,可以显示一个窗口,但里面确实灰色的,没有内容。而用带d的却可以

理解:目前还不是很确切知道原因,但猜测

a)我本来在VS中就是按照默认的采用debug的编译模式,这个可能会比较高,因为其他博主都能出来结果

b)CPPFLAGS变量中"-DNDEBUG"属性是采用debug

说明:上面的LIBS不一定需要所有的链接库,zouxy博客中就加入了几个链接库,我把LIBS修改成自己对应的opencv版本并加上d后缀,也是可以mex通过,并出来结果。但都写上去是没错的,以后也省了很多麻烦。

参考文献:

[1] http://blog.csdn.net/zouxy09/article/details/20553007

[2] http://zhidao.baidu.com/link?url=lLjCzivibkNLNYyn6Gx_oDXvnwNo7qprW02Fj_kaBmYP2XOv1oJvww_nJD4UJFMen7vIgZ5R83LYgBu6fR4BZqy3lt3NtKCQotmpNtfEC63&hideOtherAnswer=true&newAnswer=1

[3] http://www.cnblogs.com/lukylu/p/3966871.html

3、IplImage or Mat  和 cvLoadImage or imread

在混合编程中,可能会遇到跟我一样的问题,就是imread读取不了图片,但cvLoadImage可以。这时候为了处理方便,或者不改动其他现有的程序,可能就需要进行类型转化了。

(a)IplImage 转化为 Mat

通过以下两种方式:

Mat mtx = iplImg;;  //(1) 

//Matmtx(iplImg); // IplImage* ->Mat 共享数据 //(2)  

(b)Mat类转IplImage:Mat类有个IplImage成员函数

通过以下两种方式即可转化:

IplImage ipl_img(image);  //(1)  

//IplImage ipl_img = image; //(2)  

文献2中还给出了CvMat和Mat格式的转化

(c)将CvMat类型转换为Mat类型与IplImage的转换类似,可以选择是否复制数据。Mat::Mat(const CvMat* m, bool copyData=false);(d)将Mat类型转换为CvMat类型与IplImage的转换类似,不复制数据,只创建矩阵头。例:// 假设Mat类型的imgMat图像数据存在CvMat cvMat = imgMat;
// Mat -> CvMat

参考文献:

[1] http://blog.csdn.net/lichengyu/article/details/24272349

[2] http://www.cnblogs.com/zcftech/archive/2013/04/10/3013027.html

4、例子

下面给出两个 cpp 程序,和相应的matlab编译文件,

RGB2Gray.cpp 文件:可以传递参数的例子

// Interface: read image file name given and convert to gray and return to Matlab
// Author : jeff
// Date   : 2016-06-16
//说明:修改至zouxy http://blog.csdn.net/zouxy09/article/details/20553007 
#include "opencv2/opencv.hpp"
#include "mex.h"<span style="white-space:pre">	</span>//matlab编译必要的头文件

using namespace cv;

/*******************************************************
Usage: [imageMatrix] = RGB2Gray('imageFile.jpeg');
Input:
a image file
OutPut:
a matrix of image which can be read by Matlab
**********************************************************/

void exit_with_help()
{
mexPrintf(
"Usage: [imageMatrix] = DenseTrack('imageFile.jpg');\n"
);
}

static void fake_answer(mxArray *plhs[])
{
plhs[0] = mxCreateDoubleMatrix(0, 0, mxREAL);
}

void RGB2Gray(char *filename, mxArray *plhs[])
{
IplImage *img = cvLoadImage(filename);	// read the image
Mat image = img;	//IplImage格式转化为Mat格式,使得下面的程序不需要修改

if(image.empty()) {
mexPrintf("can't open input file %s\n", filename);
fake_answer(plhs);
return;
}

// convert it to gray format
Mat gray;
if (image.channels() == 3)
cvtColor(image, gray, CV_RGB2GRAY);
else
image.copyTo(gray);

// convert the result to Matlab-supported format for returning
int rows = gray.rows;
int cols = gray.cols;
plhs[0] = mxCreateDoubleMatrix(rows, cols, mxREAL);
double *imgMat;
<span style="white-space:pre">	</span>imgMat = mxGetPr(plhs[0]);
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
*(imgMat + i + j * rows) = (double)gray.at<uchar>(i, j);

return;
}

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if(nrhs == 1)
{
char filename[256];
mxGetString(prhs[0], filename, mxGetN(prhs[0]) + 1);
if(filename == NULL)
{
mexPrintf("Error: filename is NULL\n");
exit_with_help();
return;
}

RGB2Gray(filename, plhs);
}
else
{
exit_with_help();
fake_answer(plhs);
return;
}
}


接下来是OpenImage.cpp文件:不需要传递参数,这里是读图片显示图片
#include "opencv2\opencv.hpp"
//#include <highgui.h> <span style="white-space:pre">	</span>//这个头文件跟下面的头文件任意一个都可以,highgui.h是在opencv文件夹下的,这里如果写成highgui.hpp就会找不到头文件
#include "opencv2\highgui\highgui.hpp"<span style="white-space:pre">	</span>//highgui.hpp是在这个路径下面,因为前面系统的路径加入是的opencv2,所以要通过这个方式调用下面的highgui.hpp
#include <iostream>
using namespace cv;
#include "mex.h"
void openimage()
{
IplImage *src = cvLoadImage("yourImageName.jpg");<span style="white-space:pre">	</span>//<span style="font-family: Arial, Helvetica, sans-serif;">//这里将yourImageName.jpg和 .cpp文件放在同一个文件夹下</span>
cvNamedWindow("yourWindowName",CV_WINDOW_AUTOSIZE);
cvShowImage("yourWindowName",src);
cvWaitKey(0);
cvDestroyWindow("yourWindowName");
cvReleaseImage(&src);
}

void mexFunction(int nlhs,mxArray *plhs[],int nrhs, const mxArray *prhs[])

{
openimage();
}


最后是matlab编写make.m文件,以上的文件名字都可以改的

%// This make.m is for MATLAB
%// Function: compile c++ files which rely on OpenCV for Matlab using mex
%// Author : jeff
%// Date   : 2016-06-16
%// 说明:修改来源 http://blog.csdn.net/zouxy09/article/details/20553007http://www.cnblogs.com/lukylu/p/3966871.html 
%% Please modify your path of OpenCV
%% If your have any question, please contact Zou Xiaoyi

% Notice: first use "mex -setup" to choose your c/c++ compiler
clear all;
clc;
%-------------------------------------------------------------------
%% 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
% Notice: if your system is 64bit, your OpenCV must be 64bit!
out_dir='./';
CPPFLAGS = ' -O -DNDEBUG -I.\ -IC:\opencv\build\include -IC:\opencv\build\include\opencv -IC:\opencv\build\include\opencv2'; % your OpenCV "include" path
LDFLAGS = ' -LC:\opencv\build\x64\vc12\lib';					   % your OpenCV "lib" path
LIBS = ' -lopencv_calib3d249d -lopencv_contrib249d -lopencv_core249d -lopencv_features2d249d -lopencv_flann249d -lopencv_gpu249d -lopencv_highgui249d -lopencv_imgproc249d -lopencv_legacy249d -lopencv_ml249d -lopencv_nonfree249d -lopencv_objdetect249d -lopencv_photo249d -lopencv_stitching249d -lopencv_ts249d -lopencv_video249d -lopencv_videostab249d';
%LIBS = ' -lopencv_calib3d249 -lopencv_contrib249 -lopencv_core249 -lopencv_features2d249 -lopencv_flann249 -lopencv_gpu249 -lopencv_highgui249 -lopencv_imgproc249 -lopencv_legacy249 -lopencv_ml249 -lopencv_nonfree249 -lopencv_objdetect249 -lopencv_photo249 -lopencv_stitching249 -lopencv_ts249 -lopencv_video249 -lopencv_videostab249';
if is_64bit
CPPFLAGS = [CPPFLAGS ' -largeArrayDims'];
end
%% add your files here!
compile_files = {
% the list of your code files which need to be compiled
<span style="white-space:pre">	</span>'RGB2Gray.cpp'
<span style="white-space:pre">	</span>'OpenImage.cpp'
};

%-------------------------------------------------------------------
%% compiling...
for k = 1 : length(compile_files)
str = compile_files{k};
fprintf('compilation of: %s\n', str);
str = [str ' -outdir ' out_dir CPPFLAGS LDFLAGS LIBS];
args = regexp(str, '\s+', 'split');
mex(args{:});
end

fprintf('Congratulations, compilation successful!!!\n');


说明:只要修改相应的opencv的路径和版本,写好自己的cpp文件,放到compile_files中即可。

5、展望

一下说明下以后需要做的,同时混合编程中还有几个问题没明白,后面有需要再解决补充。也希望大家可以提供解决思路和方法

a) 不能读取绝对路径中的图片文件,需要在同一路径中,而VS中是可以的;

b) cpp文件中,imread不能读取图片文件,不知道是不是跟matlab中imread混淆,纯属猜测

c) 不是给定图片名参数,而是传递通过matlab读取的图像信息,需要修改程序

d) ...... 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息