개발하는 두더지

[C/C++/MFC/OpenCV] 얼굴 및 눈 코 입 검출 FaceDetect 엔진 개요 본문

OpenCV

[C/C++/MFC/OpenCV] 얼굴 및 눈 코 입 검출 FaceDetect 엔진 개요

덜지 2016. 7. 22. 01:27

OpenCV의 AdaBoost를 이용한 얼굴과 눈, 코, 입을 검출하는 엔진이다.

 

AdaBoost는 데이터가 학습데이터와 같은 Class로 분류되는지를 분류해 내는 분류기로 다수의 약한 분류기(각 약한 분류기는 의사 결정 트리로 돼있다)를 결합해 강한 분류기를 생성해내는 것이 핵심인 알고리즘으로 높은 분류율을 보인다. OpenCV에서 제공해 주는 AdaBoost 학습기를 이용하면 쉽게 학습데이터를 만들어 사용 할 수 있다.

 

Haarcascade 예제들 중에 얼굴, 눈, 코, 입에 대한 학습데이터가 이미 존재하는 것을 발견하고 그것을 이용하여 각 개체를 분류해 낸다.

 

다음의 파일들이 각각 얼굴, 왼쪽 눈, 입, 코, 오른쪽 눈에 대한 학습 데이터 들이다.

 

 

haarcascade_frontalface_alt.xml

haarcascade_mcs_lefteye.xml

haarcascade_mcs_mouth.xml

haarcascade_mcs_nose.xml

haarcascade_mcs_righteye.xml

 

 

 

FaceDetect 엔진 사용

 

FaceDetect.h

FaceDetect.lib

FaceDetect.dll

 

cv200.dll

cxcore200.dll

cv200.lib

cxcore200.lib

 

haarcascade_frontalface_alt.xml

haarcascade_mcs_lefteye.xml

haarcascade_mcs_mouth.xml

haarcascade_mcs_nose.xml

haarcascade_mcs_righteye.xml

 

위의 파일들이 배포되는데 프로젝트에 복사하고 cv200.lib cxcore200.lib FaceDetect.lib 등의 라이브러리를 링크하여 사용하면 된다.

 

 

자료구조 설명

FaceElementsDetecting 함수를 통해 검출된 안면 정보는

 

extern "C" FACEDETECT_DLL_TYPE typedef struct FaceInfo

{

        CvRect* face;          //얼굴

        CvRect* nose;          //

        CvRect* leftEye;       //왼쪽눈

        CvRect* rightEye;      //오른쪽눈

        CvRect* mouth;         //

}FaceInfo;

 

  

Interface

#ifdef DLLEXPORT_FACEDETECT_SUNMOONBIT_20_TH

#define FACEDETECT_DLL_TYPE __declspec(dllexport)

#else

#define FACEDETECT_DLL_TYPE __declspec(dllimport)

#endif

 

#include "cv.h"

 

 

/********************************************************************************

*       검출된얼굴, 눈, 코, 입에대한사각영역을저장한다.

*

*       (값이null 해당 요소는 검출실패한것이다.)

********************************************************************************/

extern "C" FACEDETECT_DLL_TYPE typedef struct FaceInfo

{

        CvRect* face;          //얼굴

        CvRect* nose;          //

        CvRect* leftEye;       //왼쪽눈

        CvRect* rightEye;      //오른쪽눈

        CvRect* mouth;         //

}FaceInfo;

 

/********************************************************************************

*       얼굴, 코, 눈, 입에대한학습데이터를로드한다.

*

*       (모든메소드를이용하기전에반드시한번호출해주어야한다.)

********************************************************************************/

extern "C" FACEDETECT_DLL_TYPE void InitFaceDetecting();

 

/********************************************************************************

*       로드한학습데이터를해제한다.

*

*       (InitFaceDetecting()을호출했다면반드시호출해주어야한다.)

********************************************************************************/

extern "C" FACEDETECT_DLL_TYPE void EndFaceDetecting();

 

/********************************************************************************

*       얼굴의각요소들을검출해낸다.

*

*       image : 얼굴을검출할이미지

********************************************************************************/

extern "C" FACEDETECT_DLL_TYPE FaceInfo* FaceElementsDetecting( IplImage* image );

 

/********************************************************************************

*       FaceElementsDetecting 함수로부터반환받은메모리를해제시킨다.

*

*       (반환받은구조체의사용이끝나면반드시호출해주어야한다.)

********************************************************************************/

extern "C" FACEDETECT_DLL_TYPE void ReleaseFaceInfo( FaceInfo** faceInfo );

 

 

Code

#define DLLEXPORT_FACEDETECT_SUNMOONBIT_20_TH

 

#include "FaceDetect.h"

 

/********************************************************************************

*       함수선언

********************************************************************************/

void FaceDetecting( IplImage* image, FaceInfo* faceInfo );          //얼굴을검출한다.

void NoseDetecting( IplImage* image, FaceInfo* faceInfo );          //코를검출한다.

void MouthDetecting( IplImage* image, FaceInfo* faceInfo );         //입을검출한다.

void LeftEyeDetecting( IplImage* image, FaceInfo* faceInfo );       //왼쪽눈을검출한다.

void RightEyeDetecting( IplImage* image, FaceInfo* faceInfo );      //오른쪽눈을검출한다.

 

/********************************************************************************

*       전역변수

********************************************************************************/

CvHaarClassifierCascade *faseCascade;        //얼굴에대한학습데이터

CvHaarClassifierCascade *noseCascade;        //코에대한학습데이터

CvHaarClassifierCascade *leftEyeCascade;     //왼쪽눈에대한학습데이터

CvHaarClassifierCascade *rightEyeCascade;    //오른쪽눈에대한학습데이터

CvHaarClassifierCascade *mouthCascade;               //입에대한학습데이터

 

CvMemStorage *storage;                                       //검출된영역을임시로저장할메모리

 

 

/********************************************************************************

*       함수구현

********************************************************************************/

 

/////////////////얼굴, 코, 눈, 입에대한학습데이터를로드한다.//////////////////

extern "C" FACEDETECT_DLL_TYPE void InitFaceDetecting()

{

        faseCascade = (CvHaarClassifierCascade *) cvLoad("haarcascade_frontalface_alt.xml", 0, 0, 0);

        noseCascade = (CvHaarClassifierCascade *) cvLoad("haarcascade_mcs_nose.xml", 0, 0, 0);

        leftEyeCascade = (CvHaarClassifierCascade *) cvLoad("haarcascade_mcs_lefteye.xml", 0, 0, 0);

        rightEyeCascade = (CvHaarClassifierCascade *) cvLoad("haarcascade_mcs_righteye.xml", 0, 0, 0);

        mouthCascade = (CvHaarClassifierCascade *) cvLoad("haarcascade_mcs_mouth.xml", 0, 0, 0);

 

        storage = cvCreateMemStorage(0);

}

 

//////////////////////////로드한학습데이터를해제한다.//////////////////////////

extern "C" FACEDETECT_DLL_TYPE void EndFaceDetecting()

{

        cvReleaseHaarClassifierCascade( &mouthCascade );

        cvReleaseHaarClassifierCascade( &rightEyeCascade );

        cvReleaseHaarClassifierCascade( &leftEyeCascade );

        cvReleaseHaarClassifierCascade( &noseCascade );

        cvReleaseHaarClassifierCascade( &faseCascade );

 

        cvReleaseMemStorage( &storage );

}

 

////////////////////////얼굴의각요소들을검출해낸다./////////////////////////

extern "C" FACEDETECT_DLL_TYPE FaceInfo* FaceElementsDetecting( IplImage* image )

{

        FaceInfo* faceInfo = new FaceInfo;

        memset( faceInfo, 0, sizeof(FaceInfo) );

 

        FaceDetecting( image, faceInfo );

 

        if( faceInfo->face != 0 )

        {

               NoseDetecting( image, faceInfo );

               MouthDetecting( image, faceInfo );

               LeftEyeDetecting( image, faceInfo );

               RightEyeDetecting( image, faceInfo );

        }

 

        return faceInfo;

}

///////////////////////////////얼굴을검출한다./////////////////////////////////

void FaceDetecting( IplImage* image, FaceInfo* faceInfo )

{

        //얼굴검출

       CvSeq* tempSeq = cvHaarDetectObjects( image, faseCascade, storage, 1.2, 2, CV_HAAR_DO_CANNY_PRUNING, cvSize(0, 0) );

 

        //얼굴의사각영역을구함.

        CvRect* tempRect = (CvRect*)cvGetSeqElem(tempSeq, 0);

 

        if( tempRect != 0 )

        {

               faceInfo->face = new CvRect;

               *faceInfo->face = *tempRect;

        }

}

 

//////////////////////////////코를검출한다.///////////////////////////////////

void NoseDetecting( IplImage* image, FaceInfo* faceInfo )

{

        //관심영역지정

        CvRect roiFace = { faceInfo->face->x, faceInfo->face->y + faceInfo->face->height/4 * 2,

               faceInfo->face->width, faceInfo->face->height/4 * 2};

 

        cvSetImageROI( image, roiFace );     

 

        //관심영역내에서코를검출

       CvSeq* tempSeq = cvHaarDetectObjects( image, noseCascade, storage, 1.2, 2, CV_HAAR_DO_CANNY_PRUNING, cvSize(0, 0) );

 

        //코의사각영역을구함.

        CvRect* tempRect = (CvRect*)cvGetSeqElem(tempSeq, 0);       

       

        if( tempRect != 0 )

        {

               faceInfo->nose = new CvRect;

 

               tempRect->x += faceInfo->face->x;

               tempRect->y += faceInfo->face->y + faceInfo->face->height/4 * 2;

 

               *faceInfo->nose = *tempRect;

        }

 

        cvResetImageROI(image);

}

 

 

///////////////////////////////입을검출한다.//////////////////////////////////

void MouthDetecting( IplImage* image, FaceInfo* faceInfo )

{

        //관심영역지정

        CvRect roiFace = { faceInfo->face->x, faceInfo->face->y + ( faceInfo->face->height/12 ) * 9,

               faceInfo->face->width, faceInfo->face->height/12 * 3 };

 

        cvSetImageROI( image, roiFace );     

 

        //관심영역내에서입을검출

        CvSeq* tempSeq = cvHaarDetectObjects( image, mouthCascade, storage, 1.2, 2, CV_HAAR_DO_CANNY_PRUNING, cvSize(0, 0) );

 

        //입의사각영역을구함.

        CvRect* tempRect = (CvRect*)cvGetSeqElem(tempSeq, 0);       

 

        if( tempRect != 0 )

        {

               faceInfo->mouth = new CvRect;

 

               tempRect->x += faceInfo->face->x;

               tempRect->y += faceInfo->face->y + ( faceInfo->face->height/12 ) * 9;

 

               *faceInfo->mouth = *tempRect;

        }

 

        cvResetImageROI(image);

}

 

//////////////////////////////왼쪽눈을검출한다.//////////////////////////////

void LeftEyeDetecting( IplImage* image, FaceInfo* faceInfo )

{

        //관심영역지정

        CvRect roiFace = { faceInfo->face->x, faceInfo->face->y + ( faceInfo->face->height/4 ) ,

               faceInfo->face->width / 2, faceInfo->face->height/4 };

 

        cvSetImageROI( image, roiFace );

 

        //관심영역내에서왼쪽눈을검

        CvSeq* tempSeq = cvHaarDetectObjects( image, leftEyeCascade, storage, 1.2, 2, CV_HAAR_DO_CANNY_PRUNING, cvSize(0, 0) );

 

        //왼쪽눈의사각영역을구함

        CvRect* tempRect = (CvRect*)cvGetSeqElem(tempSeq, 0);       

 

        if( tempRect != 0 )

        {

               faceInfo->leftEye = new CvRect;

 

               tempRect->x += faceInfo->face->x;

               tempRect->y += faceInfo->face->y + ( faceInfo->face->height/4 );

 

               *faceInfo->leftEye = *tempRect;

        }

 

        cvResetImageROI(image);

}

 

///////////////////////////////오른쪽눈을검출한다/////////////////////////////

void RightEyeDetecting( IplImage* image, FaceInfo* faceInfo )

{

        //관심영역지정

        CvRect roiFace = { faceInfo->face->x + faceInfo->face->width/2,

               faceInfo->face->y + ( faceInfo->face->height/4 ) , faceInfo->face->width/2, faceInfo->face->height/4 };

 

        cvSetImageROI( image, roiFace );

 

        //관심영역내에서오른쪽눈을검출

        CvSeq* tempSeq = cvHaarDetectObjects( image, rightEyeCascade, storage, 1.2, 2, CV_HAAR_DO_CANNY_PRUNING, cvSize(0, 0) );

 

        //오른쪽눈의사각영역을구함

        CvRect* tempRect = (CvRect*)cvGetSeqElem(tempSeq, 0);

 

        if( tempRect != 0 )

        {

               faceInfo->rightEye = new CvRect;

 

               tempRect->x += faceInfo->face->x + faceInfo->face->width/2;

               tempRect->y += faceInfo->face->y + ( faceInfo->face->height/4 );

 

               *faceInfo->rightEye = *tempRect;

        }

 

        cvResetImageROI(image);

}

 

/////////FaceElementsDetecting 함수로부터반환받은메모리를해제시킨다./////////

extern "C" FACEDETECT_DLL_TYPE void ReleaseFaceInfo( FaceInfo** faceInfo )

{

        delete (*faceInfo)->face;

        delete (*faceInfo)->leftEye;

        delete (*faceInfo)->mouth;

        delete (*faceInfo)->nose;

        delete (*faceInfo)->rightEye;

        delete *faceInfo;

}

 

 

 

예제 소스

#include "cv.h"

#include "highgui.h"

 

#include "FaceDetect.h"

 

//이미지에사각영역을그린다.

void RectDrow( IplImage* image, const CvRect* rect )

{

        CvPoint pt1 = { rect->x, rect->y };

        CvPoint pt2 = {(rect->x + rect->width), (rect->y + rect->height)};

        cvRectangle(image, pt1, pt2, CV_RGB(255, 0, 0), 2, 8, 0);

}

 

void main()

{

        cvNamedWindow( "FaceDetect", CV_WINDOW_AUTOSIZE );

        CvCapture* capture = cvCaptureFromCAM(0);                    //카메라로부터영상을캡쳐한다.

        IplImage* frame;

        char c;

 

        //얼굴인식시작

        InitFaceDetecting();

 

        FaceInfo* faceInfo;

 

        while(true)

        {

               cvGrabFrame( capture );                  //카메라로부터

               frame = cvRetrieveFrame(capture);  //프레임이미지를받는다.

 

               faceInfo = FaceElementsDetecting( frame );   //얼굴요소를검출한다.

 

               //얼굴, 눈, 코, 입이 모두 검출됐다면

               if(faceInfo->face != 0 && faceInfo->leftEye != 0                            && faceInfo->mouth != 0 && faceInfo->nose != 0 && faceInfo->rightEye != 0)

               {

                       RectDrow( frame, faceInfo->face );    //얼굴을그린다.

                       RectDrow( frame, faceInfo->nose );    //코를그린다.

                       RectDrow( frame, faceInfo->mouth );   //입을그린다.

                       RectDrow( frame, faceInfo->leftEye ); //왼쪽눈을그린다.

                       RectDrow( frame, faceInfo->rightEye );       //오른쪽눈을그린다.

               }

 

               //프레임을윈도우에출력한다.

               cvShowImage("FaceDetect", frame);

 

                                     

               c = cvWaitKey(33);                                                 

               if(c == 27)            //ESC를누르면종료한다.

               {

                       break;

               }

 

               ReleaseFaceInfo( &faceInfo );

        }

 

        //얼굴인식종료

        EndFaceDetecting();

 

        cvReleaseCapture( &capture );

        cvDestroyWindow( "FaceDetect" );

}

'OpenCV' 카테고리의 다른 글

[C/C++/MFC/OpenCV] 얼굴 및 눈 영역 검출  (0) 2016.07.22
Comments