• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

计算机视觉6BOW的图像检索

武飞扬头像
JRWu
帮助1

一、 简介

最初的Bag of words,也叫做“词袋”,在信息检索中,Bag of words model假定对于一个文本,忽略其词序和语法,句法,将其仅仅看做是一个词集合,或者说是词的一个组合,文本中每个词的出现都是独立的,不依赖于其他词 是否出现,或者说当这篇文章的作者在任意一个位置选择一个词汇都不受前面句子的影响而独立选择的。

Bag-of-words模型是信息检索领域常用的文档表示方法。在信息检索中,BOW模型假定对于一个文档,忽略它的单词顺序和语法、句法等要素,将其仅仅看作是若干个词汇的集合,文档中每个单词的出现都是独立的,不依赖于其它单词是否出现。也就是说,文档中任意一个位置出现的任何单词,都不受该文档语意影响而独立选择的。例如有如下两个文档:

 1:Bob likes to play basketball, Jim likes too.

 2:Bob also likes to play football games.

基于这两个文本文档,构造一个词典:

Dictionary = {1:”Bob”, 2. “like”, 3. “to”, 4. “play”, 5. “basketball”, 6. “also”, 7. “football”, 8. “games”, 9. “Jim”, 10. “too”}。

这个词典一共包含10个不同的单词,利用词典的索引号,上面两个文档每一个都可以用一个10维向量表示(用整数数字0~n(n为正整数)表示某个单词在文档中出现的次数):

 1:[1, 2, 1, 1, 1, 0, 0, 0, 1, 1]

 2:[1, 1, 1, 1 ,0, 1, 1, 1, 0, 0]

向量中每个元素表示词典中相关元素在文档中出现的次数(下文中,将用单词的直方图表示)。不过,在构造文档向量的过程中可以看到,我们并没有表达单词在原来句子中出现的次序(这是本Bag-of-words模型的缺点之一)

  • 将BOW引入到计算机视觉图像检索中,就有了bag of feature。就是将一幅图像看成文本对象,图像中的不同特征可以看成构成图像的不同词汇。和文本的BOW类似,这样就可以使用图像特征在图像中出现的频率,使用一个一维的向量来描述图像。
  • 要将图像表示为BOW的向量,首先就是要得到图像的“词汇”。通常需要在整个图像库中提取图像的局部特征(例如,sift,orb等),然后使用聚类的方法(k-means),合并相近的特征,聚类的中心可以看成一个个的视觉词汇(visual word),视觉词汇的集合构成视觉词典(visual vocabulary) 。得到视觉词汇集合后,统计图像中各个视觉词汇出现的频率,就得到了图像的BOW表示。

二、基于BOW的图像检索

对于两张图片,我们可以利用sift算法来进行特征匹配。但是面对大规模图像特征匹配,一个个特征匹配,计算量过于庞大。显然,暴力匹配法不实用。

对于大场景数据集(如城市场景),其实只有少于0.1%的图像具有匹配关系,所以我们可用图像整体特征实现匹配/检索,而非局部特征点。把图像视为与位置无关的局部特征集合,局部特征就相当于文本中的单词,称为“视觉单词”,视觉单词的集合称为“视觉词典”(也叫码本)。

基本流程

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

1. 特征提取 (SIFT)

过分割、密集或随机采集、关键点或稳定区域、显著区域等方式使图像形成不同的图像块,并获得各图像块处的特征。

特征必须具有较高的区分度,而且要满足旋转不变性以及尺寸不变性等,通常采用SIFT特征(也可以采用SUFT、Harrist等特征提取算法 )。SIFT会从图片上提取出很多特征点,每个特征点都是具有鲁棒性的128维向量,如果图片足够多的话,我们会提取出一个巨大的特征向量库。
学新通
学新通
学新通
SIFT详情

2. 学习 “视觉词典(visual vocabulary)” (k-means)

一个一个地匹配耗时过长,所以通过聚类方法对相似特征进行聚类。通常采用k-means算法。

流程如下所示,不断寻找聚类中心,直至算法收敛。
学新通
学新通
学新通

k-means算法流程

  1. 随机初始化 K 个聚类中心
  2. 重复下述步骤直至算法收敛:
    • 对应每个特征,根据距离关系赋值给某个中心/类别
    • 对每个类别,根据其对应的特征集重新计算聚类中心

聚类是实现 visual vocabulary/codebook的关键

  • 无监督学习策略
  • k-means 算法获取的聚类中心作为视觉单词(codevector)
  • 视觉词典/码本(visual vocabulary/codebook)可以通过不同的训练集协同训练获得
  • 一旦训练集准备足够充分, 训练出来的视觉词典/码本(visual vocabulary/codebook)将具有普适性

如何选择视觉词典/码本的规模?

  • 太少:视觉单词无法覆盖所有可能出现的情况
  • 太多: 计算量大,容易过拟合

如何提升计算效率

  • 词汇树(vocabulary trees)

视觉词典样例:
学新通
学新通

3. 针对输入特征集,根据视觉词典进行量化

码本/字典用于对输入图片的特征集进行量化

  • 对于输入特征集,量化的过程是将该特征映射到距离其最接近的 codevector ,并实现计数

4. 把输入图像,根据TF-IDF转化成视觉单词( visual words)的频率直方图

对于文本而言,当一个单词在所有文本都出现那么这个单词就不能区分文本。同理,如果一个视觉单词在每个图像中都出现,那么这个视觉单词就不能区分图像了。类比文本,我们这里也采用TF-IDF权重来表示视觉单词对区分图像的重要程度。

词频 Term Frequency,TF指的是一个给定的词语在该文件中出现的次数。如:一篇文档总词数为1000,单词A出现次数为3次,则TF=3/1000=0.003。其主要思想是:如果某个关键词在一篇文章中出现的频率高,说明该词语能够表征文章的内容,该关键词在其它文章中很少出现,则认为此词语具有很好的类别区分度,对分类有很大的贡献。

逆文档频率 Inverse Document Frequency,IDF是描述了某一个特定词语的普遍重要性,如果某词语在许多文档中都出现过,表明它对文档的区分力不强,则赋予较小的权重;反之亦然。如:总共有1000篇文档,有100个包含词语A,则IDF= log (1000/1,00) = 3.287。IDF的主要思想是:如果文件数据库中包含词语A的文件越少,则IDF越大,则说明词语A具有很好的类别区分能力。

通过此种方法,就可以使得频率高的词汇降低权重

单词w在文档d中的词频
t f w , d = n w ∑ j n j tf_{w,d}=\frac{n_w}{\sum_{j}n_j} tfw,d=jnjnw
其中 n w n_w nw是单词w在文档d中出现的次数,分母为文档中单词总数。

逆文档频率
i d f w , d = l o g ∣ ( D ) ∣ ∣ { d : w ϵ d } ∣ idf_{w,d}=log\frac{\left | (D) \right |}{|\left \{ d:w\epsilon d \right \}|} idfw,d=log{d:wϵd}(D)
其中|(D)|为总文档数,分母为包含单词w的文档数(注意不要和单词出现次数混淆)。
学新通

5. 构造特征到图像的倒排表,通过倒排表快速索引相关图像

举例说明倒排表:

文档1:what is it?
文档2:it is a banana.

则有
“what”: {1} 表示"what"出现在文档1中
“is”: {1,2} 表示"is“出现在文档1和文档2中
“it”: {1,2}
“a”: {2}
“banana”: {2}

经过倒排后,就是视觉单词:[视觉单词所出现的图像集合]。倒排表可以快速使用反转文件来计算新图像与数据库中所有图像之间的相似性,仅考虑其分档与查询图像重叠的数据库图像,大大减少了匹配次数,优化了算法。

6. 根据索引结果进行直方图匹配

根据索引结果进行直方图匹配,得到匹配结果。

三、代码实现

1. 数据集

爬虫数据采集

import requests
import os
import urllib
 
class Spider_百度_image():
    def __init__(self):
        self.url = 'http://image.百度.com/search/acjson?'
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.\
            3497.81 Safari/537.36'}
        self.headers_image = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.\
            3497.81 Safari/537.36','Referer':'http://image.百度.com/search/index?tn=百度image&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1557124645631_R&pv=&ic=&nc=1&z=&hd=1&latest=0&copyright=0&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&sid=&word=胡歌'}
        self.keyword = input("请输入搜索图片关键字:")
        self.paginator = int(input("请输入搜索页数,每页30张图片:"))
        # self.paginator = 50
        # print(type(self.keyword),self.paginator)
        # exit()
    def get_param(self):
        """
        获取url请求的参数,存入列表并返回
        :return: 
        """
        keyword = urllib.parse.quote(self.keyword)
        params = []
        for i in range(1,self.paginator 1):
            params.append('tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord={}&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=&hd=1&latest=0&copyright=0&word={}&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&cg=star&pn={}&rn=30&gsm=78&1557125391211='.format(keyword,keyword,30*i))
        return params
 
    def get_urls(self,params):
        """
        由url参数返回各个url拼接后的响应,存入列表并返回
        :return:
        """
        urls = []
        for i in params:
            urls.append(self.url i)
        return urls
    def get_image_url(self,urls):
        image_url = []
        for url in urls:
            json_data = requests.get(url,headers = self.headers).json()
            json_data = json_data.get('data')
            for i in json_data:
                if i:
                    image_url.append(i.get('thumbURL'))
        return image_url
    def get_image(self,image_url):
        """
        根据图片url,在本地目录下新建一个以搜索关键字命名的文件夹,然后将每一个图片存入。
        :param image_url: 
        :return: 
        """
        cwd = os.getcwd()
        file_name = os.path.join(cwd,self.keyword)
        if not os.path.exists(self.keyword):
            os.mkdir(file_name)
        for index,url in enumerate(image_url,start=1):
            with open(file_name '\\{}.jpg'.format(index),'wb') as f:
                f.write(requests.get(url,headers = self.headers_image).content)
            if index != 0 and index % 30 == 0:
                print('{}第{}页下载完成'.format(self.keyword,index/30))
    def __call__(self, *args, **kwargs):
        params = self.get_param()
        urls = self.get_urls(params)
        image_url = self.get_image_url(urls)
        self.get_image(image_url)
 
if __name__ == '__main__':
    spider = Spider_百度_image()
    spider()
 
学新通

四种类型,每种30张,共120张。(有的图片有误)
喜多川海夢
学新通
薛之谦
学新通
申鹤
学新通
刻晴
学新通

2. 创建词汇

import pickle
from PCV.imagesearch import vocabulary
from PCV.tools.imtools import get_imlist
from PCV.localdescriptors import sift
#获取图像列表
imlist = get_imlist("D:\\study\\计算机视觉\\code\\code5\\image")
nbr_images = len(imlist)
print('nbr_images:',nbr_images)
#获取特征列表
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('Image')
voc.train(featlist, 200, 10)#调用了PCV的vocabulary.py中的train函数
#保存词汇
with open('D:\\study\\计算机视觉\\code\\code5\\image\\vocabulary.pkl', 'wb') as f:
    pickle.dump(voc, f)#将生成的词汇保存到vocabulary.pkl(f)中
print ('vocabulary is:', voc.name, voc.nbr_words)
学新通

学新通
运行结果:sift和词汇文件

3. 创建索引

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
#获取图像列表
imlist = get_imlist("D:\\study\\计算机视觉\\code\\code5\\image")
nbr_images = len(imlist)
#获取特征列表
featlist = [imlist[i][:-3] 'sift' for i in range(nbr_images)]
#载入词汇
with open('D:\\study\\计算机视觉\\code\\code5\\image\\vocabulary.pkl', 'rb') as f:
    voc = pickle.load(f)
#创建索引
indx = imagesearch.Indexer('testImaAdd.db',voc)
indx.create_tables()
#遍历所有的图像,并将它们的特征投影到词汇上
for i in range(nbr_images)[:110]:
    locs,descr = sift.read_features_from_file(featlist[i])
    indx.add_to_index(imlist[i],descr)
#提交到数据库
indx.db_commit()
con = sqlite.connect('testImaAdd.db')
print (con.execute('select count (filename) from imlist').fetchone())
print (con.execute('select * from imlist').fetchone())
学新通

运行结果:
学新通

4. 检索测试

import pickle
from PCV.localdescriptors import sift
from PCV.imagesearch import imagesearch
from PCV.geometry import homography
from PCV.tools.imtools import get_imlist
#载入图像列表
imlist = get_imlist('D:\\study\\计算机视觉\\code\\code5\\image')
nbr_images = len(imlist)
#载入特征列表
featlist = [imlist[i][:-3] 'sift' for i in range(nbr_images)]
#载入词汇
with open('D:\\study\\计算机视觉\\code\\code5\\image\\vocabulary.pkl', 'rb') as f:
    voc = pickle.load(f)
src = imagesearch.Searcher('testImaAdd.db',voc)
#查询图像索引和查询返回的图像数
q_ind = 1
nbr_results = 5
# 常规查询(按欧式距离对结果排序)
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[:5]) #常规查询
imagesearch.plot_results(src,res_geom[:5]) #重排后的结果
学新通

运行结果:第一张图片为检索图片,后四张是匹配到的图片(按照匹配效果好到坏排序)
学新通
学新通

四、问题

1.报错如下:
学新通
解决:报错文件中imagesearch.py中pysqlite2改成sqlite3
学新通
2.报错如下:python2和3的区别
学新通
解决:将imagesearch.py中str删除
学新通
3.报错如下:python3 已经不支持cmp()函数
学新通
解决:
学新通
此处改为

sorted(tmp, key=functools.cmp_to_key(lambda x, y: x[1] - y[1]))

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhghfiig
系列文章
更多 icon
同类精品
更多 icon
继续加载