文章目录
BOW模型运用到图像检索
进行图像检索的时候,我们可以用穷举的方法,但是一一匹配效率太过低,工作量过大,于是参考文本信息检索的模型,提取特征点进行降维处理。在文本信息检索中,BOW模型假定对于一个文档,忽略它的单词顺序和语法、句法等要素,将其仅仅看作是若干个词汇的集合,文档中每个单词的出现都是独立的,不依赖于其它单词是否出现。也就是说,文档中任意一个位置出现的任何单词,都不受该文档语意影响而独立选择的。
一、BOW的原理以及基本流程
1.特征提取
将描述子空间量化成一些典型实例,并将图像中的每个描述子指派到其中的某个实例中。对图像库里的图像进行SITF特征提取,SIFT原理和方法这里不再介绍。这些典型实例可以通 过分析训练图像集确定,并被视为视觉单词。所有这些视觉单词构成的集合称为视觉词汇,有时也称为视觉码本。对于给定的问题、图像类型,或在通常情况下仅需 呈现视觉内容,可以创建特定的词汇。
第一步是提取所有图像的特征,称之为“视觉词汇”,将他们聚集在一起,此时他们还是未分类的。
2.“视觉词典(visual vocabulary)”的构造
我们用SIFT算法从图像中提取不变特征点,作为视觉词汇,并构造单词表,用单词表中的单词表示一幅图像。相当于给每一张图像打上一个标记(一张身份证)
“视觉词典(visual vocabulary)”的构造的过程就是一个图像分类的过程。这里我们用的图像分类方法是K-means聚类方法,当然不局限于这一种分类方法,比如对于文本分类而言,支持向量机(SVM)是一个可靠的选择。。
K-means算法流程:
- 随机初始化 K 个聚类中心
- 重复下述步骤直至算法收敛:
对应每个特征,根据距离关系赋值给某个中心/类别
对每个类别,根据其对应的特征集重新计算聚类中心
可以看到再用K-means算法的时候,你需要人为设置分类数目,体现在下面这段代码(cocabulary.py)的train()函数,(其中“1000”是我的码本数目,“10”表示降采样,我每个10个特征点取一次),这里需要思考一个问题:如何选择码本的大小?
太少:视觉单词无法覆盖所有可能出现的情况
太多: 计算量大,容易过拟合
常用参数设置:视觉单词数量(K-means算法获取的聚类中心)一般为 K=3000-100000,即图像整体描述的直方图维度为 3000~10000。我们要不断尝试,找到相对来说最适合的分类数目,最合适的意思是,你的分类比较正确。
假设Dictionary词典的Size为3000,即有3000个词。那么咱们可以用K-means算法对所有的patch进行聚类,k=3000,我们知道,等k-means收敛时,我们也得到了每一个cluster最后的质心,那么这3000个质心(维数128)就是词典里的3000个词了,词典构建完毕。
`
def train(self,featurefiles,k=100,subsampling=10):
“”" Train a vocabulary from features in files listed
in featurefiles using k-means with k number of words.
Subsampling of training data can be used for speedup. “”"
nbr_images = len(featurefiles)
# read the features from file
descr = []
descr.append(sift.read_features_from_file(featurefiles[0])[1])
descriptors = descr[0] #stack all features for k-means
for i in arange(1,nbr_images):
descr.append(sift.read_features_from_file(featurefiles[i])[1])
descriptors = vstack((descriptors,descr[i]))
# k-means: last number determines number of runs
self.voc,distortion = kmeans(descriptors[::subsampling,:],k,1)
self.nbr_words = self.voc.shape[0]
# go through all training images and project on vocabulary
imwords = zeros((nbr_images,self.nbr_words))
for i in range( nbr_images ):
imwords[i] = self.project(descr[i])
nbr_occurences = sum( (imwords > 0)*1 ,axis=0)
self.idf = log( (1.0*nbr_images) / (1.0*nbr_occurences+1) )
self.trainingdata = featurefiles
`
3. 针对输入特征集,根据视觉词典进行量化
利用单词表的中词汇表示图像。利用SIFT算法,可以从每幅图像中提取很多个特征点,这些特征点都可以用单词表中的单词近似代替,通过统计单词表中每个单词在图像中出现的次数,可以将图像表示成为一个n维数值向量。但是考虑到很大概率实际会发生这种情况:
通常,在每篇文本中,如“这”“和”“是”这类词出现的概率比较大,但是他们对于区别不同的文本并没有多大的作用,所以在单词计数时会忽略掉这些常用词,这些常用词称为停用词。于是我们为了提高匹配的精度,给每个特征点都赋上权重。
通过单词计数来构建文档直方图向量v,从而建立文档索引。通常,在单词计数时会忽略掉一些常用词,如“这”“和”“是”等,这些常用词称为停用词。由于每篇文档长度不同,故除以直方图总和将向量归一化成单位长度。对于直方图向量中的 每个元素,一般根据每个单词的重要性来赋予相应的权重。通常,数据集(或语料库)中一个单词的重要性与它在文档中出现的次数成正比,而与它在语料库中出现的次数成反比。
最常用的权重是 tf-idf(term frequency-inverse document frequency,词频- 逆向文档频率 ),单词 w 在文档 d 中的词频是:
nw 是单词 w 在文档 d 中出现的次数。为了归一化,将 nw 除以整个文档中单词的总数。
逆向文档频率为:
|D| 是在语料库D 中文档的数目,分母是语料库中包含单词w 的文档数d。将两者 相乘可以得到矢量 v 中对应元素的 tf-idf 权重。所以再下一步把输入图像转化成视觉单词(visual words) 的频率直方图时,我们不能简单地把特征点作为唯一标准,要降低那些比重较大的、影响实验结果的的特征。不过我后来再其他地方发现了这个,原来有可以直接调用的 tf-idf
可以使用scikit-learn中的TfidfVectorizer来完成这项任务,它将文本转换为术语频率乘以逆文档频率(tf-idf)值的矩阵,此方法适用于机器学习。另外,在这个过程中可以删除停用词&#x