# 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;
}
'차근차근 > OpenCV' 카테고리의 다른 글
참고자료 (0) | 2014.08.04 |
---|---|
error LNK2019: _main 외부 기호(참조 위치: ___tmainCRTStartup 함수)에서 확인하지 못했습니다. (0) | 2014.07.31 |
error C2057: 상수 식이 필요합니다. (0) | 2014.07.30 |
3 일에 만드는 고속 특정 물체 인식 시스템 (1) 물체 인식 시스템 (0) | 2014.07.30 |
3 일에 만드는 고속 특정 물체 인식 시스템 (2) SIFT 특징 량 추출 (0) | 2014.07.30 |