본문 바로가기

Enginius/Matlab

opencv를 매트랩에서 사용해보자

 Image processing 관련된 일을 하다보면 opencv를 사용할 경우가 많다. 기본적으로 제공하는 library가 매우 빵빵하기 때문이다. 하지만 사용이 약간 불편할 때가 있는데 이는 내가 Matlab에 너무 길들여진 탓일 것이다. 사실 Matlab만으로 개발하는 것이 가장 편리하겠지만 (대부분의 경우) 카메라를 사용하거나, 빠른 연산을 필요로 하는 경우에는 Matlab을 좋은 tool이 아니다. 


 내가 속한 랩실의 박사과정인 히스레정(http://cpslab.snu.ac.kr/people)께서 좋은 development kit를 구하셨기에 이를 설치하고, 이용하는 포스팅을 하겠다. 개발 환경은 Window7-Ultimate K 64 bit 이고 프로그램은 Matlab 2011a와 Visual Studio 2010을 사용하였다. 


1. 저자의 홈페이지

 

 * 저자의 홈페이지: http://www.cs.sunysb.edu/~kyamagu/mexopencv/ 

 이곳에 모든 것이 있다. 한글보다 영어가 편하면 아래는 무시해도 좋다. 


2. 자 그럼 시작해보자.


 설치를 위해서는 다음의 홈페이지에 들어가야 한다.   


 *설치 갈라잡이: https://github.com/kyamagu/mexopencv


 여기에 들어가면 Window환경에서 개발하기 위해선 matlab과 , 2.3.1 이상의 opencv와, compiler가 필요하다고 한다. 

 이 중에서 opencv 2.4.2를 받아야 하는데 이는 다음 홈페이지에 들어가면 받을 수 있다. 


 *OpenCV 받기: http://sourceforge.net/projects/opencvlibrary/files/opencv-win/2.4.0/

 *멀티쓰레딩 지원: http://threadingbuildingblocks.org/ver.php?fid=187 (os는 win)

 

 이곳에 들어가면 약 213MB짜리 설치 파일을 받을 수 있다. 또 멀티 쓰레드를 위한 파일도 받아놓자. 


3. OpenCV만 설치하기 아쉽다. Visual Studio에서도 써보자.


 이곳에 써진 것은 다음 블로그에서 퍼온 것이다. 

 *멋진 블로그: http://babytiger.tistory.com/entry/window%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C-OpenCV-240-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0


 1. 일단 위에서 받으라고 한 파일을 다 받자. 


 2. 받은 후에 실행을 해서 압축을 풀고 각 폴더를 원하는 위치로 옮기자. 

- OpenCV의 경우 시간이 좀 걸리니 인내심을 갖자. 


 3. 나는 다음과 같이 옮겼다. 

- OpenCV: opencv라는 폴더를 C:\opencv 로 옮긴다. 

- TBB_: tbb40_20120613oss이라는 폴더를  C:\tbb40_20120613oss 로 옮긴다. (날짜에 주의한다! 계속 업데이트 중이다.)


 4. 환경 변수 설정을 하자. 

- 컴퓨터 아이콘을 오른쪽 버튼 클릭 -> 속성 -> 고급 시스템 설정 -> 환경변수 (제어판\시스템 및 시스템\시스템)에서 PATH 변수 끝에 OpenCV와 TBB 경로를 환경에 맞게 입력. 


- OpenCV 경로 설정

 윈도우 32bit + VS2010 -> C:\opencv\build\x86\vc10\bin; 

 윈도우 32bit + VS2008 -> C:\opencv\build\x86\vc9\bin ;

 윈도우 64bit + VS2010 -> C:\opencv\build\x64\vc10\bin;

 윈도우 64bit + VS2008 -> C:\opencv\build\x64\vc9\bin;


- TBB 경로 설정

 인텔CPU 32bit + VS2010 -> C:\tbb40_20120613oss\bin\ia32\vc10; 

 인텔CPU  32bit + VS2008 -> C:\tbb40_20120613oss\bin\ia32\vc9;

 인텔CPU  64bit + VS2010 -> C:\tbb40_20120613oss\bin\intel64\vc10;

 인텔CPU  64bit + VS2008 -> C:\tbb40_20120613oss\bin\intel64\vc9;


이 부분이 X같은 건데 opencv는 64비트로 pre-build된 lib를 쓰면 에러가 난다. 아니 아예 올리질 말던가 -_- 여튼 무조건 32비트로 하자. 


- 입력이 끝난 후에는 재부팅한다. 


 5. 프로젝트를 만들고 라이브러리 경로를 설정하자. 

 - 파일(File) -> 새로 만들기(New) -> 프로젝트(Project) (단축키: 컨트롤+시프트+N) -> Visual C++ -> Win32 -> Win32 콘솔 응용 프로그램(Win32 Console Application) -> 다음 (빈 프로젝트(Empty project) 체크) -> 마침


*라이브러리 경로 설정

1. Local 방법: 보기(View) -> 속성 페이지(Property Pages) -> 구성 속성 -> C/C++ -> 추가 포함 디렉터리(Additional Include Directories) C:\Program Files\opencv\build\include 입력

 ※ 구성 속성에 C/C++ 탭이 안보이면 프로젝트에 .c/.c++ 파일을 생성하면 보입니다.


2. 보기(View) -> 속성 페이지(Property Pages) -> 구성 속성 -> 링커(Linker) -> 추가 라이브러리 디렉터리(Additional Library Directories) 에 환경에 따라 라이브러리 경로를 입력합니다. 


윈도우 32bit + VS2010 -> C:\Program Files\opencv\build\x86\vc10\lib

윈도우 32bit + VS2008 -> C:\Program Files\opencv\build\x86\vc9\lib

윈도우 64bit + VS2010 -> C:\Program Files\opencv\build\x64\vc10\lib

윈도우 64bit + VS2008 -> C:\Program Files\opencv\build\x64\vc9\lib


3. 보기(View) -> 속성 페이지(Property Pages) -> 구성 속성 -> 링커(Linker) -> 입력(Input) -> 추가 종속성(Additional dependencies) 에 아래 진한 DLL 이름은 opencv 공식 tutorials에 있는 목록입니다.


2.4.2 디버그(debug) 모드

opencv_calib3d242d.lib

opencv_contrib242d.lib

opencv_core242d.lib

opencv_features2d242d.lib

opencv_flann242d.lib

opencv_gpu242d.lib

opencv_haartraining_engined.lib

opencv_highgui242d.lib

opencv_imgproc242d.lib

opencv_legacy242d.lib

opencv_ml242d.lib

opencv_nonfree242d.lib

opencv_objdetect242d.lib

opencv_photo242d.lib

opencv_stitching242d.lib

opencv_ts242d.lib

opencv_video242d.lib

opencv_videostab242d.lib


4. 예제 소스 

 - 할 일이 아직 남아있다!

1. C:\tbb40_20120613oss\bin\ia32\vc10 에서 tbb_debug.dll을 복사해서 cpp 파일이 있는 폴더에 복사한다. 

2. C:\opencv\build\x86\vc10\lib 에서  lilb파일들을 싹다 복사해서 cpp 파일이 있는 폴더에 복사한다. 


#include <opencv/highgui.h>


int main(){

IplImage *src = 0;

char *name = "Windows";

CvCapture *capture = cvCaptureFromCAM(0);


if(!capture){

return 1;

}


cvNamedWindow(name,CV_WINDOW_AUTOSIZE);


for(;;){

cvGrabFrame(capture);

src = cvRetrieveFrame(capture);

cvShowImage(name,src);

if(cvWaitKey(10) == 27){

break;

}

}


cvReleaseCapture(&capture);

cvDestroyWindow(name);


return 0;

}

 

 => 잘 된다. 아 하루종일 삽질한걸 생각하면 눈물이 다 난다..오픈소스는 뚜껑열리게해서 오픈소스인 것 같다. XXX head-open source. -_-. 


4. 원래 목적인 Matlab과 연동, mexopencv로 돌아와보자.


 1. 먼저 Windows SDK를 설치해야한다. Visual Studio 2010 sp1과 충돌이 있다고 하니 유의하자.  (http://celdee.tistory.com/765)

 *Windows SDK 받기: http://www.microsoft.com/en-us/download/details.aspx?id=8279

 이거 오래걸린다. 또  


 2. 설치가 끝났다면 mexopencv를 받자. 

 *다운 받을 수 있는 홈페이지: https://github.com/kyamagu/mexopencv 


 3. c:\opencv\build\x86\vc10\bin 를 환경 변수의 Path에 추가한다. 


 4. mex -setup

- 난 visual studio 2010으로 하였다. 


 5. cv.make

- 다운 받은 폴더에 들어가서 이걸 친다. 이 때 이 경로에 한글이 있으면 안되는 것 같다. 


 6. 설치에 시간이 좀 걸린다... 또  


 7. 설치가 다 끝나고 나면 테스트를 해보자. 

- 적당히 이미지를 하나 저장한 뒤에 다음과 같이 m 파일을 만들고 실행한다. 

clc;

clear all;

addpath('C:\Users\human\Dropbox\Research\CPSLab\Implementation\ETC\kyamagu-mexopencv-df31825\kyamagu-mexopencv-df31825');


%%

img = imread('images.jpg');

imgGray = rgb2gray(img);

% result = cv.filter2D(img, [1 0 -1]);

%imshow(result);


tic;

keypoints = cv.SIFT(img);

toc;


numSIFT = size(keypoints,2);

imshow(img);

hold on

for si = 1:numSIFT

    %% for every SIFT

    plot( keypoints(si).pt(1), keypoints(si).pt(2)...

        , 'o', 'MarkerSize', keypoints(si).size...

        , 'MarkerEdgeColor', [ rand() rand() rand() ]...

        , 'LineWidth', 4 );

end

hold off




5. 이제 새로운 mex 함수를 만들고 사용해 볼까?

Developing a new mex function

All you need to do is to add your mex source file in src/+cv/. If you want to add a mex function called myfunc, createsrc/+cv/myfunc.cpp. The minimum contents of the myfunc.cpp would look like this:

#include "mexopencv.hpp"
void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[] )
{
    // Check arguments
    if (nlhs!=1 || nrhs!=1)
        mexErrMsgIdAndTxt("myfunc:invalidArgs", "Wrong number of arguments");

    // Convert MxArray to cv::Mat
    cv::Mat mat = MxArray(prhs[0]).toMat();

    // Do whatever you want

    // Convert cv::Mat back to mxArray*
    plhs[0] = MxArray(mat);
}

This example simply copies an input to cv::Mat object and then copies again to the output. Notice how the MxArray class provided by mexopencv converts mxArray to cv::Mat object. Of course you would want to do something more with the object. Once you create a file, type make to build your new function. The compiled mex function will be located inside +cv/ and accessible throughcv.myfunc within matlab.

The mexopencv.hpp header includes a class MxArray to manipulate mxArray object. Mostly this class is used to convert between opencv data types and mxArray.

int i            = MxArray(prhs[0]).toInt();
double d         = MxArray(prhs[0]).toDouble();
bool b           = MxArray(prhs[0]).toBool();
std::string s    = MxArray(prhs[0]).toString();
cv::Mat mat      = MxArray(prhs[0]).toMat();   // For pixels
cv::Mat ndmat    = MxArray(prhs[0]).toMatND(); // For N-D array
cv::Point pt     = MxArray(prhs[0]).toPoint();
cv::Size siz     = MxArray(prhs[0]).toSize();
cv::Rect rct     = MxArray(prhs[0]).toRect();
cv::Scalar sc    = MxArray(prhs[0]).toScalar();
cv::SparseMat sp = MxArray(prhs[0]).toSparseMat(); // Only double to float

mxArray* plhs[0] = MxArray(i);
mxArray* plhs[0] = MxArray(d);
mxArray* plhs[0] = MxArray(b);
mxArray* plhs[0] = MxArray(s);
mxArray* plhs[0] = MxArray(mat);
mxArray* plhs[0] = MxArray(ndmat);
mxArray* plhs[0] = MxArray(pt);
mxArray* plhs[0] = MxArray(siz);
mxArray* plhs[0] = MxArray(rct);
mxArray* plhs[0] = MxArray(sc);
mxArray* plhs[0] = MxArray(sp); // Only 2D float to double

Check MxArraay.hpp for a complete list of the conversion API.

If you rather want to develop a matlab function that internally calls a mex function, make use of the +cv/private directory. Any function placed under private directory is only accessible from +cv/ directory. So, for example, when you want to design a matlab class that wraps the various behavior of the mex function, define your class at +cv/MyClass.m and develop a mex function dedicated for that class in src/+cv/private/MyClass_.cpp. Inside of +cv/MyClass.m, you can call MyClass_() without cv namescope.

 

6. CV HELP