-----------------------------------------------------------------------------
已经提取的SIFT特征文件格式:
<N>:所有图片的数量
<M1>:每一张图片的SIFT特征数
<1>:第一个1个128维sift特征
<2>第二个...
< . >
< . >
<m0>第m0个...
<M2>
.
.
.
<MN>
----------------------------------------------------------------------------
CHistogram.h
#ifndef _C_HISTOGRAM_H
#define _C_HISTOGRAM_H
#include <cv.h>
#include <vector>
const int cnFeatureDimension = 128; //特征向量的维数
const int cnClusterNumber = 100; //K_Means中k的数量
using namespace std;
class CHistogram{
public:
CHistogram():cnImageNumber(0),cnFeatrueNumber(0){};
void ReadFeaturesVector();
void FormHistogram();
void WriteHistogramToFile();
private:
int cnImageNumber; //全部图片的数量
int cnFeatrueNumber; //全部特征的数量
vector<int> everyImageFeatureNumber; //存储每幅图片的特征点数目
//double (*featureArray)[cnFeatureDimension]; //用来把所有特征存储到此数组
vector<vector<double>> featureVector;
//int (*historgram)[cnClusterNumber]; //用来存储生成的直方图
vector<vector<int>> histogramVector;
};
#endif
CHistogram.cpp
#include "CHistogram.h"
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
void CHistogram::ReadFeaturesVector()
{
string filePath("F:\\Documents\\cv\\source code\\myCode\\MySIFT\\");
string fileName;//("myImage.sift");
cout << "Please input the file to read: " << endl;
cin >> fileName;
ifstream infile((filePath+fileName).c_str());
if(!infile)
{
cerr << "Open the file failed!" << endl;
}
infile >> cnImageNumber;
int imageFeatureNum;//表示每幅图像的特征数;
for(int i = 0; i != cnImageNumber; ++i)
{
infile >> imageFeatureNum;
everyImageFeatureNumber.push_back(imageFeatureNum);//统计此图片的特征数量
cnFeatrueNumber += imageFeatureNum;//统计所有特征的数量,聚类时用到
for(int j = 0; j != imageFeatureNum; ++j)
{
vector<double> tempVec(cnFeatureDimension);
for(int k = 0; k < cnFeatureDimension; ++k)
{
infile >> tempVec[k];
}
featureVector.push_back(tempVec);
}
}
//double (*featureArray)[cnFeatureDimension] = new double[cnFeatrueNumber][cnFeatureDimension];
//把存储在vector中的特征向量复制到featureArray数组中
//for(int i = 0; i < tempVec.size(); ++i)
// for(int j = 0; j < cnFeatureDimension; ++j)
// featureArray[i][j] = tempVec[i][j];
}
void CHistogram::FormHistogram()
{
//聚类中心矩阵
CvMat *clusterCenters = cvCreateMat(cnClusterNumber, cnFeatureDimension, CV_32FC1);
//所有特征矩阵
CvMat featureMat;
//必须是float才能进行运算!!!!!!!!!!!!!!!!妹的被坑了!!!!!
float *tempDoubleArray = new float[cnFeatrueNumber * cnFeatureDimension];
//ZeroMemory(tempDoubleArray, sizeof(double) * cnFeatrueNumber * cnFeatureDimension);
for(int i = 0; i < cnFeatrueNumber; ++i)
for(int j = 0; j < cnFeatureDimension; ++j)
tempDoubleArray[i*cnFeatureDimension+j] = featureVector[i][j];
//初始化featureMat----------特别注意:第五个参数必须为一维数组!
cvInitMatHeader(&featureMat, cnFeatrueNumber, cnFeatureDimension, CV_32FC1, tempDoubleArray);
//输出整数向量:每个样本对应的类别标识,在 cnClusterNumber 内。
CvMat *labels = cvCreateMat(cnFeatrueNumber, 1, CV_32SC1);
//函数 cvKMeans2 执行 k-means 算法 搜索 cnClusterNumber 个类别的中心并对样本进行分类,输出 labels(i) 为样本 i 的类别标识。
cvKMeans2(&featureMat, cnClusterNumber, labels,
cvTermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 1, 0.1));
int (*historgram)[cnClusterNumber] = new int[cnImageNumber][cnClusterNumber];
ZeroMemory(historgram, sizeof(int) * cnImageNumber * cnClusterNumber);
int index = 0;//用于访问labels的游标
for(int i = 0; i < cnImageNumber; ++i)
{
for(int j = 0; j < everyImageFeatureNumber[i]; ++j)
{
int *data_ = labels->data.i;
int temp = data_[index++];
//int temp = (labels->data.i)[index++];
++historgram[i][temp];
}
}
for(int i = 0; i < cnImageNumber; ++i)
{
vector<int> tempIntVector;
for(int j = 0; j < cnClusterNumber; j++)
{
tempIntVector.push_back(historgram[i][j]);
}
histogramVector.push_back(tempIntVector);
}
delete[] tempDoubleArray;
delete[] historgram;
cvReleaseMat(&labels);
cvReleaseMat(&clusterCenters);
}
void CHistogram::WriteHistogramToFile()
{
string fileName;
cout << "Please input the file to write: " << endl;
cin >> fileName;
ofstream outfile(fileName.c_str());
outfile << cnImageNumber << endl;
for(int i = 0; i < cnImageNumber; ++i)
for(int j = 0; j < cnClusterNumber; j++)
outfile << histogramVector[i][j] << endl;
}