在大型的图像数据库上,CBIR(基于内容的图像搜索)技术用于检索在视觉上具有相似性的图像。返回的图像可以是颜色相似、纹理相似、图像中的物体或场景相似;总之是可以在这些图像上找到共有的任何信息。对于高层查询,比如寻找相似物体,将查询图像与数据库中所有图像进行完全比较(比如特征匹配)往往是不可行。在数据库很大的情况下,这样的查询方式会耗费很多时间,通过前任的不懈努力,已经成功引入文本挖掘技术到BOW中,解决了数百万图像中搜索具有相似内容的图像成为可能的问题。
目录
图像检索
前言
(一)环境说明及安装
(二)基于BOW图像检索原理
(1)基于内容的图像检索
(2)创建视觉单词
(3)建立图像索引
(4)搜索图像
(三)代码运行流程
(四)测试
(五)在wb端演示图像查询
(五)代码及图像下载
1.ptyhon3.7版本,wins10 64位,IDLE运行编译;
2.vlfeat-0.9.20版本,vlfeat的win64里的vl.dll和sift.exe和vl.lib复制在项目里,同时注意把PCV包放在项目下
3.安装PyQt5
方法(1)窗口键+R,输入cmd进入命令窗口,输入命令语句:pip install PyQt5 ;但是自动导入的方法速度很慢,需要下载很长时间,不建议使用此方法;
方法(2)进入官网链接下载:https://pypi.org/project/PyQt5/#files ,选择图截图下适合自己电脑安装配置的版本,因为我安装的是python3.7,电脑环境是win10 64位,所以下载的是:PyQt5-5.12.2-5.12.3-cp35.cp36.cp37.cp38-none-win_amd64.whl ,下载完成后再进入到命令行窗口,输入命令语句:pip install PyQt5-5.12.2-5.12.3-cp35.cp36.cp37.cp38-none-win_amd64.whl ,建议使用此方法,安装方便。
4.安装cherrypy:直接在命令窗口输入:pip install cherrypy
5.需加入文件service.conf,并用记事本打开修改文件内容为自己项目所在的路径。例如我的项目路径在文件test7下:E:\Python37_course\test7。
下载连接: service.conf文件下载
提取码:01ty
到此环境安装完成。
从文本挖掘中获取灵感——矢量空间模型
矢量空间模型(也称BOW模型)是一个用于表示和搜索文本文档的模型。BOW模型基本上可以用于任何对象类型,包括图像。这些矢量是由文本词频直方图构成,即矢量包含了每个单词出现的次数,而且在其他地方包含很多0元素。BOW模型是忽略了单词出现的顺序及位置。
通过单词计数来构成文档直方图向量,从而建立文档索引。由于每篇文档长度不同,故以直方图总和和将向量归一化成单位长度。对于直方图向量中的每个元素可根据每个单词的重要性赋予相应的权重,通常数据集中的一个单词的重要性与它在文档中出现的次数成正比,与在数据集出现次数成反比。
1.SIFT算法提取特征,创建视觉单词词汇
对于计算机而言,不能同人一样具有主观意识对图像之间进行区分,而无法把两张相似或不相似的图片进行区分,这时就需要进行机器学习,学习 “视觉词典(visual vocabulary)对图像进行“身份证”标记,即进行图像特征提取,而目前比较通用的提取方法为sift描述算子进行特征提取,从而标记每张图片,达到唯一标识。特征点的提取主要是针对图像的关键部分提取,sift算法优点就在于对一些特殊点提取比较敏感,例如:sift算法对图像旋转、尺度缩放、亮度变化具有保持不变性,对视角变化、仿射变换、噪声有一定稳定性,即特征点取的是一些边缘角点、亮点等等。
sift原理参考博文:https://blog.csdn.net/weixin_43837871/article/details/88604483
2.建立视觉单词
为了将文本挖掘技术运用到图像中,首先要建立视觉等效单词;可以采用SIFT局部描述算子获得,针对输入特征集,根据视觉词典进行量化。建立视觉单词的思想就是将描述算子空间量化成一些典型实例,并将图像中的每个描述算子指派到其中的某个实例中,这些典型实例可通过分析训练图像集确定。即从一个很大的训练集提取特征描述算子,利用一些聚类算法可以构建出视觉单词(聚类算法最常用的是K-means),视觉单词是在给定特征描述算子空间中一组向量集,采用K-means进行聚类得到的聚类质心;把输入图像,根据TF-IDF转化成视觉单词( visual words)的频率直方图 ,用视觉单词直方图来表示图像。如图下所示:
1.建立数据库
在索引前,需要建立一个数据库。对图像进行索引是从图像中提取描述子,利用词汇将描述子转换成视觉单词,并保存视觉单词及对应图像的单词直方图。从而可以利用图像对数据库进行查询,并返回相似的图像。这里使用了SQlite作为数据库,SQlite对应的python版本是pysqlite。因为我使用的是python3版本,python3自带sqlite3。
2.添加图片
建立图像数据库,就需要加入图像,实现方法为在pcv包的imagesearch.py 文件里的add_to_index()方法;此方法主要是获取一幅带有特征描述子的图像,投影到词汇上添加进数据库中。
1.利用索引获取候选图像
利用建立起来的索引找到包含特定的所有图像,即相似物体、相似的脸、相似颜色等;为了获得包含多个单词的候选图像,例如一个单词直方图中全部非零元素,在每个单词上进行遍历,得到包含改单词的图像列表,合并这些列表。然后创建一个元组列表有单词id和次数构成,其中次数以候选列表中每个单词出现的次数为准。同时还以元组中的第二个元素为准进行排序。最后会得到一个包含图像id的列表,排在列表最前面的是最好的匹配图像。
2.用一幅图像进行查询
利用一副图像进行查询是没必要进行完全的搜索,对了比较单词直方图,需要从数据库中读入图像单词直方图,检索每个单词直方图及候选图像列表,对于每个候选图像,用标准的欧式距离比较它和查询图像间的直方图,返回一个已经排好序的的元组列表。
1.对每张图片生成相应的.sift文件,及视觉词汇,以便建立BOW模型。我所用的是图像集为26张。如果需要增加图像或减少只需要改代码里读取训练图像的数量。
代码如下:
# -*- coding: utf-8 -*-
import pickle
from PCV.imagesearch import vocabulary
from PCV.tools.imtools import get_imlist
import sift
#获取图像列表
#imlist = get_imlist('E:/Python37_course/test7/first1000/')
imlist = get_imlist('E:/Python37_course/test7/images/')
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)
voc = vocabulary.Vocabulary('test77_test')
voc.train(featlist, 26, 10)
#保存词汇
# saving vocabulary
'''with open('E:/Python37_course/test7/first1000/vocabulary.pkl', 'wb') as f:
pickle.dump(voc, f)'''
with open('E:/Python37_course/test7/images/vocabulary.pkl', 'wb') as f:
pickle.dump(voc, f)
print ('vocabulary is:', voc.name, voc.nbr_words)
运行结果:
同时生成了数据模型vocabulary.pkl,如果数据模型为空,在后面存入数据库会出现报错,读入数据为空。
2.将上面得到的数据模型存放数据库testImaAdd.db中,即运行下面代码会生成一个testImaAdd.db数据库文件。
# -*- coding: utf-8 -*-
import pickle
from PCV.imagesearch import imagesearch
from PCV.localdescriptors import sift
import sqlite3
from PCV.tools.imtools import get_imlist
#获取图像列表
#imlist = get_imlist('E:/Python37_course/test7/first1000/')
imlist = get_imlist('E:/Python37_course/test7/images/')
nbr_images = len(imlist)
#获取特征列表
featlist = [imlist[i][:-3]+'sift' for i in range(nbr_images)]
# load vocabulary
#载入词汇
'''with open('E:/Python37_course/test7/first1000/vocabulary.pkl', 'rb') as f:
voc = pickle.load(f)'''
with open('E:/Python37_course/test7/images/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)[:1000]:
for i in range(nbr_images)[:26]:
locs,descr = sift.read_features_from_file(featlist[i])
indx.add_to_index(imlist[i],descr)
# commit to database
#提交到数据库
indx.db_commit()
con = sqlite3.connect('testImaAdd.db')
print (con.execute('select count (filename) from imlist').fetchone())
print (con.execute('select * from imlist').fetchone())
运行结果:
如果出现上面情况,说明已经生成一个数据库,如果需要再生成一个需要,把之前的数据库文件删除,或者重新生成另外一个库即换一个库名。建议直接删除。删除后,运行结果就会在项目下生成一个DB文件。
出现数据库没有创建成功,就需要查看代码,在读取图像数目有没有与建立的图像数据库数匹配对;
建立图像数据库成功后,就可以进行图像查询测试一下结果。代码如下:
# -*- coding: utf-8 -*-
import pickle
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('E:/Python37_course/test7/first1000/')
imlist = get_imlist('E:/Python37_course/test7/images/')
nbr_images = len(imlist)
#载入特征列表
featlist = [imlist[i][:-3]+'sift' for i in range(nbr_images)]
#载入词汇
'''with open('E:/Python37_course/test7/first1000/vocabulary.pkl', 'rb') as f:
voc = pickle.load(f)'''
with open('E:/Python37_course/test7/images/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 = 0
nbr_results = 20
# 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[:8]) #常规查询
imagesearch.plot_results(src,res_geom[:8]) #重排后的结果
运行结果:
查询图像在最左边,后面都是按图像列表检索的前几幅图像。对输出的结果,首先是载入图像列表、特征列表及词汇。然后创建一个Searcher对象,执行定期查询,并将结果保存在res_reg列表中,然后载入res_reg列表中每一幅图像特征,并和查询的图像进行匹配。当隐形通过计算匹配数和计数内点数得到,最终可通过减少内点数目对包含图像索引和内点数的字典进行排序。最后可视化检索靠前的匹配图像结果。
对于常规查询结果可重拍后的查询结果来说,重排后的查询结果会比常规查询结果更为准确些,重排用单应性进行拟合建立RANSAC模型,再导入候选图像特征进行排序查询;常规查询只是进行了简单的索引和查询,找到相似即可。
对于图像查询,可通过建立演示,在web网页上操作。一下直接附上代码,运行即可。当然在运行此代码时,需要加入文件service.conf,否则会报错。
按照前面环境安装说明,成功修改service.conf的路径为自己项目路径后,运行结果如下:
然后进入网页,输入http://127.0.0.1:8080,查看检索结果。第一张为查询图像。
链接:代码+图像下载
提取码:kgni