一、基于内容的图像检索
在大型图像数据库上,CBIR(Content-Based Image Retrieval,基于内容的图像检索)技术用于检索在视觉上具相似性的图像。这样返回的图像可以是颜色相似、纹理相似、图像中的物体或场景相似;总之,基本上可以是这些图像自身共有的任何信息。对于高层查询,比如寻找相似的物体,将查询图像与数据库中所有的图像进行完全比较(比如用特征匹配)往往是不可行的。在数据库很大的情况下,这样的查询方式会耗费过多时间。在过去的几年里,研究者成功地入文本挖掘技术到 CBIR 中处理问题,使在数百万图像中搜索具有相似内容的图像成为可能。
1.BOW模型
从文本挖掘中获取灵感——矢量空间模型: 矢量空间模型是一个用于表示和搜索文本文档的模型。我们将看到,它基本上可以应用于任何对象类型,包括图像。该名字来源于用矢量来表示文本文档,这些矢量是由文本词频直方图构成的 1。换句话说,矢量包含了每个单词出现的次数,而且在其他别的地方包含很多 0 元素。由于其忽略了单词出现的顺序及位置,该模型也被称为 BOW 表示模型。
BOW(Bag Of Words) 词袋模型起始可以被理解为一种直方图统计,被应用在文本分类中,将文档表示成特征矢量。它只统计频率信息,并没有序列信息。BOW是选择words字典,然后统计字典中每个单词出现的次数。
2.BOF模型
特征袋BOF是词袋BOW的一种改进,用于图像处理问题。只不过在图像中,我们抽出的不再是一个个word,而是图像的关键特征Feature,所以研究人员将它更名为Bag of Feature。
Bag of features: 基础流程 有了特征之后,我们会将这些特征通过聚类算法得出很多聚类中心。这些聚类中心通常具有较高的代表性。典型的聚类算法有k-means算法。我们将这些聚类中心组合在一起,形成一部字典。
3.K-Means聚类算法
K- Means是迭代动态聚类算法中的一种,其中K表示类别数,Means表示均值。顾名思义K-Means是一种通过均值对数据点进行聚类的算法。K-Means算法通过预先设定的K值及每个类别的初始质心对相似的数据点进行划分。并通过划分后的均值迭代优化获得最优的聚类结果。
K-Means算法流程: 1.随机初始化 K 个聚类中心 2.重复下述步骤直至算法收敛: 3.对应每个特征,根据距离关系赋值给某个中心/类别 4.对每个类别,根据其对应的特征集重新计算聚类中心 对于算法步骤的理解: 第一步是为待聚类的点寻找聚类中心; 第二步是计算每个点到聚类中心的距离,将每个点聚类到离该点最近的聚类中去; 第三步是计算每个聚类中所有点的坐标平均值,并将这个均值作为新的聚类中心; 反复执行第二步、第三步,直到聚类中心不再进行大范围移动或者聚类次数达到要求为止。
4.TF-IDF权重
TF-IDF即词频(Term Frequency,TF)与逆文档频率(Inverse Document Frequency,IDF)的乘积,将此值作为权值,降低一些重复特征所带来的影响。 TF:单词w在文档d的词频(其中分子表示某个特征在总的特征出现的次数,分母表示总特征的数量,所以tf表示某个特征出现的频率。)
通过单词计数来构建文档直方图向量 v,从而建立文档索引。通常,在单词计数时会忽略掉一些常用词,如“这”“和”“是”等,这些常用词称为停用词。由于每篇文档长度不同,故除以直方图总和将向量归一化成单位长度。对于直方图向量中的每个元素,一般根据每个单词的重要性来赋予相应的权重。通常,数据集(或语料库)中一个单词的重要性与它在文档中出现的次数成正比,而与它在语料库中出现的次数成反比。
最常用的权重是 tf-idf(term frequency-inverse document frequency,词频 - 逆向文档频率 ),单词 w 在文档 d 中的词频是: nw 是单词 w 在文档 d 中出现的次数。为了归一化,将 nw 除以整个文档中单词的总数。 逆向文档频率为: |D| 是在语料库 D 中文档的数目,分母是语料库中包含单词 w 的文档数 d。将两者相乘可以得到矢量 v 中对应元素的 tf-idf 权重。
5.倒排表
倒排索引是实现“单词-文档矩阵”的一种具体存储形式,通过倒排索引,可以根据单词快速获取包含这个单词的文档列表。倒排索引主要由两个部分组成:“单词词典”和“倒排文件”。
6.总结:图像检索流程
1.特征提取-SIFT 2.学习 “视觉词典(visual vocabulary)-K-means 3.针对输入特征集,根据视觉词典进行量化 4.输入图像,根据TF-IDF转化成视觉单词(visual words)的频率直方图 5.构造特征到图像的倒排表,通过倒排表快速 索引相关图像 6.根据索引结果进行直方图匹配
二、视觉单词
为了将文本挖掘技术应用到图像中,我们首先需要建立视觉等效单词;这通常可以采用 SIFT 局部描述子做到。它的思想是将描述子空间量化成一些典 型实例,并将图像中的每个描述子指派到其中的某个实例中。这些典型实例可以通过分析训练图像集确定,并被视为视觉单词。所有这些视觉单词构成的集合称为视 觉词汇,有时也称为视觉码本。对于给定的问题、图像类型,或在通常情况下仅需呈现视觉内容,可以创建特定的词汇。从一个(很大的训练图像)集提取特征描述子,利用一些聚类算法可以构建出视觉单词。聚类算法中最常用的是 K-means,这里也将采用 K-means。视觉单词并不高端,只是在给定特征描述子空间中的一组向量集,在采用 K-means 进行聚类时得到的视觉单词是聚类质心。用视觉单词直方图来表示图像,则该模型便称为 BOW 模型。
1.创建词汇
为创建视觉单词词汇,首先需要提取特征描述子。这里,我们使用 SIFT 特征描述子。如前面一样,imlist 包含的是图像的文件名。运行下面的代码,可以得到每幅 图像提取出的描述子,并将每幅图像的描述子保存在一个文件中:
nbr_images = len(imlist)
featlist = [ imlist[i][:-3]+'sift' for i in range(nbr_images)]
for i in range(nbr_images):
sift.process_image(imlist[i],featlist[i])
创建名为 vocabulary.py 的文件,将下面代码添加进去。该代码创建一个词汇类,以及在训练图像数据集上训练出一个词汇的方法:
from scipy.cluster.vq import *
import vlfeat as sift
class Vocabulary(object):
def __init__(self,name):
self.name = name
self.voc = []
self.idf = []
self.trainingdata = []
self.nbr_words = 0
def train(self,featurefiles,k=100,subsampling=10):
""" 用含有k 个单词的 K-means 列出在 featurefiles 中的特征文件训练出一个词汇。对训练数据下
采样可以加快训练速度 """
nbr_images = len(featurefiles)
# 从文件中读取特征
descr = []
descr.append(sift.read_features_from_file(featurefiles[0])[1])
descriptors = descr[0] # 将所有的特征并在一起,以便后面进行 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: 最后一个参数决定运行次数
self.voc,distortion = kmeans(descriptors[::subsampling,:],k,1)
self.nbr_words = self.voc.shape[0]
# 遍历所有的训练图像,并投影到词汇上
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
def project(self,descriptors):
""" 将描述子投影到词汇上,以创建单词直方图 """
# 图像单词直方图
imhist = zeros((self.nbr_words))
words,distance = vq(descriptors,self.voc)
for w in words:
imhist[w] += 1
return imhist
Vocabulary 类包含了一个由单词聚类中心 VOC 与每个单词对应的逆向文档频率构成的向量,为了在某些图像集上训练词汇,train() 方法获取包含有 .sift 描后缀的述 子文件列表和词汇单词数 k。在 K-means 聚类阶段可以对训练数据下采样,因为如果使用过多特征,会耗费很长时间。 现在在你计算机的某个文件夹中,保存了图像及提取出来的 sift 特征文件,下面的代码会创建一个长为 k ≈ 1000 的词汇表。这里,再次假设 imlist 是一个包含了图 像文件名的列表:
import pickle
import vocabulary
nbr_images = len(imlist)
featlist = [ imlist[i][:-3]+'sift' for i in range(nbr_images) ]
voc = vocabulary.Vocabulary('ukbenchtest')
voc.train(featlist,1000,10)
# 保存词汇
with open('vocabulary.pkl', 'wb') as f:
pickle.dump(voc,f)
print 'vocabulary is:', voc.name, voc.nbr_words
三、图像索引
1.建立数据集
2.特征提取生成数据模型
# -*- coding: utf-8 -*-
import pickle
from PCV.imagesearch import vocabulary
from PCV.tools.imtools import get_imlist
from PCV.localdescriptors import sift
# 获取图像列表
imlist = get_imlist('D:\\Luo-\\Picture')
nbr_images = len(imlist)
# 获取特征列表
featlist = [imlist[i][:-3] + 'sift' for i in range(nbr_images)]
# 提取文件夹下图像的sift特征
for i in range(nbr_images):
sift.process_image(imlist[i], featlist[i])
# 生成词汇
#train的参数为(特征列表,读取图片数,训练数)
voc = vocabulary.Vocabulary('test')
voc.train(featlist, 30, 10)
# 保存词汇
# saving vocabulary
with open('D:\\Luo-\\siftPic\\vocabulary.pkl', 'wb') as f:
pickle.dump(voc, f)
print('vocabulary is:', voc.name, voc.nbr_words)
3.建立图像索引+存放数据模型
在开始之前,需要创建表,索引和索引器indexer类,以便将图像数据写入数据库,将上面得到的数据模型存放数据库.db中。
# -*- coding: utf-8 -*-
import pickle
from PCV.imagesearch import imagesearch
from PCV.localdescriptors import sift
from sqlite3 import dbapi2 as sqlite
from PCV.tools.imtools import get_imlist
#获取图像列表
imlist = get_imlist(r'D:\\Luo-\\Picture')
nbr_images = len(imlist)
#获取特征列表
featlist = [imlist[i][:-3]+'sift' for i in range(nbr_images)]
# load vocabulary
#载入词汇
with open(r'D:\\Luo-\\Picture\\vocabulary.pkl', 'rb') as f:
voc = pickle.load(f)
#创建索引
indx = imagesearch.Indexer('testImaAdd.db',voc)
indx.create_tables()
# go through all images, project features on vocabulary and insert
#遍历所有的图像,并将它们的特征投影到词汇上
for i in range(nbr_images)[:500]:
locs,descr = sift.read_features_from_file(featlist[i])
indx.add_to_index(imlist[i],descr)
# commit to database
#提交到数据库
indx.db_commit()
con = sqlite.connect('testImaAdd.db')
print(con.execute('select count (filename) from imlist').fetchone())
print(con.execute('select * from imlist').fetchone())
生成数据库:
4.测试:匹配/重排
# -*- coding: utf-8 -*-
import pickle
from PCV.localdescriptors import sift
from PCV.imagesearch import imagesearch
from PCV.geometry import homography
from PCV.tools.imtools import get_imlist
# load image list and vocabulary
#载入图像列表
imlist = get_imlist(r'D:\\Luo-\\Picture')
nbr_images = len(imlist)
#载入特征列表
featlist = [imlist[i][:-3]+'sift' for i in range(nbr_images)]
#载入词汇
'''with open('D:\\Luo-\\Picture\\vocabulary.pkl', 'rb') as f:
voc = pickle.load(f)'''
with open(r'D:\\Luo-\\Picture\\vocabulary.pkl', 'rb') as f:
voc = pickle.load(f)
src = imagesearch.Searcher('testImaAdd.db',voc)
# index of query image and number of results to return
#查询图像索引和查询返回的图像数
q_ind = 20
nbr_results = 6
# regular query
# 常规查询(按欧式距离对结果排序)
res_reg = [w[1] for w in src.query(imlist[q_ind])[:nbr_results]]
print ('top matches (regular):', res_reg)
# load image features for query image
#载入查询图像特征
q_locs,q_descr = sift.read_features_from_file(featlist[q_ind])
fp = homography.make_homog(q_locs[:,:2].T)
# RANSAC model for homography fitting
#用单应性进行拟合建立RANSAC模型
model = homography.RansacModel()
rank = {}
# load image features for result
#载入候选图像的特征
for ndx in res_reg[1:]:
locs,descr = sift.read_features_from_file(featlist[ndx]) # because 'ndx' is a rowid of the DB that starts at 1
# get matches
matches = sift.match(q_descr,descr)
ind = matches.nonzero()[0]
ind2 = matches[ind]
tp = homography.make_homog(locs[:,:2].T)
# compute homography, count inliers. if not enough matches return empty list
try:
H,inliers = homography.H_from_ransac(fp[:,ind],tp[:,ind2],model,match_theshold=4)
except:
inliers = []
# store inlier count
rank[ndx] = len(inliers)
# sort dictionary to get the most inliers first
sorted_rank = sorted(rank.items(), key=lambda t: t[1], reverse=True)
res_geom = [res_reg[0]]+[s[0] for s in sorted_rank]
print ('top matches (homography):', res_geom)
# 显示查询结果
imagesearch.plot_results(src,res_reg[:6]) #常规查询
imagesearch.plot_results(src,res_geom[:6]) #重排后的结果
|