차근차근/OpenCV

ear_recognition.cpp

예쁜꽃이피었으면 2014. 7. 30. 17:48

# include <opencv/cv.h> 

# include <opencv/highgui.h> 

# include <iostream> 

# include <fstream> 

# include <map>


# include "opencv2\nonfree\nonfree.hpp"


//# include <stdio.h>

using  namespace std;


const  int DIM = 128 ;

 const  double DIST_THRESHOLD = 0.25 ;

 const  double VOTE_THRESHOLD = 50 ;

 const  int SURF_PARAM = 400 ;


const  char * IMAGE_DIR = "caltech101_10" ;

 const  char * OBJID_FILE = "object.txt" ;

 const  char * DESC_FILE = "description.txt" ;


// 프로토 타입 

bool loadObjectId ( const  char * filename, map < int , string> & id2name);

 bool loadDescription ( const  char * filename, vector < int > & labels, vector < int > & laplacians, CvMat * & objMat);

 double euclideanDistance ( float * vec, float * mvec, int Length);

 int searchNN ( float * vec, int Lap, vector < int > & labels, vector < int > & laplacians, CvMat * objMat);


int Main ( int argc, char ** argv) {

     double tt = ( double ) cvGetTickCount ();


    // 물체 ID-> 물체 파일 이름의 해시를 생성 

    cout << "물체 ID-> 물체 이름의 해시를 만듭니다 ..." << flush;

    map < int , string> id2name;

     if (! loadObjectId (OBJID_FILE, id2name)) {

        cerr << "cannot load object id file" << endl;

         return  1 ;

    }

    cout << "OK" << endl;


    // 키포인트의 특징 벡터를 objMat 행렬에로드 

    cout << "물체 모델 데이터베이스를로드합니다 ..." << flush;

    vector < int > labels;      // 키 포인트 레이블 (objMat에 해당) 

    vector < int > laplacians;   // 키 포인트 라플라시안 

    CvMat * objMat;            // 각 행이 물체의 키포인트의 특징 벡터 

    if (! loadDescription (DESC_FILE , labels, laplacians, objMat)) {

        cerr << "cannot load description file" << endl;

         return  1 ;

    }

    cout << "OK" << endl;


    cout << "물체 모델 데이터베이스의 물체 회" << id2name.size () << endl;

    cout << "데이터베이스의 키 포인트 :" << objMat-> rows << endl;

    tt = ( double ) cvGetTickCount () - tt;

    cout << "Loading Models Time =" << tt / (cvGetTickFrequency () * 1000.0 ) << "ms" << endl;


    while ( 1 ) {

         // 쿼리 파일의 입력 

        char input [ 1024 ];

        cout << "query?>" ;

        cin >> input;


        char queryFile [ 1024 ];

        _snprintf(queryFile, sizeof queryFile, " % s / % s " , IMAGE_DIR, input);


        cout << queryFile << endl;


        tt = ( double ) cvGetTickCount ();


        // 쿼리 이미지를로드

        IplImage * queryImage = cvLoadImage (queryFile, CV_LOAD_IMAGE_GRAYSCALE);

        if (queryImage == NULL ) {

            cerr << "cannot load image file :" << queryFile << endl;

             continue ;

        }


        // 쿼리에서 SURF 특징 량을 추출 

        CvSeq * queryKeypoints = 0 ;

        CvSeq * queryDescriptors = 0 ;

        CvMemStorage * storage = cvCreateMemStorage ( 0 );

        CvSURFParams params = cvSURFParams (SURF_PARAM, 1 );

cv::initModule_nonfree();//유경추가

        cvExtractSURF (queryImage, 0 , &queryKeypoints, &queryDescriptors, storage, params);

        cout << "쿼리의 키 포인트 :" << queryKeypoints-> total << endl;


        // 쿼리의 각 키포인트 1-NN 물체 ID를 검색하여 투표 

        //int numObjects = (int)id2name.size();    // 데이터베이스의 물체 수 

int numObjects = (int)id2name.size();    // 데이터베이스의 물체 수 

        int * votes = new int[numObjects];   // 각 물체의 수집 득표 수 

for ( int i = 0 ; i <numObjects; i ++) {

            votes [i] = 0 ;

        }


        for ( int i = 0 ; i <queryDescriptors-> total; i ++) {

            CvSURFPoint * p = (CvSURFPoint *) cvGetSeqElem (queryKeypoints, i);

            float * vec = ( float *) cvGetSeqElem (queryDescriptors, i);

             int lap = p-> laplacian;

             int nnId = searchNN (vec, lap, labels, laplacians, objMat);

            votes [nnId] ++;

        }


        for ( int i = 0 ; i <numObjects; i ++) {

            cout << votes [i] << endl;

        }


        // 투표 수가 최대 물체 ID를 요구 

        int maxId = - 1 ;

         int maxVal = - 1 ;

         for ( int i = 0 ; i<numObjects; i ++) {

             if (votes [i]> maxVal) {

                maxId  = i;

                maxVal = votes [i];

            }

        }


        // 물체 ID를 물체 파일명으로 변환

        string name = id2name [maxId];

        cout << "확인 결과 :" << name << endl;


        tt = ( double ) cvGetTickCount () - tt;

        cout << "Recognition Time =" << tt / (cvGetTickFrequency () * 1000.0 ) << "ms" << endl;


        // 뒤처리

delete [] votes;

votes = NULL;

        cvReleaseImage (& queryImage);

        cvClearSeq (queryKeypoints);

        cvClearSeq (queryDescriptors);

        cvReleaseMemStorage (& storage);

        cvDestroyAllWindows ();

    }


    // 뒤처리


    cvReleaseMat (& objMat);




    return  0 ;

}


/** 

* 물체 ID-> 물체 이름의 map을 만들고 반환 

* @ param [in] filename 물체 ID-> 물체 이름의 대응을 저장 한 파일 

* @ param [out] id2name 물체 ID-> 물체 이름 의 map 

* @ return 성공하면 true, 실패하면 false 

*/ 

bool loadObjectId ( const  char * filename, map < int , string> & id2name) {

     // 물체 ID와 물체 이름을 저장 한 파일 열기

    ifstream objFile (filename);

    if (objFile.fail ()) {

        cerr << "cannot open file :" << filename << endl;

         return  false ;

    }


    // 한 줄씩 읽어 들여, 물체 ID-> 물체 이름의 map을 만들

    string line;

    while (getline(objFile, line, '\n' )) {

         // 탭으로 구분 된 문자열을 ldata에 저장

        vector <string> ldata;

        istringstream ss (line);

        string s;

        while (getline (ss, s, '\t' )) {

            ldata.push_back (s);

        }


        // 물체 ID와 물체 이름을 추출하여 map에 저장 

        int objId  = atol (ldata [ 0 ]. c_str ());

        string objName = ldata [ 1 ];

        id2name.insert (map < int , string> :: value_type (objId , objName));

    }


    // 뒤처리

    objFile.close ();


    return  true ;

}


/** 

* 키 포인트 레이블 (추출 물체 ID) 및 라플라시안과 특징 벡터를로드 labels과 objMat에 저장 

* @ param [in] filename 특징 벡터를 저장 한 파일 

* @ param [out] labels 특징 벡터 추출 물체 ID 

* @ param [out] laplacianss 특징 벡터 라플라시안 

* @ param [out] objMat 특징 량을 포함하는 행렬 (행 당 하나의 특징 벡터) 

* @ return 성공하면 true, 실패하면 false 

*/ 

bool loadDescription ( const  char * filename, vector < int > & labels, vector < int > & laplacians, CvMat * & objMat) {

     // 물체 ID와 특징 벡터를 저장 한 파일 열기

    ifstream descFile (filename);

    if (descFile.fail ()) {

        cerr << "cannot open file :" << filename << endl;

         return  false ;

    }


    // 행렬의 크기를 결정하는 키 포인트의 수를 계산 

    int numKeypoints = 0 ;

    string line;

    while (getline(descFile, line, '\n' )) {

        numKeypoints ++;

    }

    objMat = cvCreateMat (numKeypoints, DIM, CV_32FC1);


    // 파일 포인터를 위로 축소

    descFile.clear ();

    descFile.seekg ( 0 );


    // 데이터를 읽어 들여 행렬에 저장 

    int cur = 0 ;

     while (getline (descFile, line, '\n' )) {

         // 탭으로 구분 된 문자열을 ldata에 저장

        vector <string> ldata;

        istringstream ss (line);

        string s;

        while (getline (ss, s ,'\t' )) {

            ldata.push_back (s);

        }

        // 물체 ID를 꺼내 특징 벡터 레이블로하는 

        int objId = atoi (ldata [ 0 ]. c_str ());

        labels.push_back (objId);

        // 라플라시안을 꺼내 들어 

        int laplacian = atoi (ldata [ 1 ]. c_str ());

        laplacians.push_back (laplacian);

        // DIM 차원 벡터의 요소를 행렬에 저장 

        for ( int j = 0 ; j <DIM; j ++) {

             float val = atof (ldata [j + 2 ]. c_str ());   // 특징 벡터 ldata [2] 에서 

            CV_MAT_ELEM (* objMat, float , cur, j) = val;

        }

        cur ++;

    }


    descFile.close ();


    return  true ;

}


/** 

* 두 벡터의 유클리드 거리를 계산하여 반환 

* @ param [in] vec 벡터 1의 배열 

* @ param [in] mvec 벡터 2의 배열 

* @ param [in] length 벡터의 길이 

* @ return 유클리드 거리 

*/ 

double euclideanDistance ( float * vec, float * mvec, int length) {

     double dist = 0.0 ;


    for ( int i = 0 ; i < length; i ++) {

        dist += (vec [i] - mvec [i]) * (vec [i] - mvec [i]);

    }

    dist = sqrt (dist);


    return dist;

}


/** 

* 쿼리의 키포인트 1-NN 키 포인트를 물체 모델 데이터베이스에서 찾고 그 물체 ID를 반환 

* @ param [in] vec 쿼리 키포인트의 특징 벡터 

* @ param [in] lap 쿼리 키 포인트 의 라플라시안 

* @ param [in] labels 물체 모델 데이터베이스의 각 키포인트 물체 ID 

* @ param [in] laplacians 물체 모델 데이터베이스의 각 키 포인트 라플라시안 

* @ param [in] objMat 물체 모델 데이터베이스의 각 키 포인트 특징 벡터 

* @ return 지정된 키 포인트에 가장 가까운 키 포인트 물체 ID 

*/ 

int searchNN ( float * vec, int lap, vector < int > & labels, vector < int > & laplacians, CvMat * objMat) {

     int neighborObj = - 1 ;

     double minDist = 1e6 ;

     for ( int i = 0 ; i <objMat-> rows; i ++) {

         // 쿼리의 키 포인트와 라플라시안이 다른 키포인트는 무시 

        if (lap != laplacians [i]) {

             continue ;

        }

        // i 번째 행의 선두 데이터의 포인터 (여기에서 128 개가 i 번째 행의 특징 벡터) 

        float * mvec = ( float *) (objMat-> data.fl + i * DIM);

         double d = euclideanDistance (vec , mvec, DIM);

         if (d <minDist) {

            neighborObj = labels [i];   // NN 키포인트 물체 ID를 업데이트 

            minDist = d;            // 최소 거리를 업데이트

        }

    }

    return neighborObj;

}


반응형