一:整体思路
数据库建立:
1. 提取图像的SIFT特征
2. 将所有特征集合起来进行Kmeans聚类
3. 求出各个聚类的聚类中心并存入文件(高版本的opencv的Kmeans无需此步骤)
4. 记录下每个图片文件的聚类词频 ( FIle1 : class1: n1 class2: n2 class3.......)
5. 建立倒排索引表 ( class1: file1: n1 file2: n2 file3:.....)
查询:
1. 提取文件的SIFT特征
2. 对每一个特征与kmeans中心匹配,求出匹配的class ,并根据匹配程度做权值记录表。
3. 根据权值表和倒排索引表求出最佳匹配项
二:环境搭建
1. opencv1.0
2. gsl
下载连接:点击打开链接
具体配置问度娘,此处略过!
三: 部分代码实现
1. 提取sift特征向量
struct feature* featTemp;
featTemp->feat_num = sift_features( img, &featTemp ); export_features(fileName,featTemp,featTemp->feat_num);
2. Kmeans聚类
CvMat *samples=cvCreateMat(featNum, 128, CV_32FC1); //包含所有图片的所有feature信息的矩阵,featureNum个feature,每个feature为dims(128)维向量,每一维的元素类型为32位浮点数
CvMat *clusters=cvCreateMat(featNum, 1, CV_32SC1); //每个feature所在“质心”的指针(实际上本例程中没有用到该信息)
//CvMat *centers=cvCreateMat(cluster_count, 128, CV_32FC1); //“质心”信息的数组,k个“质心”每个质心都是dims(128)维向量,每一维的元素类型为32位浮点数
cvSet(clusters,cvScalar(1,0,0,0),0);
cvSet(centers,cvScalar(1,0,0,0),0);
//获取sift特征文件列表
getFilePathArray("*.feature");
if (fileListHead == NULL)
{
printf("please makeLib first");
return 0;
}
filelist = fileListHead;
do
{
n = import_features(filelist->name, FEATURE_LOWE, &featTemp); //导入feature文件,n为导入的
for(i = 0; i < n; i++)
{
for(j = 0; j < 128; j++)
{
samples->data.fl[temp++] = featTemp[i].descr[j];
}
}
}while( filelist->next != NULL && (filelist = filelist->next) );
cvKMeans2(samples, cluster_count, clusters,cvTermCriteria(CV_TERMCRIT_EPS,10,1.0) ); //Kmeans聚类3. 建立倒排索引表
//最大图片数量 超出则需要修改数组大小 #define MAX_LIB_PIC 500 //聚类目标类种 #define MAX_MEANS 1024
//创建feature字典,并保存到文件中
//feature[]:数组中存储每一个文件的特征个数
int createKeyWordList(CvMat *samples,CvMat *clusters,const char* filename,int feature[],int featureNum)
{
int loop = 0, loop2 = 0,whichFile = 0,key;
int keyWordList[MAX_LIB_PIC][MAX_MEANS] = {0} ;
int dictionary[MAX_MEANS][MAX_LIB_PIC] = {0};
int ave[MAX_MEANS] = {0};
int avePic[MAX_LIB_PIC] = {0};
FILE* fp,*word;
fp = fopen( filename , "w" );
if ( fp == NULL )
{
printf("createKeyWordList file writr error ");
}
//求出每一个文件feature的词频
for ( loop = 0 ; loop < featureNum ; loop++)
{
if ( loop >= feature[whichFile] )
{
whichFile ++;
}
keyWordList[whichFile][ clusters->data.i[loop] ]++;
}
// 将词频转化为百分率占比
for ( loop2 = 0 ; loop2 < MAX_LIB_PIC ; loop2++ )
{
for ( loop = 0 ; loop < MAX_MEANS ; loop++ )
{
avePic[loop2] += keyWordList[loop2][loop];
}
}
for ( loop = 0 ; loop < MAX_MEANS ; loop++ )
{
for ( loop2 = 0 ; loop2 < MAX_LIB_PIC ; loop2++ )
{
if (avePic[loop2] != 0)
{
dictionary[loop][loop2] = keyWordList[loop2][loop] * 10000 /avePic[loop2];
}
}
}//建立倒排索引
for ( loop = 0 ; loop < MAX_MEANS ; loop++ )
{
for ( loop2 = 0 ; loop2 < MAX_LIB_PIC ; loop2++ )
{
ave[loop] += dictionary[loop][loop2];
}
}
for ( loop = 0 ; loop < MAX_MEANS ; loop++ )
{
fprintf(fp,"%d ", loop + 1);
for ( loop2 = 0 ; loop2 < MAX_LIB_PIC ; loop2++ )
{
fprintf(fp," %d:%d ", loop2 + 1 , dictionary[loop][loop2]*10000/ave[loop] );
//fprintf(fp," %d:%d ", loop2 + 1 , dictionary[loop][loop2]);
}
fprintf(fp,"\n");
}
fclose(fp);
}4. 查询图像特征
float macheImageFeat[MAX_MEANS] = {0};int MakeMatch(const char* filename , struct kd_node* kd_root)
{
struct feature *match , *copy;
struct feature** nbrs;
int k , i , count = 0,num;
double d0, d1;
match = (struct feature*)malloc(sizeof(struct feature));
_getcwd(feature_Path,_MAX_PATH);
num = import_features(filename,FEATURE_LOWE,&match);
memset(macheImageFeat,0, MAX_MEANS * sizeof(float) );
for( i = 0; i < num ; i++ )
{
copy = match + i ;
k = kdtree_bbf_knn( kd_root, copy, 2, &nbrs, KDTREE_BBF_MAX_NN_CHKS );
if ( k == 2 )
{
d0 = descr_dist_sq( copy, nbrs[0] );
d1 = descr_dist_sq( copy, nbrs[1] );
//printf("distens : d0 --- %f d1 --- %f d1 - d0 --- %f %f \n" , d0 , d1 , d1 * NN_SQ_DIST_RATIO_THR - d0);
if( d0 < d1 * NN_SQ_DIST_RATIO_THR )
{
count++;
match[i].fwd_match = nbrs[0];
macheImageFeat[i] = 1 - ( d0 /d1 );// 求出特征权值
}
}
free( nbrs );
}
printf("There are %d feature matchs with the picture %s\n",count,filename);
return count;
}
5. 求出最佳匹配图片
int getMaxMatch( float lable[] , int dictionary[MAX_MEANS][MAX_LIB_PIC]){
int loop,loop2,result,num = 1,temp;
int target[3] = {0};
float ret[MAX_LIB_PIC] = {0} ;
for ( loop2 = 0 ; loop2 < MAX_LIB_PIC ; loop2++ )
{
for ( loop = 0 ; loop < MAX_MEANS ; loop++ )
{
ret[loop2] += dictionary[ loop ][ loop2 ] * lable[loop] ;//lable就是求出的<span style="font-family: Arial, Helvetica, sans-serif;">macheImageFeat</span>
}
}
result = 0;
for ( loop2 = 0 ; loop2 < MAX_LIB_PIC ; loop2++ )
{
if ( result < ret[loop2] )
{
result = ret[loop2] ;
num = loop2 + 1;
}
}
printf("The match picture is %d : %f matchs\n",num,ret[num - 1]);
return num;//图片的序列号
}大功告成。
目前对学校建筑物图片就行测试,图片库大概20张左右,准确率为100%。
随时随地看视频