标签:word each term end point oca 是什么 with mem
在图像检索时,通常首先提取图像的局部特征,这些局部特征通常有很高的维度(例如,sift是128维),有很多的冗余信息,直接利用局部特征进行检索,效率和准确度上都不是很好。这就需要重新对提取到的局部特征进行编码,以便于匹配检索。
常用的局部特征编码方法有三种:
本文主要介绍基于k-means聚类算法的BoF
的实现。
该方法源自于文本处理的词袋模型。Bag-of-words model (BoW model) 最早出现在NLP和IR领域. 该模型忽略掉文本的语法和语序, 用一组无序的单词(words)来表达一段文字或一个文档. 近年来, BoW模型被广泛应用于计算机视觉中. 与应用于文本的BoW类比, 图像的特征(feature)被当作单词(Word).
例如下面的句子:
John likes to watch movies. Mary likes too. John also likes to watch football games.
就可以构建一个词典
{"John": 1, "likes": 2, "to": 3, "watch": 4, "movies": 5, "also": 6, "football": 7, "games": 8, "Mary": 9, "too": 10}
该字典中包含10个单词, 每个单词有唯一索引, 注意它们的顺序和出现在句子中的顺序没有关联. 根据这个字典, 我们能将上述两句话重新表达为下述两个向量:
[1, 2, 1, 1, 1, 0, 0, 0, 1, 1] [1, 1, 1, 1, 0, 1, 1, 1, 0, 0]
这两个向量共包含10个元素, 其中第i个元素表示字典中第i个单词在句子中出现的次数。
统计词频的时候有两种方法:
特征词袋(BoF,Bag Of Feature)借鉴文本处理的词袋(BoW,Bag Of Bag)算法,将图像表示成视觉关键词的统计直方图。就像上面对文本的处理一样,提取文本中出现单词组成词汇表,这里关键是得到图像库的“词汇表”。为了得到图像库的“词汇表",通常对提取到的图像特征进行聚类,得到一定个数的簇。这些聚类得到的簇,就是图像的”词汇“,可以称为视觉词(Visual Word)。聚类形成的簇,可以使用聚类中心来描述,所以,视觉词指的是图像的局部区域特征(如纹理,特征点)经过聚类形成的聚类中心。
有了视觉词的集合后,就可以将一幅图像表示为\(K\)维的向量(\(K\)为聚类中心的个数,也就是视觉词的个数),向量的每个分量表示某个视觉词在图像中出现的次数。
构建图像的BoF
的步骤如下:以SIFT特征为例
所以聚类在构建BoF
是很重要的一步,接下来简单的介绍下聚类的基本知识以及最常用的聚类算法k-means
算法。
聚类(Clustering)是一种无监督学习算法,其目的是将数据集中的样本划分为若干个不相交的子集,每个子集称为一个簇(Cluster)。聚类的时候并不关心某一类是什么,只根据数据的相似性,将数据划分到不同的组中。每个组内的成员具有相似的性质。
聚类算法说白了就是给你一大堆点的坐标(维度可以是很高),然后通过一个向量的相似性准则(通常是距离,比如欧拉距离),然后把相近的点放在一个集合里面,归为一类。
更正式的说,假设有样本集 \(D = \{x_1,x_2,\dots,x_m\}\)有\(m\)个无标记的样本,每个样本可以使用一个\(n\)维特征向量表示:\(x_i = (x_{i1};x_{i2};\dots;x_{in})\),根据相似的准则,将集合\(D\)划分为\(k\)个不相交的簇\(\{C_l|l = 1,2,\dots,k\}\)。每个簇可以用其聚类中心来描述\(\lambda_l = (x_{l1},x_{l2},\dots,x_{ln}),l = 1,2,\dots,k\).
两个向量的相似性,通常可以使用距离度量,距离越大,相似性越小;距离越小,相似性越大。给定两个样本\(x = (x_1,x_2,\dots,x_n), y = (y_1,y_x,\dots,y_n)\),常用的距离计算有:
以上三种距离可以统称为闵可夫斯基距离 Minkowski distance,\(dist = (\sum_{i=1}^n|x_i-y_i|^p)^{\frac{1}{p}}\)
当然,度量两个向量相似性的方法还有很多种,这里只列举了最常用的,在均值聚类算法中经常的使用的是欧氏距离和曼哈顿距离。
聚类算法可以分为三类:
\(k\)均值聚类是原型聚类的一种,它使用簇内的均值向量来描述每个簇,假设给定的样本集\(D = \{x_1,x_2,\dots,x_m\}\),得到\(k\)个簇,\(C = {C_1,C_2,\dots,C_k}\),\(k\)means算法的目标是使,簇内样本到簇的质心(簇内的均值向量)距离最小
\[
E = \sum_{i=1}^k\sum_{x\in C_i}\|x-u_i\|_2^2,u_i = \frac{1}{|C_i|}\sum x\in C_i
\]
\(u_i\)是簇\(C_i\)的均值向量。\(E\)就表示了簇内样本围绕着均值向量(簇的中心)的紧密程度,\(E\)越小则簇内样本相似度越高。
要使得\(E\)的值最小,是一个NP难题,因此均值聚类使用贪心策略,通过迭代的方法来求解最优解。
均值聚类算法多数是基于Lioyd‘s Algorithm,其流程很简单。首先,随机的确定\(k\)个初始点作为各个簇的质心。然后将数据集中每个点分配到与其最近的质心代表的簇中。然后更新各个簇的质心为该簇所有向量的均值。具体表示如下:
创建k个点作为起始质心(通常随机选择)
当任意一个点所在的簇发生变化时
对数据集中的每个数据点
对每个质心
计算质心与数据点之间的距离
将数据点分配到与其最近的簇中
对每个簇,计算簇中所有点的均值作为新的质心
k-means算法有两个输入参数簇的个数\(k\)以及初始的簇的质心
k-means++
来确定vlfeat实现了三种的k-means算法:
可以使用如下代码来初始化k-means算法:
VlKMeans * fkmeans = vl_kmeans_new(VL_TYPE_FLOAT, VlDistanceL2);
vl_kmeans_set_algorithm(fkmeans, VlKMeansElkan);
vl_kmeans_init_centers_with_rand_data(fkmeans,data,data_dim,data_num,k);
首先设置聚类时的数据类型为float
,相似性度量使用l2
距离也就是欧氏距离;接着设置使用的算法为是Elkan
,并且使用随机的方法确定k
个簇的中心。
初始化完成后,使用如下代码进行聚类
vl_kmeans_cluster(fkmeans, data, data_dim, data_num, k);
需要指定数据,数据的维度,数据的个数以及簇的中心,这里需要注意的是数据的维度。聚类数据的维度指的是,一个数据有几个分量组成。例如,
相较于vlfeat,OpenCV中的kmeans
则更易于调用。
double cv::kmeans(InputArray data,
int K,
InputOutputArray bestLabels,
TermCriteria criteria,
int attempts,
int flags,
OutputArray centers = noArray()
)
KMEANS_RANDOM_CENTERS
随机指定;KMEANS_PP_CENTERS
k-means++;KMEANS_USE_INITIAL_LABELS
算法第一次执行时,使用用户提供的初始质心;第二次及以后的执行使用随机或者半随机的方式初始化质心在OpenCV中TermCriteria
表示迭代算法结束的两种条件:
该类的初始化需要三个参数
COUNT, EPS or COUNT + EPS
在上一篇文章图像检索(1): 再论SIFT-基于vlfeat实现中实现了SIFT
特征点的提取,这里再对提取到的特征点进行聚类,构建图像集的视觉词汇表。
基于SIFT特征构建BoF的步骤:
基于OpenCV的实现如下:
void bof_encode(const string &image_folder,int k,vector<Mat> &bof) {
vector<string> image_file_list;
get_file_name_list(image_folder,image_file_list);
// 提取图像的sift
vector<Mat> descriptor_list;
Ptr<xfeatures2d::SIFT> sift = xfeatures2d::SIFT::create();
for(const string & file: image_file_list){
cout << "Extracte sift feature #" << file << endl;
vector<KeyPoint> kpts;
Mat des;
Mat img = imread(file);
CV_Assert(!img.empty());
sift->detectAndCompute(img,noArray(),kpts,des);
descriptor_list.push_back(des);
}
// 将各个图像的sift特征组合到一起
Mat descriptor_stack;
vconcat(descriptor_list,descriptor_stack);
// 聚类
Mat cluster_centers;
vector<int> labels;
kmeans(descriptor_stack,k,labels,TermCriteria(TermCriteria::EPS + TermCriteria::COUNT,
10, 1.0),3, KMEANS_RANDOM_CENTERS,cluster_centers);
// labels已经得到了每个样本(特征点)所属的簇,需要进行统计得到每一张图像的BoF
int index = 0;
for(Mat img : descriptor_list){
// For all keypoints of each image
auto cluster = new int[k];
for(int i = 0; i < img.rows; i ++){
cluster[labels[index]] ++;
index ++;
}
Mat mat(1,k,CV_32S);
auto ptr = mat.ptr<int>(0);
mempcpy(ptr,cluster,sizeof(int) * k);
bof.push_back(mat);
delete cluster;
}
}
提取特征点后,需要将得到的sift的特征描述子组合到一起,进行聚类,需要用到函数vconcat
,该函数在y方向上将Mat
组合在一起,需要各个Mat
的列是一样,组合得到的Mat
仍然有相同的列;同样的函数hconcat
在水平方向上组合Mat
,组合得到的Mat
的行保持不变。
在聚类后可以得到所有图像的各个sift特征所属的簇,上述代码的:
// labels已经得到了每个样本(特征点)所属的簇,需要进行统计得到每一张图像的BoF
int index = 0;
for(Mat img : descriptor_list){
// For all keypoints of each image
auto cluster = new int[k];
for(int i = 0; i < img.rows; i ++){
cluster[labels[index]] ++;
index ++;
}
Mat mat(1,k,CV_32S);
auto ptr = mat.ptr<int>(0);
mempcpy(ptr,cluster,sizeof(int) * k);
bof.push_back(mat);
delete cluster;
}
就是统计每张图像中,各个Visual Word的个数。这样一幅图像就可以使用一个K
维的向量表示。
标签:word each term end point oca 是什么 with mem
原文地址:https://www.cnblogs.com/wangguchangqing/p/9222267.html