目录
- [1 基于内容的图像检索(CBIR)](#1 基于内容的图像检索(CBIR))
- [2 视觉单词](#2 视觉单词)
- [3 图像索引](#3 图像索引)
-
- [3.1 建立数据库](#3.1 建立数据库)
- [3.2 添加图像](#3.2 添加图像)
- [4 在数据库中搜索图像](#4 在数据库中搜索图像)
-
- [4.1 利用索引获取候选图像](#4.1 利用索引获取候选图像)
- [4.2 用一幅图像进行查询](#4.2 用一幅图像进行查询)
- [4.3 确定对比基准并绘制结果](#4.3 确定对比基准并绘制结果)
1 基于内容的图像检索(CBIR)
CBIR技术用于检索在视觉上具相似度的图像。返回的图像可以是颜色相似,纹理相似,图像中的物体或场景相似。
过去几年里,成功地引入文本挖掘技术到CBIR中处理问题,使得在数百万图像中搜索具有相似内容的图像成为可能。
- 从文本挖掘中获取灵感------矢量空间模型
矢量空间模型是一个用于表示和搜索文本文档的模型。这些矢量是由文本词频直方图构成的。矢量包含了每个单词出现的次数,而且在其他别的地方包含很多0元素。因为该模型忽略了单词出现的顺序以及位置,也被称为BOW表示模型。
使用单词计数来构建文档直方图向量v,建议文档索引。在单词计数中会忽略类似"这","和","是"等常用词,这些常用词被称为停用词。向量需要除以直方图总和将向量归一化为单位长度。对于向量中的不同元素,根据单词的重要性赋予权重。一个单词的重要性与它在文档中出现的次数成正比,与在语料库中出现的次数成反比。
最常用权重是tf-idf,单词w在文档d中的词频是:
t f w , d = n w ∑ j n j \mathrm{tf}{w,d}=\frac{n_w}{\sum_jn_j} tfw,d=∑jnjnw
n w n_w nw是单词 w w w在文档 d d d 中出现的次数。为了归一化,将 n w n_w nw 除以整个文档中单词的总数。
逆向文档频率为:
i d f w , d = log ∣ ( D ) ∣ ∣ { d : w ∈ d } ∣ \mathrm{idf}{w,d}=\log\frac{|(D)|}{|\{d\colon w\in d\}|} idfw,d=log∣{d:w∈d}∣∣(D)∣
∣ D ∣ \left|D\right| ∣D∣是在语料库 D D D中文档的数目,分母是语料库中包含单词 w w w的文档数 d d d。将两者相乘可以得到矢量 ν \nu ν中对应元素的 tf-idf 权重。
2 视觉单词
首先需要建立视觉等效单词,可以使用SIFT局部描述子做到,思想是将描述子空间量化为一些典型示例,将图像中的每个描述子指派到某个实例中。典型示例可通过分析训练图像集确定,被视为视觉单词。视觉单词构成集合称为视觉词汇(视觉码本)。
从一个集提取特征描述子,利用聚类算法构建出视觉单词。采用K-means进行聚类得到的视觉单词是聚类质心。用视觉单词直方图表示图像,称BOW模型。
- 创建词汇
首先提取特征描述子,使用SIFT特征描述子。使用代码得到每幅图像的描述子。将图像的描述子保存在文件Vocabulary.pkl中。
python
import pickle
import sift
from PCV.imagesearch import vocabulary
from PCV.tools.imtools import get_imlist
from PCV.localdescriptors import sift
#获取图像列表
imlist = get_imlist('C:/Users/23232/Desktop/PCV.geometry/first1000')
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])
#生成词汇
voc = vocabulary.Vocabulary('ukbenchtest')
voc.train(featlist, 1000, 10)
#保存词汇
# saving vocabulary
with open('Vocabulary.pkl', 'wb') as f:
pickle.dump(voc, f)
print ('vocabulary is:', voc.name, voc.nbr_words)
得到了词汇对象文件。
3 图像索引
该过程是建立图像数据库和图像的视觉单词表示。
3.1 建立数据库
对图像进行索引是从这些图像中提取描述子,利用词汇将描述子转换为视觉单词,保存视觉单词及对应图像的单词直方图。
使用SQList作为数据库,该数据库将所有的信息保存在一个文件。SQList使用SQL查询语言。
先创建表,索引和索引器Indexer类,将图像数据写入数据库。
创建imagesearch.py文件,将下列代码写入:
python
import pickle
from pysqlite2 import dbapi2 as sqlite
class Indexer(object):
def __init__(self,db,voc):
self.con = sqlite.connect(db)
self.voc = voc
def __del__(self):
self.con.close()
def db_commit(self):
self.con.commit()
def create_tables(self):
""" 创建数据库表单"""
self.con.execute('create table imlist(filename)')
self.con.execute('create table imwords(imid,wordid,vocname)')
self.con.execute('create table imhistograms(imid,histogram,vocname)')
self.con.execute('create index im_idx on imlist(filename)')
self.con.execute('create index wordid_idx on imwords(wordid)')
self.con.execute('create index imid_idx on imwords(imid)')
self.con.execute('create index imidhist_idx on imhistograms(imid)')
self.db_commit()
使用pickle模块将数组编码成字符串以及将字符串进行解码。Indexer 类连接数据库,并且一旦创建 (调用_init_()方法)后就可以保存词汇对象。del ()方法可以确保关闭数据库连接,db commit()可以将更改写入数据库文件。
表单imlist包含索引的图像文件名,imwords包含单词的单词索引,用到了哪些词汇,单词出现在哪些图像,imhistograms包含了每幅图像的单词直方图。
3.2 添加图像
基于数据库表单,可以在索引中添加图像,add_to_index()方法来实现该功能。
python
def add_to_index(self,imname,descr):
""" Take an image with feature descriptors,
project on vocabulary and add to database. """
if self.is_indexed(imname): return
print('indexing', imname)
imid = self.get_id(imname)
imwords = self.voc.project(descr)
nbr_words = imwords.shape[0]
for i in range(nbr_words):
word = imwords[i]
self.con.execute("insert into imwords(imid,wordid,vocname) values (?,?,?)", (imid,word,self.voc.name))
self.con.execute("insert into imhistograms(imid,histogram,vocname) values (?,?,?)", (imid,pickle.dumps(imwords),self.voc.name))
上述代码获得图像文件名和Numpy数组(包含在图像中找到的描述子)使用辅助函数is_indexed()检查图像是否已经索引,get_id()对一幅图像文件名给定id号。
python
def get_id(self,imname):
""" Get an entry id and add if not present. """
cur = self.con.execute(
"select rowid from imlist where filename='%s'" % imname)
res=cur.fetchone()
if res==None:
cur = self.con.execute(
"insert into imlist(filename) values ('%s')" % imname)
return cur.lastrowid
else:
return res[0]
def is_indexed(self,imname):
""" Returns True if imname has been indexed. """
im = self.con.execute("select rowid from imlist where filename='%s'" % imname).fetchone()
return im != None
接下来遍历ukbench数据库中的样本图像,将其加入索引。
python
import pickle
import sift
from PCV.imagesearch import vocabulary
from PCV.tools.imtools import get_imlist
from PCV.localdescriptors import sift
from PCV.imagesearch import imagesearch
import sqlite3
#获取图像列表
imlist = get_imlist('C:/Users/23232/Desktop/PCV.geometry/first1000')
nbr_images = len(imlist)
#获取特征列表
featlist = [imlist[i][:-3]+'sift' for i in range(nbr_images)]
with open('Vocabulary.pkl', 'rb') as f: # 读取再上一步中保存的.pkl文件
voc = pickle.load(f)
# 创建索引
index = imagesearch.Indexer('test2.db', voc) # 创建数据库
index.create_tables() # 创建数据库表单
# 遍历所有的图像,并将它们的特征投影到词汇上
for i in range(nbr_images)[:1000]:
locs, descr = sift.read_features_from_file(featlist[i])
index.add_to_index(imlist[i], descr)
# 提交到数据库
index.db_commit()
con = sqlite3.connect('test2.db') # 连接到数据库
print(con.execute('select count (filename) from imlist').fetchone()) # 数据库操作
print(con.execute('select * from imlist').fetchone())
4 在数据库中搜索图像
建立完图像的索引后,可以在数据库中搜索相似的图像。使用BOW来表示整个图像。
通过将Search类添加到imagesearch.py中。
python
class Searcher(object):
def __init__(self,db,voc):
""" 初始化数据库的名称 """
self.con = sqlite.connect(db)
self.voc = voc
def __del__(self):
self.con.close()
Search对象连接到数据库,删除就关闭连接。
利用单词索引获得候选集,然后再候选集上进行逐一比较。
4.1 利用索引获取候选图像
利用索引找到包含特定单词的所有图像,是对数据库做简单的查询。
首先再Search类中加入candidates_from_word()方法:
python
def candidates_from_word(self,imword):
""" G 获取包含 imword 的图像列表"""
im_ids = self.con.execute(
"select distinct imid from imwords where wordid=%d" % imword).fetchall()
return [i[0] for i in im_ids]
给出了包含特定单词的所有图像id号。通过再每个单词上进行便利获得包含多个单词的候选图像。
candidates_from_histogram方法显示有多少单词与单词直方图中的单词匹配。
python
def candidates_from_histogram(self,imwords):
""" 获取具有相似单词的图像列表"""
words = imwords.nonzero()[0]
candidates = []
for word in words:
c = self.candidates_from_word(word)
candidates+=c
tmp = [(w,candidates.count(w)) for w in set(candidates)]
tmp.sort(cmp=lambda x,y:cmp(x[1],y[1]))
tmp.reverse()
return [w[0] for w in tmp]
使用如下代码从索引中查找出前10个图像id
python
import sift
from PCV.imagesearch import vocabulary
from PCV.tools.imtools import get_imlist
from PCV.localdescriptors import sift
from PCV.imagesearch import imagesearch
import sqlite3
#获取图像列表
imlist = get_imlist('C:/Users/23232/Desktop/PCV.geometry/first1000')
nbr_images = len(imlist)
#获取特征列表
featlist = [imlist[i][:-3]+'sift' for i in range(nbr_images)]
f = open('Vocabulary.pkl', 'rb')
voc = pickle.load(f)
f.close()
src = imagesearch.Searcher('test2.db', voc)
locs,descr = sift.read_features_from_file(featlist[0])
iw = voc.project(descr)
print ('ask using a histogram...')
print (src.candidates_from_histogram(iw)[:10])
4.2 用一幅图像进行查询
使用一幅图像进行查询,不需要进行完全的搜索。Searcher类需要从数据库读入图像的单词直方图。
使用如下代码对图像进行查询:
python
src = imagesearch.Searcher('test2.db',voc)
print('try a query...')
print(src.query(imlist[0])[:10])
打印出前10个结果,显示了候选图像与查询图像间距离。
4.3 确定对比基准并绘制结果
可以计算前4个位置中搜索到相似图像数来评价搜索结果的好坏。
将以下代码添加到imagesearch.py中
python
def compute_ukbench_score(src,imlist):
""" 对查询返回的前 4个结果计算平均相似图像数,并返回结果"""
nbr_images = len(imlist)
pos = zeros((nbr_images,4))
for i in range(nbr_images):
pos[i] = [w[1]-1 for w in src.query(imlist[i])[:4]]
score = array([ (pos[i]//4)==(i//4) for i in range(nbr_images)])*1.0
return sum(score) / (nbr_images)