Python计算机视觉编程——第七章 图像搜索

1 基于内容的图像检索(CBIR)

CBIR技术用于检索在视觉上具相似度的图像。返回的图像可以是颜色相似,纹理相似,图像中的物体或场景相似。
过去几年里,成功地引入文本挖掘技术到CBIR中处理问题,使得在数百万图像中搜索具有相似内容的图像成为可能。

  • 从文本挖掘中获取灵感——矢量空间模型
    矢量空间模型是一个用于表示和搜索文本文档的模型。这些矢量是由文本词频直方图构成的。矢量包含了每个单词出现的次数,而且在其他别的地方包含很多0元素。因为该模型忽略了单词出现的顺序以及位置,也被称为BOW表示模型。
    使用单词计数来构建文档直方图向量v,建议文档索引。在单词计数中会忽略类似“这”,“和”,“是”等常用词,这些常用词被称为停用词。向量需要除以直方图总和将向量归一化为单位长度。对于向量中的不同元素,根据单词的重要性赋予权重。一个单词的重要性与它在文档中出现的次数成正比,与在语料库中出现的次数成反比。
    最常用权重是tf-idf,单词w在文档d中的词频是:
    t f w , d = n w ∑ j n j \mathrm{tf}_{w,d}=\frac{n_w}{\sum_jn_j} tfw,d=jnjnw
    n w n_w nw是单词 w w w在文档 d d d 中出现的次数。为了归一化,将 n w n_w nw 除以整个文档中单词的总数。
    逆向文档频率为:
    i d f w , d = log ⁡ ∣ ( D ) ∣ ∣ { d  ⁣ : w ∈ d } ∣ \mathrm{idf}_{w,d}=\log\frac{|(D)|}{|\{d\colon w\in d\}|} idfw,d=log{d:wd}(D)
    ∣ D ∣ \left|D\right| D是在语料库 D D D中文档的数目,分母是语料库中包含单词 w w w的文档数 d d d。将两者相乘可以得到矢量 ν \nu ν中对应元素的 tf-idf 权重。

2 视觉单词

首先需要建立视觉等效单词,可以使用SIFT局部描述子做到,思想是将描述子空间量化为一些典型示例,将图像中的每个描述子指派到某个实例中。典型示例可通过分析训练图像集确定,被视为视觉单词。视觉单词构成集合称为视觉词汇(视觉码本)。
从一个集提取特征描述子,利用聚类算法构建出视觉单词。采用K-means进行聚类得到的视觉单词是聚类质心。用视觉单词直方图表示图像,称BOW模型。

  • 创建词汇
    首先提取特征描述子,使用SIFT特征描述子。使用代码得到每幅图像的描述子。将图像的描述子保存在文件Vocabulary.pkl中。
import pickle
import sift
from PCV.imagesearch import vocabulary
from PCV.tools.imtools import get_imlist
from PCV.localdescriptors import sift

#获取图像列表
imlist = get_imlist('C:/Users/23232/Desktop/PCV.geometry/first1000')
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)
#保存词汇
# saving vocabulary
with open('Vocabulary.pkl', 'wb') as f:
    pickle.dump(voc, f)
print ('vocabulary is:', voc.name, voc.nbr_words)

得到了词汇对象文件。
在这里插入图片描述

3 图像索引

该过程是建立图像数据库和图像的视觉单词表示。

3.1 建立数据库

对图像进行索引是从这些图像中提取描述子,利用词汇将描述子转换为视觉单词,保存视觉单词及对应图像的单词直方图。
使用SQList作为数据库,该数据库将所有的信息保存在一个文件。SQList使用SQL查询语言。

先创建表,索引和索引器Indexer类,将图像数据写入数据库。
创建imagesearch.py文件,将下列代码写入:

import pickle
from pysqlite2 import dbapi2 as sqlite
class Indexer(object):
  def __init__(self,db,voc):
  self.con = sqlite.connect(db)
  self.voc = voc
  def __del__(self):
    self.con.close()
  def db_commit(self):
    self.con.commit()
  def create_tables(self):
  """ 创建数据库表单""" 
    self.con.execute('create table imlist(filename)')
    self.con.execute('create table imwords(imid,wordid,vocname)')
    self.con.execute('create table imhistograms(imid,histogram,vocname)')
    self.con.execute('create index im_idx on imlist(filename)')
    self.con.execute('create index wordid_idx on imwords(wordid)')
    self.con.execute('create index imid_idx on imwords(imid)')
    self.con.execute('create index imidhist_idx on imhistograms(imid)')
    self.db_commit()

使用pickle模块将数组编码成字符串以及将字符串进行解码。Indexer 类连接数据库,并且一旦创建 (调用_init_()方法)后就可以保存词汇对象。del ()方法可以确保关闭数据库连接,db commit()可以将更改写入数据库文件。
表单imlist包含索引的图像文件名,imwords包含单词的单词索引,用到了哪些词汇,单词出现在哪些图像,imhistograms包含了每幅图像的单词直方图。

3.2 添加图像

基于数据库表单,可以在索引中添加图像,add_to_index()方法来实现该功能。

    def add_to_index(self,imname,descr):
        """ Take an image with feature descriptors, 
            project on vocabulary and add to database. """
            
        if self.is_indexed(imname): return
        print('indexing', imname)
        
        imid = self.get_id(imname)
        
        imwords = self.voc.project(descr)
        nbr_words = imwords.shape[0]
        
        for i in range(nbr_words):
            word = imwords[i]
            self.con.execute("insert into imwords(imid,wordid,vocname) values (?,?,?)", (imid,word,self.voc.name))
            
        self.con.execute("insert into imhistograms(imid,histogram,vocname) values (?,?,?)", (imid,pickle.dumps(imwords),self.voc.name))

上述代码获得图像文件名和Numpy数组(包含在图像中找到的描述子)使用辅助函数is_indexed()检查图像是否已经索引,get_id()对一幅图像文件名给定id号。

    def get_id(self,imname):
        """ Get an entry id and add if not present. """
        
        cur = self.con.execute(
        "select rowid from imlist where filename='%s'" % imname)
        res=cur.fetchone()
        if res==None:
            cur = self.con.execute(
            "insert into imlist(filename) values ('%s')" % imname)
            return cur.lastrowid
        else:
            return res[0] 
    
    def is_indexed(self,imname):
        """ Returns True if imname has been indexed. """
        
        im = self.con.execute("select rowid from imlist where filename='%s'" % imname).fetchone()
        return im != None

接下来遍历ukbench数据库中的样本图像,将其加入索引。

import pickle
import sift
from PCV.imagesearch import vocabulary
from PCV.tools.imtools import get_imlist
from PCV.localdescriptors import sift
from PCV.imagesearch import  imagesearch
import sqlite3
#获取图像列表
imlist = get_imlist('C:/Users/23232/Desktop/PCV.geometry/first1000')
nbr_images = len(imlist)
#获取特征列表
featlist = [imlist[i][:-3]+'sift' for i in range(nbr_images)]

with open('Vocabulary.pkl', 'rb') as f:  # 读取再上一步中保存的.pkl文件
    voc = pickle.load(f)
# 创建索引
index = imagesearch.Indexer('test2.db', voc)  # 创建数据库
index.create_tables()  # 创建数据库表单

# 遍历所有的图像,并将它们的特征投影到词汇上
for i in range(nbr_images)[:1000]:
    locs, descr = sift.read_features_from_file(featlist[i])
    index.add_to_index(imlist[i], descr)

# 提交到数据库
index.db_commit()
con = sqlite3.connect('test2.db')  # 连接到数据库
print(con.execute('select count (filename) from imlist').fetchone())  # 数据库操作
print(con.execute('select * from imlist').fetchone())

在这里插入图片描述

4 在数据库中搜索图像

建立完图像的索引后,可以在数据库中搜索相似的图像。使用BOW来表示整个图像。
通过将Search类添加到imagesearch.py中。

class Searcher(object):
  def __init__(self,db,voc):
    """ 初始化数据库的名称 """
    self.con = sqlite.connect(db)
    self.voc = voc
  def __del__(self):
    self.con.close()

Search对象连接到数据库,删除就关闭连接。
利用单词索引获得候选集,然后再候选集上进行逐一比较。

4.1 利用索引获取候选图像

利用索引找到包含特定单词的所有图像,是对数据库做简单的查询。

首先再Search类中加入candidates_from_word()方法:

def candidates_from_word(self,imword):
  """ G 获取包含 imword 的图像列表"""
  im_ids = self.con.execute(
      "select distinct imid from imwords where wordid=%d" % imword).fetchall()
  return [i[0] for i in im_ids]

给出了包含特定单词的所有图像id号。通过再每个单词上进行便利获得包含多个单词的候选图像。
candidates_from_histogram方法显示有多少单词与单词直方图中的单词匹配。

def candidates_from_histogram(self,imwords):
  """ 获取具有相似单词的图像列表"""
  words = imwords.nonzero()[0]
  candidates = []
  for word in words:
    c = self.candidates_from_word(word)
    candidates+=c
  tmp = [(w,candidates.count(w)) for w in set(candidates)]
  tmp.sort(cmp=lambda x,y:cmp(x[1],y[1]))
  tmp.reverse()
  return [w[0] for w in tmp]
  

使用如下代码从索引中查找出前10个图像id

import sift
from PCV.imagesearch import vocabulary
from PCV.tools.imtools import get_imlist
from PCV.localdescriptors import sift
from PCV.imagesearch import  imagesearch
import sqlite3
#获取图像列表
imlist = get_imlist('C:/Users/23232/Desktop/PCV.geometry/first1000')
nbr_images = len(imlist)
#获取特征列表
featlist = [imlist[i][:-3]+'sift' for i in range(nbr_images)]

f = open('Vocabulary.pkl', 'rb')
voc = pickle.load(f)
f.close()


src = imagesearch.Searcher('test2.db', voc)
locs,descr = sift.read_features_from_file(featlist[0])
iw = voc.project(descr)
print ('ask using a histogram...')
print (src.candidates_from_histogram(iw)[:10])

在这里插入图片描述

4.2 用一幅图像进行查询

使用一幅图像进行查询,不需要进行完全的搜索。Searcher类需要从数据库读入图像的单词直方图。
使用如下代码对图像进行查询:

src = imagesearch.Searcher('test2.db',voc)
print('try a query...')
print(src.query(imlist[0])[:10])

打印出前10个结果,显示了候选图像与查询图像间距离。
在这里插入图片描述

4.3 确定对比基准并绘制结果

可以计算前4个位置中搜索到相似图像数来评价搜索结果的好坏。

将以下代码添加到imagesearch.py中

def compute_ukbench_score(src,imlist):
    """ 对查询返回的前 4个结果计算平均相似图像数,并返回结果"""
    nbr_images = len(imlist)
    pos = zeros((nbr_images,4))

    for i in range(nbr_images):
        pos[i] = [w[1]-1 for w in src.query(imlist[i])[:4]]

    score = array([ (pos[i]//4)==(i//4) for i in range(nbr_images)])*1.0
    return sum(score) / (nbr_images)
  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值