》程序运行环境:
XCODE_DIR : /Applications/Xcode.app/Contents/Developer
XCRUN_DIR : /usr/bin
XCODE_AGREED_VERSION : 10.1
ISYSROOT : /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk
SDKVER : 10.14
CLANG_VERSION : 10.0.0
MATLABROOT : /Applications/MATLAB_R2019b.app
ARCH : maci64
简要信息:XCode 10.1; Matlab 2019b; Clang: 10.0.0;macOS High Sierra
》使用Matlab的编译MEX函数,对含有OpenCV的CPP代码进行编译,并调用。
》含有OpenCV的CPP代码normxcorr2_mex.cpp,内容如下:
#include "mex.h"
#include "cv_src/cv.h"
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <ctype.h>
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
int i, j, oi, oj, k;
int imw, imh;
int tpw, tph;
int resw, resh;
int outw, outh; // real size of output (taking into account 'shape')
int offw, offh;
double* im;
double* tp;
double* res;
IplImage* cvIm;
IplImage* cvTp;
IplImage* cvRes;
int shapeTypeCharSize = 6;
char* shapeTypeChar;
int shapeType = 1;
/* 1, full
2, valid
3, same
*/
float* cvImP;
float* cvTpP;
float* cvResP;
if( nrhs < 2 ) {
mexErrMsgTxt("result = normxcorr2Mex(TEMPLATE, IMAGE)");
} else if( !( mxIsDouble(prhs[0])&&mxIsDouble(prhs[1])) ) {
mexErrMsgTxt("IMAGE and TEMPLATE must be of type double");
} else if( nrhs > 2 && !mxIsChar(prhs[2]) ) {
mexErrMsgTxt("SHAPE parameter must be a character string");
}
shapeTypeChar = (char*)malloc(shapeTypeCharSize);
if( nrhs>2 ) {
mxGetString( prhs[2], shapeTypeChar, shapeTypeCharSize );
for( int ci=0; ci<strlen(shapeTypeChar); ci++ )
shapeTypeChar[ci] = tolower(shapeTypeChar[ci]);
if( !strcmp(shapeTypeChar, "full") )
shapeType = 1;
else if( !strcmp(shapeTypeChar, "valid") )
shapeType = 2;
else if( !strcmp(shapeTypeChar, "same") )
shapeType = 3;
else
shapeType = 0;
}
free(shapeTypeChar);
if( !shapeType )
mexErrMsgTxt("unknown shape type");
im = mxGetPr(prhs[1]);
imw = mxGetN(prhs[1]);
imh = mxGetM(prhs[1]);
tp = mxGetPr(prhs[0]);
tpw = mxGetN(prhs[0]);
tph = mxGetM(prhs[0]);
resw = imw-tpw+1;
resh = imh-tph+1;
if( resw<=0 || resh<=0 ) {
mexErrMsgTxt("size(image) < size(template)");
}
cvIm = cvCreateImage(cvSize(imw,imh), IPL_DEPTH_32F, 1);
cvTp = cvCreateImage(cvSize(tpw,tph), IPL_DEPTH_32F, 1);
cvRes = cvCreateImage(cvSize(resw,resh), IPL_DEPTH_32F, 1);
cvImP = (float*)cvIm->imageData;
cvTpP = (float*)cvTp->imageData;
cvResP = (float*)cvRes->imageData;
if( shapeType==1 ) { //full
outw = imw+tpw-1;
outh = imh+tph-1;
offw = tpw-1;
offh = tph-1;
} else if( shapeType==2 ) { //valid
outw = resw;
outh = resh;
offw = 0;
offh = 0;
} else if( shapeType==3 ) { // same
outw = imw;
outh = imh;
offw = ceil((float)(tpw-1)/2.0f);
offh = ceil((float)(tph-1)/2.0f);
}
plhs[0] = mxCreateDoubleMatrix( outh, outw, mxREAL );
res = mxGetPr(plhs[0]);
// we don't need to worry about alignment since we're using 32f
k = 0;
for( i=0; i<imw; i++ ) {
for( j=0; j<imh; j++ ) {
cvImP[ j*imw+i ] = im[ k ];
k++;
}
}
k = 0;
for( i=0; i<tpw; i++ ) {
for( j=0; j<tph; j++ ) {
cvTpP[ j*tpw+i ] = tp[ k ];
k++;
}
}
cvMatchTemplate( cvIm, cvTp, cvRes, CV_TM_CCOEFF_NORMED );
for( i=0, oi=offw; i<resw; i++, oi++ ) {
for( j=0, oj=offh; j<resh; j++, oj++ ) {
res[ oi*outh + oj ] = cvResP[ j*resw + i ];
}
}
cvReleaseImage(&cvIm);
cvReleaseImage(&cvTp);
cvReleaseImage(&cvRes);
}
》在Matlab的命令行中使用mex normxcorr2_mex.cpp,程序出现以下错误:
Undefined symbols for architecture x86_64:
"_cvCreateImage", referenced from:
_mexFunction in normxcorr2_mex.o
"_cvMatchTemplate", referenced from:
_mexFunction in normxcorr2_mex.o
"_cvReleaseImage", referenced from:
_mexFunction in normxcorr2_mex.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
》解决方案:
基于参考文献【1】,
在Matlab的命令行中,输入OpenCV源代码编译后结果的Include路径,以及LIB路径,然后执行mex相关的命令,最终输出文件名以.mexmaci64结束的文件。
(1) OpenCV_INLCUDE_DIR = '-I/usr/local/Cellar/opencv@3/3.4.5_5/include -I/usr/local/Cellar/opencv@3/3.4.5_5/include/opencv -I/usr/local/Cellar/opencv@3/3.4.5_5/include/opencv2 ‘;
(2) OpenCV_LIBRARY_DIR = '-L/usr/local/Cellar/opencv@3/3.4.5_5/lib -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_contrib -lopencv_legacy';
(3)eval(['mex mex normxcorr2_mex.cpp' OpenCV_INLCUDE_DIR OpenCV_LIBRARY_DIR]);
对于Windows平台,OpenCV源代码编译后的Include路径,LIB路径,请参考文献【2】,同时文献【2】也对-I, -L参数进行了相关的解释,具体可以自己去查阅相关资料。
》由于上述过程是基于OpenCV源代码编译后的结果进行配置的,本文在这里简单介绍一下macOS, Linux环境下如何编译penCV源代码或者直接获取编译后的结果。同时还需要注意的是,根据自己的需求选择对应版本的OpenCV源代码进行编译。
(1)对于macOS的用户来说,最简单的方式是在终端中输入brew install opencv@3 获取编译后的对应版本的opencv代码,(如果没有安装brew, 可以自己搜索mac环境下如何安装brew)。安装过程结束后,命令行会提醒用户该package被存放哪一个目录。
- 一般是存放
然后通过cd 操作,获取对应LID, INCLUDE文件夹的路径。
(2)对于Linux, Unbuntu的用户,可以参考文献【3】进行OpenCV的安装与编译。