基于BOW的图像检索

一、图像检索

1.1 图像检索原理概述

图像检索,简单的说便是从图片检索数据库中检索出满足条件的图片,图像检索技术的研究根据描述图像内容方式的不同可以分为两类:一类是基于文本的图像检索技术,一类为基于内容的图像检索技术。它最早用于对于文章内容的检索,原理是将文本看作是单词的集合,不考虑其中的语法,上下文等等。通过建立词典,对每个单词出现次数进行统计,以便得到文本内容的分类。计算机视觉的专家从中获得灵感,将其用于图像的检索中,就有了Bag Of Features。

1.2 实现图像检索的步骤

1.特征提取
2.采用K-means算法学习“视觉词典”(visual vocabulary)
3.针对输入特征集,根据视觉词典进行量化
4.把输入图像,根据TF-IDF转化成视觉单词( visual words)的频率直方图
5.构造特征到图像的倒排表,通过倒排表快速索引相关图像
6.根据索引结果进行直方图匹配

特征提取
之前学习了关于特征提取的几个方式,例如sift,Harris脚点。这里通过SIFT来提取图像的特征点。类似BOW,我们将图像看成一个由各种图像块组成的集合,通过特征提取,获得图像的关键图像特征。

学习视觉词典
通过步骤1,得到了多张图像的特征点。这些特征并没有进行分类,其中有的特征点之间是极其相似,所以通过K-means聚类算法,将我们提取出来的特征点进行分类处理。
K-Means算法基本流程:
随机初始化 K 个聚类中心
重复下述步骤直至算法收敛:

  • 对应每个特征,根据距离关系赋值给某个中心/类别
  • 对每个类别,根据其对应的特征集重新计算聚类中心

聚类是学习视觉词典的重点操作。将聚类出来的聚类中心称为视觉单词(codevector)。而将视觉单词组成的集合称为视觉词典/码本(codebook)。
注意:关于码本的大小

  • 如果我们做出来的码本规模太小, 就会出现,我们的视觉单词不能包括所有可能的情况。
  • 相反的,如果我们做出来的码本规模过大,会使得计算量增加,且有过拟合现象出现。

根据TF-IDF转化成频率直方图
在这里插入图片描述

  • 其中分子表示某个特征在总的特征出现的次数,分母表示总特征的数量,所以tf表示某个特征出现的频率。

在这里插入图片描述

  • 其中的分子表示全部的图像数量,分母表示某个特征在总的图像下出现的次数。

在转换为频率直方图时候,使用到TF-IDF(即词频与逆文档频率乘积)作为权值。引入这个权值的目的是为了降低一些重复特征所带来的影响。比如在BOW中,一些常用词汇比如the,it,do等等词汇,不能体现文本内容特征,但是出现频率却很高,利用tf-idf可以降低这种不必要词汇的影响。同理,在BOF图像搜索中,图像之间也会有这样的无意义的特征出现,所以需要降低这类特征的权值。

二、具体实现

2.1 选用数据集

该数据集共包含150张图片,展示部分数据集如下:
在这里插入图片描述

2.2 实现代码

2.2.1 生成代码所需要的模型文件

生成视觉词典:

# -*- 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('C:/meitu/')
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, 30, 10)
#保存词汇
# saving vocabulary
with open('C:/meitu/vocabulary.pkl', 'wb') as f:
    pickle.dump(voc, f)
print ('vocabulary is:', voc.name, voc.nbr_words)
  • 对应151张图像生成了151个sift文件,并且生成了视觉词典:
    在这里插入图片描述
  • kmeans聚类得到的pkl文件:
    在这里插入图片描述
2.2.2 将模型数据导入数据库
# -*- 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('C:/meitu/')
nbr_images = len(imlist)
# 获取特征列表
featlist = [imlist[i][:-3] + 'sift' for i in range(nbr_images)]

# load vocabulary
# 载入词汇
'''with open('E:/Python37_course/test7/first1000/vocabulary1.pkl', 'rb') as f:
    voc = pickle.load(f)'''
with open('C:/meitu//vocabulary4.pkl', 'rb') as f:
    # voc = pickle.load(f)
    voc = pickle.load(f, encoding='iso-8859-1')
# 创建索引
indx = imagesearch.Indexer('testImaAdd4.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)[:1000]:
    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('testImaAdd4.db')
print(con.execute('select count (filename) from imlist').fetchone())
print(con.execute('select * from imlist').fetchone())
  • 运行后在代码文件夹之下生成了一个数据库文件:
    在这里插入图片描述
2.2.3 进行测试
# -*- coding: utf-8 -*-
import pickle
# import sift
from PCV.imagesearch import imagesearch
from PCV.geometry import homography
from PCV.tools.imtools import get_imlist
from PIL import Image
# from pylab import *
from PCV.localdescriptors import sift
from PCV.localdescriptors import harris

# load image list and vocabulary
# 载入图像列表
# imlist = get_imlist('E:/Python37_course/test7/first1000/')
imlist = get_imlist('C:/meitu//')
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('C:/meitu//vocabulary1.pkl', 'rb') as f:
    voc = pickle.load(f, encoding='iso-8859-1')

src = imagesearch.Searcher('testImaAdd1.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):', str(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[:5])  # 常规查询
imagesearch.plot_results(src, res_geom[:5])  # 重排后的结果

主要是对比两种查询方式:

  • 常规查询
  • 用单应性进行拟合建立RANSAC模型

测试图片:
在这里插入图片描述
控制台输出的查询到的图片索引值:
在这里插入图片描述在这里插入图片描述

2.3 不同k-means维度的实现结果

不同k-means的维度分别生成对应的pkl文件和数据库文件:
在这里插入图片描述
在这里插入图片描述
kmeans聚类时选取维度不同得到不同结果
测试图片:
在这里插入图片描述

2.3.1 30维

常规查询:
在这里插入图片描述
RANSAC查询:
在这里插入图片描述

2.3.2 50维

常规查询:
在这里插入图片描述
RANSAC查询:
在这里插入图片描述

2.3.3 1000维

常规查询:
在这里插入图片描述
RANSAC查询:
在这里插入图片描述
小结:

  • 通过比较不同K-means聚类维度检索出来的匹配结果中可以看出,维度较小的匹配结果比维度高的错误率高。维度越高,图片检索的准确度越高。
  • 观察发现常规查询的查询结果匹配度高于重排后的查询,重排后查询会降低准确率。可能原因是重排用到了Ransac算法,Ransac算法能有效剔除错配,但它同样可能删去正确的匹配特征,由此导致了检索结果不准确。

三、实验总结

1、 通过改变数据集可以发现有两种情况测试结果相对好一些:(1)特征明显的图片(2)数据集中出现次数较多的图片
2、通过得到的结果发现测试正确率并不是很好

  • 使用k-means聚类,除了其K和初始聚类中心选择的问题外,对于数据大的数据集,输入矩阵的巨大将使得内存溢出及效率低下。
  • 字典大小的选择也是问题,字典过大,单词缺乏一般性,对噪声敏感,计算量大,关键是图象投影后的维数高;字典太小,单词区分性能差,对相似的目标特征无法表示。

3、由上面实验结果对比,可以看出整体结果不理想,查询图片是罗马斗兽场,结果出来的是其他图片。可能由于数据集的构建不正确,存在大量特征相似的建筑且较为集中。这也说明此算法在一些检测程度上效果还不足,这说明可能在创建词汇上,特征描述相似,还不够准确独特,这就需要深入研究。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值