Bag of features(Bof)一种是用于图像和视频检索的算法,此算法的神奇之处,就在于对于不同角度,光照的图像,基本都能在图像库中正确检索。Bof,即Bag of features,中文翻译为“词袋”,是一种用于图像或视频检索的技术。而检索就要进行比对。两幅不同的图像如何比对,比对什么,这就需要提炼出每幅图像中精练的东西出来进行比较。正如超市中的条形码,就能很好的反映出一件商品的所有特征。因此概括的来说,bof就是生成每幅图像的“条形码”来进行检索。
实验中,我们有一个包含100幅图像的小型图像库。然后再拿一些图像进行query,来找出库中与之对应的图像。
1.首先,我们用sift算法生成图像库中每幅图的特征点及描述符。
2.再用k-means算法对图像库中的特征点进行训练,生成类心。
3.生成每幅图像的BOF,具体方法为:判断图像的每个特征点与哪个类心最近,最近则放入该类心,最后将生成一列频数表,即初步的无权BOF。
4.通过tf-idf对频数表加上权重,生成最终的bof。(因为每个类心对图像的影响不同。比如超市里条形码中的第一位总是6,它对辨别产品毫无作用,因此权重要减小)。
5.对query进来的图像也进行3.4步操作,生成一列query图的BOF。
6.将query的Bof向量与图像库中每幅图的Bof向量求夹角,夹角最小的即为匹配对象。
本次实验准备了100张图片,来源于附近的景观,以及网络上面的图片。在实验开始前最好进行图片压缩,以方便后续的运行,否则速度将会很慢。同样也可以选择网络上的数据集直接进行操作。
# -*- 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('D:/pycharm/untitled1/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('D:/pycharm/untitled1/vocabulary.pkl', 'wb') as f:
pickle.dump(voc, f)
print 'vocabulary is:', voc.name, voc.nbr_words
先将整个图片集的所有图片进行特征提取,生成一整个视觉词典。
# -*- 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('D:/pycharm/untitled1/image/') # 存放数据集的路径
nbr_images = len(imlist)
# nbr_images = 300
# 获取特征列表
featlist = [imlist[i][:-3] + 'sift' for i in range(nbr_images)]
# 载入词汇
with open('D:/pycharm/untitled1/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()
这里将提取到的特征值放入视觉字典后并将其连接到数据库,将一开始的整个数据集转成数据库,以方便后面的查询。
这里需要运用到新的库–sqlite库,利用sqlist库进行数据的存储和链接。因此在该部分运行前,需要先下载sqlite库。
# -*- 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('D:/pycharm/untitled1/image/') # 存放数据集的路径
nbr_images = len(imlist)
# nbr_images = 300
# 载入特征列表
featlist = [imlist[i][:-3]+'sift' for i in range(nbr_images)]
# 载入词汇
with open('D:/pycharm/untitled1/vocabulary.pkl', 'rb') as f: # 存放模型的路径
voc = pickle.load(f)
src = imagesearch.Searcher('testImaAdd.db', voc)
imlist = get_imlist('D:/pycharm/untitled1/image/') # 存放数据集的路径
# 查询图像索引和查询返回的图像数
q_ind = 030 # 查询图片的索引
nbr_results = 5
# 常规查询(按欧式距离对结果排序)
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[:5]) # 常规查询
imagesearch.plot_results(src, res_geom[:5]) # 重排后的结果
在以上建立了索引的情况下,可以进行图像的检索,输入需要检索的图片,跟整个数据集中的图片进行对比,挑出与该张图片较为匹配的五张图。
1、实验图片:
实验结果:
实验出来了与要进行索引的图片最为相近的五张图
经过ransac算法进行索引,显示最为接近的五张图
2、实验图片:
实验出来了与要进行索引的图片最为相近的五张图
经过ransac算法进行索引,显示最为接近的五张图
从上述的结果中,可以看到第一组所得检测结果较为准确,但是第二组实验中的匹配结果出现了误差,5张图片中出现了一种不符合匹配的图片。可能是因为数据集中的建筑比较多,图片的背景都是蓝色,大致相似,因此导致了结果的不准确。这也说明此算法在一些检测程度上效果还不足,这说明可能在创建词汇上,特征描述相似,还不够准确独特,这就需要深入研究了。此次实验数据集只含100张图片,可以扩大数据集来进行更进一步的研究。
在本次实验中,运用到了sqlite库,python2.7的版本可以到https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyopengl进行相应版本的下载,利用pip install pysqlite-2.8.3-cp27-cp27m-win_amd64.whl进行库的下载。
**注意:**在使用pip进行库的安装时,需要进入到该库所在的文件目录下面,否则系统找不到该文件会提示错误。