python计算机视觉编程——基于BOF的图像检索(附代码)

图像检索

    • 一、图像检索
      • 1.1基本原理
    • 1.2 BOW原理简述(同BOF原理)
      • 1.3 基于BOF的图像检索基本流程
        • 1.3.1 sift特征提取
        • 1.3.2 建立视觉单词
        • 1.3.3 K-Means算法
    • 二、实验
      • 2.1 实验环境
      • 2.2实验要求
      • 2.3实验代码(实验分析也在其中)
        • 1.生成sift特征文件
        • 2.建立数据库
        • 3.测试索引
        • 4.在web端演示可视化索引
    • 三、实验总结遇到的问题
        • 3.1 ImportError: No module named pysqlite2
        • 3.2 数据库已存在
        • 3.3 TypeError: a bytes-like object is required, not 'str'
        • 3.4 python3 中cmp的替换

此次实验的内容主要有关于图像检索的内容,与教材《python计算机视觉编程》衔接,将展示如何利用文本挖掘技术对基于图像视觉内容进行图像搜索。

一、图像检索

由于暴力检索(即一张一张图像直接对比)需要花费大量的计算机运行时间和内存,考虑到检索效率,从20世纪70年代开始,有关图像检索的研究就已开始,当时主要是基于文本的图像检索技术(Text-based Image Retrieval,简称TBIR),利用文本描述的方式描述图像的特征,如绘画作品的作者、年代、流派、尺寸等。到90年代以后,出现了对图像的内容语义,如图像的颜色、纹理、布局等进行分析和检索的图像检索技术,即基于内容的图像检索(Content-based Image Retrieval,简称CBIR)技术。CBIR属于基于内容检索(Content-based Retrieval,简称CBR)的一种,CBR中还包括对动态视频、音频等其它形式多媒体信息的检索技术
总的来说图像检索就是从大量的图像数据库中检索出满足条件的图片,技术包括:

  • 基于文本的图像检索技术
  • 基于内容的图像检索技术

1.1基本原理

由于对于大场景数据集(如城市场景), 只有极少部分的图像对具有匹配关系,为了解决这一问题,我们利用图像整体特征实现匹配检索,而非局部特征点。
在检索原理上,无论是基于文本的图像检索还是基于内容的图像检索,主要包括三方面:

  • 一方面对用户需求的分析和转化,形成可以检索索引数据库的提问;
  • 另一方面,收集和加工图像资源,提取特征,分析并进行标引,建立图像的索引数据库
  • 最后一方面是根据相似度算法,计算用户提问与索引数据库中记录的相似度大小,提取出满足阈值的记录作为结果,按照相似度降序的方式输出。

1.2 BOW原理简述(同BOF原理)

为了将文本挖掘技术应用到图像中,我们首先需要建立视觉等效单词;这通常可以SIFT 局部描述子做到。它的思想是将描述子空间量化成一些典型实例,并将图像中的每个描述子指派到其中的某个实例中。这些典型实例可以通过分析训练图像集确定,并被视为视觉单词。所有这些视觉单词构成的集合称为视觉词汇,有时也称为视觉码本。对于给定的问题、图像类型,或在通常情况下仅需呈现视觉内容,可以创建特定的词汇。从一个(很大的训练图像)集提取特征描述子,利用一些聚类算法可以构建出视觉图像搜索,或在更加高级的场合下使用层次 K-means单词。聚类算法中最常用的是 K-means,这里也将采用 K-means。视觉单词并不高端,只是在给定特征描述子空间中的一组向量集,在采用 K-means 进行聚类时得到的视觉单词是聚类质心。用视觉单词直方图来表示图像,则该模型便称为 BOW 模型。
Bag-of-Words模型源于文本分类技术。在信息检索中,它假定对于一个文本,忽略其词序、语法和句法,将其仅仅看作是一个词集合,或者说是词的一个组合。文本中每个词的出现都是独立的,不依赖于其他词是否出现,即在任意一个位置选择词汇都不受前面句子的影响而独立选择的。
使用某种聚类算法(如K-means)将特征进行聚类,每个聚类中心被看作是词典中的一个视觉词汇(Visual Word),相当于文本检索中的词,视觉词汇由聚类中心对应特征形成的码字(code word)来表示(可看当为一种特征量化过程)。所有视觉词汇形成一个视觉词典(Visual Vocabulary),对应一个码书(code book),即码字的集合,词典中所含词的个数反映了词典的大小。图像中的每个特征都将被映射到视觉词典的某个词上,这种映射可以通过计算特征间的距离去实现。然后,统计每个视觉词的出现与否或次数图像可描述为一个维数相同的直方图向量,即Bag-of-Features。在Bag-of-Features方法的基础上,Andrew Zisserman进一步借鉴文本检索中TF-IDF模型(Term Frequency一Inverse Document Frequency)来计算Bag-of-Features特征向量。接下来便可以使用文本搜索引擎中的反向索引技术对图像建立索引,高效的进行图像检索。
Bag-of-Features更多地是用于图像分类或对象识别,鉴于SIFT的优异性能,本文提取的是SIFT特征

1.3 基于BOF的图像检索基本流程

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

1.3.1 sift特征提取

该特征提取原理可以参考我之前写过的博文,这里不多写:
sift特征提取
python计算机视觉编程——基于BOF的图像检索(附代码)_第1张图片

1.3.2 建立视觉单词

为了将文本挖掘技术运用到图像中,首先要建立视觉等效单词;可以采用SIFT局部描述算子获得,针对输入特征集,根据视觉词典进行量化。建立视觉单词的思想就是将描述算子空间量化成一些典型实例,并将图像中的每个描述算子指派到其中的某个实例中,这些典型实例可通过分析训练图像集确定。即从一个很大的训练集提取特征描述算子,利用一些聚类算法可以构建出视觉单词(聚类算法最常用的是K-means),视觉单词是在给定特征描述算子空间中一组向量集,采用K-means进行聚类得到的聚类质心;把输入图像,根据TF-IDF转化成视觉单词( visual words)的频率直方图 ,用视觉单词直方图来表示图像。如图下所示:
python计算机视觉编程——基于BOF的图像检索(附代码)_第2张图片

1.3.3 K-Means算法

关于K-Means算法的原理可以参考下面这篇博文:
Kmeans聚类算法
K值越大,噪声对聚类影响越小,但是K值取过大将无法得出聚类结果,所以聚类时K值的选取要适当。
K-Means算法基本流程:

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

二、实验

2.1 实验环境

1.ptyhon3.7版本,win10 ,pycharm;
2.由于有用到sift特征提取,所以需要安装vlfeat,我安装的是0.9.20版本。vlfeat的win64里的vl.dll和sift.exe和vl.lib复制在项目里。
3.把PCV包放在项目下
4.安装PyQt5(直接pip就好了,加个镜像快很多,要不然容易超时)
5.安装cherrypy(同样直接pip,用于可视化检索)

2.2实验要求

python计算机视觉编程——基于BOF的图像检索(附代码)_第3张图片

2.3实验代码(实验分析也在其中)

1.生成sift特征文件

对每张图片生成相应的.sift文件,及视觉词汇,以便建立BOW模型。我所用的是图像集为104张(自己网络搜索的图片)。如果需要增加图像或减少只需要改代码里读取训练图像的数量,为了让sift特征提取速度变快,我将所有图片的大小调整成统一的大小,并且设置成400*300的分辨率,加快了代码的运行速度。
python计算机视觉编程——基于BOF的图像检索(附代码)_第4张图片
python计算机视觉编程——基于BOF的图像检索(附代码)_第5张图片

# -*- 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('E:/thirddown/computervision/untitled4/jsjsj/data/')
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])

# 生成词汇
#train的参数为(特征列表,读取图片数,训练数)
voc = vocabulary.Vocabulary('test')
voc.train(featlist, 104, 20)

# 保存词汇
# saving vocabulary
with open('E:/thirddown/computervision/untitled4/jsjsj/data/vocabulary.pkl', 'wb') as f:
    pickle.dump(voc, f)
print('vocabulary is:', voc.name, voc.nbr_words)

运行结果:
python计算机视觉编程——基于BOF的图像检索(附代码)_第6张图片
每张数据集都得到了对应的sift文件,同时每幅图像的描述子保存在vocabulary.pkl文件中,如果数据模型为空,在后面存入数据库会出现报错,读入数据为空。
python计算机视觉编程——基于BOF的图像检索(附代码)_第7张图片

python计算机视觉编程——基于BOF的图像检索(附代码)_第8张图片

2.建立数据库

2.将上面得到的数据模型存放数据库testImaAdd.db中,即运行下面代码会生成一个testImaAdd.db数据库文件。
注意在读取图像数目要与建立的图像数据库数匹配对,即下面这行代码要匹配第一个文件的数据集的数目:
python计算机视觉编程——基于BOF的图像检索(附代码)_第9张图片
python计算机视觉编程——基于BOF的图像检索(附代码)_第10张图片

# -*- 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:/thirddown/computervision/untitled4/jsjsj/data/')
nbr_images = len(imlist)
# 获取特征列表
featlist = [imlist[i][:-3] + 'sift' for i in range(nbr_images)]

# load vocabulary
# 载入词汇

with open('E:/thirddown/computervision/untitled4/jsjsj/data/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)[:104]:
    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数据库文件。
python计算机视觉编程——基于BOF的图像检索(附代码)_第11张图片

3.测试索引

建立图像数据库成功后,就可以进行图像查询测试一下索引结果。
我这里测试了数据集中的第一张图片,选择最匹配的二十张图片,展示前八张最匹配的图片。
python计算机视觉编程——基于BOF的图像检索(附代码)_第12张图片

# -*- 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

# load image list and vocabulary
# 载入图像列表

imlist = get_imlist('E:/thirddown/computervision/untitled4/jsjsj/data/')
nbr_images = len(imlist)
# 载入特征列表
featlist = [imlist[i][:-3] + 'sift' for i in range(nbr_images)]

# 载入词汇

with open('E:/thirddown/computervision/untitled4/jsjsj/data/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列表中每一幅图像特征,并和查询的图像进行匹配。当隐形通过计算匹配数和计数内点数得到,最终可通过减少内点数目对包含图像索引和内点数的字典进行排序。最后可视化检索靠前的匹配图像结果。我的图片集包括四个不同场景,分别是:凡尔赛宫,科隆大教堂,故宫和埃及金字塔。上面的运行结果的测试图片为凡尔赛宫,实验结果显示正常,从104张图片中找出了凡尔赛宫,而没有找错成另外三种场景。

我换了另一个场景进行测试,第二次用的是科隆大教堂:
实验结果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
从测试结果可以看出这次测试的结果没有上一次的好,出现了错误的检索,可能原因是图像分辨率太低,sift特征提取没有很明显的区分,都标记为角点较多的作为特征词典。对于常规查询结果可重拍后的查询结果来说,重排后的查询结果会比常规查询结果更为准确些,重排用单应性进行拟合建立RANSAC模型,再导入候选图像特征进行排序查询;常规查询只是进行了简单的索引和查询,找到相似即可。

4.在web端演示可视化索引

# -*- coding: utf-8 -*-
import cherrypy
import pickle
import urllib
import os
from numpy import *
# from PCV.tools.imtools import get_imlist
from PCV.imagesearch import imagesearch
import random

"""
This is the image search demo in Section 7.6.
"""


class SearchDemo:

    def __init__(self):
        # 载入图像列表

        self.path = 'E:/thirddown/computervision/untitled4/jsjsj/data/'
        self.imlist = [os.path.join(self.path, f) for f in os.listdir(self.path) if f.endswith('.jpg')]
        # self.imlist = get_imlist('./first500/')
        # self.imlist = get_imlist('E:/python/isoutu/first500/')
        self.nbr_images = len(self.imlist)
        print(self.imlist)
        print(self.nbr_images)
        self.ndx = list(range(self.nbr_images))
        print(self.ndx)

        # 载入词汇
        # f = open('first1000/vocabulary.pkl', 'rb')
        with open('E:/thirddown/computervision/untitled4/jsjsj/data/vocabulary.pkl', 'rb') as f:
            self.voc = pickle.load(f)
        # f.close()

        # 显示搜索返回的图像数
        self.maxres = 10

        # header and footer html
        self.header = """
            
            
            Image search
            
            
            """
        self.footer = """
            
            
            """

    def index(self, query=None):
        self.src = imagesearch.Searcher('testImaAdd.db', self.voc)

        html = self.header
        html += """
            
Click an image to search. Random selection of images.

"""
if query: # query the database and get top images # 查询数据库,并获取前面的图像 res = self.src.query(query)[:self.maxres] for dist, ndx in res: imname = self.src.get_filename(ndx) html += "" html += ""</span> <span class="token operator">+</span> imname <span class="token operator">+</span> <span class="token string">"" print(imname + "################") html += "" # show random selection if no query # 如果没有查询图像则随机显示一些图像 else: random.shuffle(self.ndx) for i in self.ndx[:self.maxres]: imname = self.imlist[i] html += "" html += ""</span> <span class="token operator">+</span> imname <span class="token operator">+</span> <span class="token string">"" print(imname + "################") html += "" html += self.footer return html index.exposed = True # conf_path = os.path.dirname(os.path.abspath(__file__)) # conf_path = os.path.join(conf_path, "service.conf") # cherrypy.config.update(conf_path) # cherrypy.quickstart(SearchDemo()) cherrypy.quickstart(SearchDemo(), '/', config=os.path.join(os.path.dirname(__file__), 'service.conf'))

这里我没有办法实现,一直报错说我转义字符出现问题,三种方法
修改无果…放弃了,希望能有大神指点一下…
python计算机视觉编程——基于BOF的图像检索(附代码)_第13张图片

三、实验总结遇到的问题

3.1 ImportError: No module named pysqlite2

引用了一句 from pysqlite2 import dbapi2 as sqlite
在调试时报错:No module named pysqlite2
是因为Python3X带的是sqlite3库
python计算机视觉编程——基于BOF的图像检索(附代码)_第14张图片
所以只要将这句话改成 import sqlite3 as sqlite就可以了

3.2 数据库已存在

python计算机视觉编程——基于BOF的图像检索(附代码)_第15张图片
将生成的数据库删除,或者换个名字。这里因为重复运行代码和修改数据集导致重复生成数据库。

3.3 TypeError: a bytes-like object is required, not ‘str’

这里报错是系统库文件中的imagesearch.py,错误的意思是参数类型错误,因为源代码中pickle.loads(str(s[0]))中的str不符合参数要求,故要修改。
python计算机视觉编程——基于BOF的图像检索(附代码)_第16张图片

3.4 python3 中cmp的替换

TypeError: 'cmp' is an invalid keyword argument for this function
在官方文档中可以发现,在python2中的sort()函数:
sort(cmp=None, key=None, reverse=False)
python3中的sort()函数:
sort(*, key=None, reverse=None)

少了cmp参数。
python3中的cmp函数已经被弃用,而是使用了cmp_to_key这个函数,但是这个函数的用法和cmp函数完全不同

  1. cmp关键字被替换成key
  2. cmp函数本身不可用

综合需要用到key关键字, cmp_to_key()函数和operator模块三者来替换原来的cmp方法,真的太不方便了…以下是对imagesearch.py文件的修改部分,修改后即没有报错可运行。

python计算机视觉编程——基于BOF的图像检索(附代码)_第17张图片

python计算机视觉编程——基于BOF的图像检索(附代码)_第18张图片

你可能感兴趣的:(python计算机视觉编程——基于BOF的图像检索(附代码))