BOW即Bag of words,在上篇文章(浅析Bag-of-words及Bag-of-features)中我们有解释它的原理及应用,这里就不讲了。
本篇文章主要讲的是基于BOW实现的图像检索。
目录
一、实验内容
二、实现步骤
(1)选用数据集
(2)具体实现
1、创建词汇
2、创建图像索引
3、在数据库中搜索图像
三、实现结果
四、实验总结
五、pysqlite库安装方法
如题,检索在视觉上具有相似性的图像,可以是颜色相似、纹理相似、图像中的物体或场景相似。本实验是实现图像检索。
实现主要分三个部分
1、创建词汇
2、创建图像索引
3、在数据库中搜索图像
首先介绍下本实验采用的数据集,图片不多,只有184张
可以采用一些比较正规的识别数据集,可以使数据集大些
我们要为我们的数据集里的图片创建视觉单词词汇,首先载入图像列表,利用SIFT提取特征描述子,获取特征列表,创建Vocabulary对象生成并保存词汇。
# -*- coding: utf-8 -*
import pickle
from PCV.imagesearch import vocabulary
from PCV.tools.imtools import get_imlist
from PCV.localdescriptors import sift
# 要记得将PCV放置在对应的路径下
# 获取图像列表
imlist = get_imlist('E:\\study_work\\python\\image\\') # 存放数据集的路径
nbr_images = len(imlist) # 获取数据集的长度
# nbr_images = 300 # 可以是自己选择用多少张图片作为训练数据集
# 获取特征列表
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('imglltest')
voc.train(featlist, 300, 10)
# 保存词汇
with open('E:\\study_work\\python\\image\\vocabulary.pkl', 'wb') as f:
pickle.dump(voc, f)
print 'vocabulary is:', voc.name, voc.nbr_words
这里解释一下生成词汇部分
Vocabulary是调用PCV下imagesearch中的文件vocabulary.py,该文件代码的作用是创建一个词汇类,以及在训练图像数据集上训练出一个词汇。其中包含了一个有单词聚类中心与每个单词对应的逆向文档频率构成的向量。该词汇类中还包含了train()函数。
train()函数是从文件中读取特征然后将所有特征并在一起,以便进行K-means聚类,遍历所有的训练图像,这是Bag of features过程的前三步工作---提取特征和学习“视觉词典”并且对视觉词典进行量化。train()方法获取包含有.sift描述子文件列表和词汇单词数k(聚类中心数),在K-means聚类过程中容易使用过多特征,所以对训练数据进行下采样加快训练速度。
最后采用pickle模块中保存词汇表(码本),pickle.dump(voc, f)是将词汇写入到.pkl文件中。
因为本部分有数据库操作,使用了python中的pysqlite库,pysqlite库需要自己安装,后面也有附安装教程。
本部分主要实现目的是将模型数据导入数据库。照常先载入图像列表、特征列表及词汇,创建Indexer类对象利用数据库创建图像索引。
# -*- 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
# 要记得将PCV放置在对应的路径下
# 获取图像列表
imlist = get_imlist('E:\\study_work\\python\\image\\') # 存放数据集的路径
nbr_images = len(imlist)
# nbr_images = 300
# 获取特征列表
featlist = [imlist[i][:-3]+'sift' for i in range(nbr_images)]
# 载入词汇
with open('E:\\study_work\\python\\image\\vocabulary.pkl', 'rb') as f: # 读取再上一步中保存的.pkl文件
voc = pickle.load(f)
# 创建索引
index = imagesearch.Indexer('testImaAdd.db', voc) # 创建数据库
index.create_tables() # 创建数据库表单
# 遍历所有的图像,并将它们的特征投影到词汇上
for i in range(nbr_images)[:300]:
locs, descr = sift.read_features_from_file(featlist[i])
index.add_to_index(imlist[i], descr)
# 提交到数据库
index.db_commit()
con = sqlite.connect('testImaAdd.db') # 连接到数据库
print con.execute('select count (filename) from imlist').fetchone() # 数据库操作
print con.execute('select * from imlist').fetchone()
在这里解释下imagesearch调用的方法
imagesearch.Indexer('testImaAdd.db', voc) 是指调用imagesearch中的索引器Indexer类,初始化(连接上数据库,初始化词汇对象之后调用了Indexer类里create_tables()函数,create_tables()用于创建数据库表单及一些索引用以加快搜索速度,里面包含了图像文件名、词汇、单词直方图。add_to_index(imlist[i], descr)作用是在索引中添加没有被索引的图像。获取图像id(图像文件名的id号)及单词(将描述子投影到词汇上,创建单词直方图),将每个单词和图像链接起来,然后存储图像的单词直方图。最后就是保存所有数据库操作,将更改写入数据库文件。
在前面我们已经建立了图像索引,现在就可以在数据库中搜索相似的图像了。本部分创建了Searcher对象,执行定期查询,并将结果保存在res_reg列表中,然后载入res_reg列表中每一副图像的特征,并和查询图像进行匹配。最终获得排序好的检索结果图像。
# -*- 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
# 要记得将PCV放置在对应的路径下
# 载入图像列表
imlist = get_imlist('E:\\study_work\\python\\image\\') # 存放数据集的路径
nbr_images = len(imlist)
# nbr_images = 300
# 载入特征列表
featlist = [imlist[i][:-3]+'sift' for i in range(nbr_images)]
# 载入词汇
with open('E:\\study_work\\python\\image\\vocabulary.pkl', 'rb') as f: # 存放模型的路径
voc = pickle.load(f)
src = imagesearch.Searcher('testImaAdd.db', voc)
# 查询图像索引和查询返回的图像数
q_ind = 40 # 查询图片的索引
nbr_results = 6
# 常规查询(按欧式距离对结果排序)
res_reg = [w[1] for w in src.query(imlist[q_ind])[:nbr_results]]
print 'top matches (regular):', res_reg
# 载入查询图像特征
q_locs, q_descr = sift.read_features_from_file(featlist[q_ind])
fp = homography.make_homog(q_locs[:, :2].T)
# 用单应性进行拟合建立RANSAC模型
model = homography.RansacModel()
rank = {}
# 载入候选图像的特征
for ndx in res_reg[1:]:
locs, descr = sift.read_features_from_file(featlist[ndx])
# 获取匹配数
# get matches执行完后会出现两张图片
matches = sift.match(q_descr, descr)
ind = matches.nonzero()[0]
ind2 = matches[ind]
tp = homography.make_homog(locs[:, :2].T)
# 计算单应性,对内点技术。如果没有足够的匹配书则返回空列表
try:
H, inliers = homography.H_from_ransac(fp[:, ind], tp[:, ind2], model, match_theshold=4)
except:
inliers = []
# 存储内点数
rank[ndx] = len(inliers)
# 将字典排序,以首先获取最内层的内点数
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]) # 重排后的结果
在这里我们运用到了imagesearch中的Searcher类,常规查询时调用了query()方法,此方法作用是获取查询图像的文件名,检索其单词直方图和与候选图像列表(即其具有相似单词直方图的图像列表)。利用单词索引获得候选集,然后在候选集上进行逐一比较。对每个候选图像,都用标准的欧氏距离度量它和查询图像直方图的相似性,并按照相似性程度大小排序,返回排序后的距离及对应数据库ids大小,排在列表最前的是最好的匹配图像。
(1)第一组
(2)第二组
(3)第三组
(4)第四组
(5)第五组
由上面三组实验结果对比,可以看出第一组和第二组所得检测结果准确,六张图像都是同一人物或建筑。但这也不排除是因为实验数据集中的人物建筑类型较少的原因。第三组实验的查询图片尚大楼(集美大学),检测结果中包含了其他建筑的图片,不过结果大致是准确。这可能是由于数据集不够大(此次实验数据集只含184张图片),可以将扩大数据集。所以这里又采用了肯塔基大学物体识别数据集(有1000张图片,且图像类型丰富)做了第四组、第五组实验,第四组查询图片是书,结果显示能够准确检测出相似结果。而第五组的查询图片是兔子,结果出来的是其他图片。这也说明此算法在一些检测程度上效果还不足,这说明可能在创建词汇上,特征描述相似,还不够准确独特,这就需要深入研究了。
如果是python2.7的同学可以直接打开cmd命令行输入命令:
也可以前往https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyopengl里下载
如果是python3.0以上版本,这里要感谢实验室大佬的辛苦劳作~
这里附上链接:https://pan.baidu.com/s/1ry1BvDGk7ILuteCb134BgQ 提取码:1ose
此文件里包含了图像检索代码、工具包以及实验数据集(first1000),如果是python2.7版本的可直接用博客上的代码。
好啦,就此ending~请大家多多指教