Created
December 28, 2016 06:17
-
-
Save aidiary/f19440369913d34dd62c26215b09cd84 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cv.h> | |
#include <highgui.h> | |
#include <iostream> | |
#include <fstream> | |
#include <map> | |
using namespace std; | |
const int DIM = 128; | |
const int SURF_PARAM = 400; | |
const char* IMAGE_DIR = "../dataset/caltech101_10"; | |
const char* OBJID_FILE = "../dataset/object_caltech101_10.txt"; | |
const char* DESC_FILE = "../dataset/description_caltech101_10.txt"; | |
// プロトタイプ宣言 | |
bool loadObjectId(const char *filename, map<int, string>& id2name); | |
bool loadDescription(const char *filename, 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 << "物体モデルデータベースをインデキシングします ... " << flush; | |
CvFeatureTree* ft = cvCreateKDTree(objMat); // objMatはコピーされないので解放してはダメ | |
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); | |
cvExtractSURF(queryImage, 0, &queryKeypoints, &queryDescriptors, storage, params); | |
cout << "クエリのキーポイント数: " << queryKeypoints->total << endl; | |
// 投票箱を用意 | |
int numObjects = (int)id2name.size(); // データベース中の物体数 | |
int votes[numObjects]; // 各物体の集めた得票数 | |
for (int i = 0; i < numObjects; i++) { | |
votes[i] = 0; | |
} | |
// クエリのキーポイントの特徴ベクトルをCvMatに展開 | |
CvMat* queryMat = cvCreateMat(queryDescriptors->total, DIM, CV_32FC1); | |
CvSeqReader reader; | |
float* ptr = queryMat->data.fl; | |
cvStartReadSeq(queryDescriptors, &reader); | |
for (int i = 0; i < queryDescriptors->total; i++) { | |
float* descriptor = (float*)reader.ptr; | |
CV_NEXT_SEQ_ELEM(reader.seq->elem_size, reader); | |
memcpy(ptr, descriptor, DIM * sizeof(float)); // DIM次元の特徴ベクトルをコピー | |
ptr += DIM; | |
} | |
// kd-treeで1-NNのキーポイントインデックスを検索 | |
int k = 1; // k-NNのk | |
CvMat* indices = cvCreateMat(queryKeypoints->total, k, CV_32SC1); // 1-NNのインデックス | |
CvMat* dists = cvCreateMat(queryKeypoints->total, k, CV_64FC1); // その距離 | |
cvFindFeatures(ft, queryMat, indices, dists, k, 250); | |
// 1-NNキーポイントを含む物体に得票 | |
for (int i = 0; i < indices->rows; i++) { | |
int idx = CV_MAT_ELEM(*indices, int, i, 0); | |
votes[labels[idx]]++; | |
} | |
// 投票数が最大の物体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; | |
// 後始末 | |
cvReleaseImage(&queryImage); | |
cvClearSeq(queryKeypoints); | |
cvClearSeq(queryDescriptors); | |
cvReleaseMemStorage(&storage); | |
cvDestroyAllWindows(); | |
} | |
// 後始末 | |
cvReleaseFeatureTree(ft); | |
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; | |
} | |
// 1行ずつ読み込み、物体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] objMat 特徴量を格納した行列(各行に1つの特徴ベクトル) | |
* | |
* @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 = atol(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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment