【计算机视觉】基于BOW的图像检索

一、图像检索概述

简单的说便是从图片检索数据库中检索出满足条件的图片,图像检索技术的研究根据描述图像内容方式的不同可以分为两类:一类是基于文本的图像检索技术,一类为基于内容的图像检索技术。它最早用于对于文章内容的检索,原理是将文本看作是单词的集合,不考虑其中的语法,上下文等等。通过建立词典,对每个单词出现次数进行统计,以便得到文本内容的分类。计算机视觉的专家从中获得灵感,将其用于图像的检索中,就有了Bag Of Features。BOW(Bag of Feature)是一种图像特征提取方法,它借鉴了文本分类的思路(Bag of Words),从图像抽象出很多具有代表性的「关键词」,形成一个字典,再统计每张图片中出现的「关键词」数量,得到图片的特征向量。

二、Bag of Feature 算法

Bag-of-Features模型仿照文本检索领域的Bag-of-Words方法,把每幅图像描述为一个局部区域/关键点(Patches/Key Points)特征的无序集合。使用某种聚类算法(如K-means)将局部特征进行聚类,每个聚类中心被看作是词典中的一个视觉词汇(Visual Word),相当于文本检索中的词,视觉词汇由聚类中心对应特征形成的码字(code word)来表示(可看当为一种特征量化过程)。所有视觉词汇形成一个视觉词典(Visual Vocabulary),对应一个码书(code book),即码字的集合,词典中所含词的个数反映了词典的大小。图像中的每个特征都将被映射到视觉词典的某个词上,这种映射可以通过计算特征间的距离去实现,然后统计每个视觉词的出现与否或次数,图像可描述为一个维数相同的直方图向量,即Bag-of-Features。
总结来看,这种方式将文本表示成特征矢量。它的基本思想是假定对于一个文本,忽略其词序和语法、句法,仅仅将其看做是一些词汇的集合,而文本中的每个词汇都是独立的。
我们需要找到图像的特征,类似于词汇作为文本的特征,而这种特征必须得对光照,图片的是否旋转,图片畸变等不敏感,而sift特征提取能够较好的满足上述要求,因此,我们使用sift特征提取的方法形成一个词汇。
通过单词计数来构建文档直方图向量v,从而建立文档索引。通常,在单词计数时会忽略掉一些常用词,如 “这” “和” “是” 等,这些常用词称为停用词。由于每篇文档长度不同,因此除以直方图总和将向量归一化成单位长度。对于直方图向量中的每个元素,一般根据每个单词的重要性来赋予相应的权重。通常,数据集(或语料库)中一个单词的重要性与它在文档中出现的次数成正比,而与它在语料库中出现的次数成反比。
最常用的是权重是tf-idf(tern frequency-inverse document frequency,词频-逆向文档频率)
在这里插入图片描述
在这里插入图片描述
则,逆向文件频率:
在这里插入图片描述
在这里插入图片描述

三、图像检索流程

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

特征提取

特征提取通常使用 SIFT局部描述子技术。视觉单词流程类似。
##

学习特征词典

当我们提取完图像特征后,便开始了学习特征词典,利用一些聚类算法可以构建出视觉单词,最常用的是K−means算法。

K−means 算法
算法流程
1.随机初始化 K 个聚类中心;
2.重复下述步骤直至算法收敛:
对应每个特征,根据距离关系赋值给某个中心/类别;
对每个类别,根据其对应的特征集重新计算聚类中心。
在这里插入图片描述

聚类后,就得到了这k 个向量组成的词典,称为visual words(视觉单词)。所有这些视觉单词构成的集合称为视觉词汇。

对输入特征集进行量化

对于图像中的每一个SIFT特征,都可以在字典中找到一个最相似的visual word,这样,我们可以统计一个k维的直方图,代表该图像的SIFT特征在字典中的相似度频率。统计出最相似的向量出现的次数,最后得到这幅图片的直方图向量。

在这里插入图片描述

索引倒排表

通过TF-IDF过滤掉常见的词语,保留重要的词语后,我们便可以建立倒排索引表。
倒排索引表是一种逆向的索引方法,构造倒排表可以快速索引图像。倒排索引,通过搜索要查询的关键字,查询到跟该关键字相关的所有文档。倒排表可以获得是各视觉单词出现在图像库的哪些图像中。

直方图匹配

最后,根据索引的结果进行直方图匹配,就完成了图像索引。
在这里插入图片描述

四、实验过程

1.收集数据集

本次实验准备了30张水果蔬菜类型的图片集。
在这里插入图片描述

2.提取SIFT特征、生成视觉词典

import pickle
from PCV.imagesearch import vocabulary
from PCV.tools.imtools import get_imlist
from PCV.localdescriptors import sift
from PCV.imagesearch import imagesearch
from PCV.geometry import homography
from sqlite3 import dbapi2 as sqlite


#获取图像列表
imlist = get_imlist('./fruits/')
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) # 使用k-means算法在featurelist里边训练处一个词汇
#保存词汇
# saving vocabulary
with open('./BOW/vocabulary.pkl', 'wb') as f:
    pickle.dump(voc, f)
print ('vocabulary is:', voc.name, voc.nbr_words)

3.视觉词典进行量化生成数据库

import pickle
from PCV.imagesearch import vocabulary
from PCV.tools.imtools import get_imlist
from PCV.localdescriptors import sift
from PCV.imagesearch import imagesearch
from PCV.geometry import homography
from sqlite3 import dbapi2 as sqlite # 使用sqlite作为数据库


#获取图像列表
imlist = get_imlist('./fruits/')
nbr_images = len(imlist)
#获取特征列表
featlist = [imlist[i][:-3]+'sift' for i in range(nbr_images)]

# load vocabulary
#载入词汇
with open('./BOW/vocabulary.pkl', 'rb') as f:
    voc = pickle.load(f)
#创建索引
indx = imagesearch.Indexer('testImaAdd.db',voc) # 在Indexer这个类中创建表、索引,将图像数据写入数据库
indx.create_tables() # 创建表
# go through all images, project features on vocabulary and insert
#遍历所有的图像,并将它们的特征投影到词汇上
for i in range(nbr_images)[:888]:
    print(featlist[i])
    locs,descr = sift.read_features_from_file(featlist[i])
    indx.add_to_index(imlist[i],descr) # 使用add_to_index获取带有特征描述子的图像,投影到词汇上
                                       # 将图像的单词直方图编码存储
# commit to database
#提交到数据库
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.图像检索

# -*- 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('./fruits/')
nbr_images = len(imlist)
#载入特征列表
featlist = [imlist[i][:-3]+'sift' for i in range(nbr_images)]

#载入词汇
with open('./BOW/vocabulary.pkl', 'rb') as f:
    voc = pickle.load(f)

src = imagesearch.Searcher('testImaAdd.db',voc)# Searcher类读入图像的单词直方图执行查询

# index of query image and number of results to return
#查询图像索引和查询返回的图像数
q_ind = 4
nbr_results = 2

# 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:]:
    try:
        locs, descr = sift.read_features_from_file(featlist[ndx])
    except:
        continue
    # 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[:6]) #常规查询
imagesearch.plot_results(src,res_geom[:6]) #重排后的结果

5、实验结果及分析

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

五、实验总结

1、原先使用自己拍摄的图片数据集的时候,图片太大,生成sift特征平均每张图要运行2到3分钟左右,因此采用了网上搜索到的图片集进行实验。图片集每5张图片相似,6组共30张。图片像素为100×100,运行速度明显变快。
2、运行结果来看,BOW图像检索的效果相对较好,前四张为相似图片。
3、仍存在某些劣势:
a、Kmeans聚类时间长
b、词袋表的量化的过程,损失了匹配精度(本实验中采用网上的图,匹配效果相对较好)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
BOW (Bag of Words) 是一种常用的图像检索方法,其基本思想是将图像转化为向量,然后通过计算向量之间的距离来实现图像检索。下面是一个基于Python的BOW图像检索系统的设计思路和实现方法。 ## 设计思路 1. 预处理阶段:对于每张图片,提取其SURF特征,并使用K-means算法将特征向量聚类,得到视觉词汇表。 2. 训练阶段:对于每张图片,使用其SURF特征和视觉词汇表,构造其Bag of Words向量,并使用SVM分类器对图像进行分类。 3. 检索阶段:对于查询图片,提取其SURF特征并构造其Bag of Words向量,计算查询向量与训练集中所有图像的距离,并返回距离最近的前K张图片作为检索结果。 ## 实现方法 下面是一个基于Python的BOW图像检索系统的实现方法。 ### 1. 预处理阶段 ```python import cv2 import numpy as np from sklearn.cluster import KMeans # 定义SURF特征提取器 surf = cv2.xfeatures2d.SURF_create() # 定义K-means聚类器 kmeans = KMeans(n_clusters=50) # 加载训练集图片 train_images = [] for i in range(1, 11): img = cv2.imread(f'train/{i}.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) kp, des = surf.detectAndCompute(gray, None) train_images.append(des) # 将特征向量聚类,得到视觉词汇表 features = np.vstack(train_images) kmeans.fit(features) vocabulary = kmeans.cluster_centers_ ``` 以上代码中,我们使用OpenCV的SURF特征提取器提取训练集图片的SURF特征,并使用K-means算法将特征向量聚类,得到视觉词汇表。 ### 2. 训练阶段 ```python import os # 构造训练集的Bag of Words向量和标签 train_data = [] train_labels = [] for i in range(1, 11): img = cv2.imread(f'train/{i}.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) kp, des = surf.detectAndCompute(gray, None) words = kmeans.predict(des) bow_vector = np.zeros((1, 50)) for w in words: bow_vector[0, w] += 1 train_data.append(bow_vector) train_labels.append(i) # 使用SVM分类器对图像进行分类 svm = cv2.ml.SVM_create() svm.setType(cv2.ml.SVM_C_SVC) svm.setKernel(cv2.ml.SVM_LINEAR) svm.train(np.array(train_data), cv2.ml.ROW_SAMPLE, np.array(train_labels)) ``` 以上代码中,我们对每张训练集图片提取SURF特征并构造其Bag of Words向量,然后使用SVM分类器对图像进行分类。 ### 3. 检索阶段 ```python # 加载查询图片 query_img = cv2.imread('query.jpg') query_gray = cv2.cvtColor(query_img, cv2.COLOR_BGR2GRAY) query_kp, query_des = surf.detectAndCompute(query_gray, None) # 构造查询图片的Bag of Words向量 query_words = kmeans.predict(query_des) query_bow = np.zeros((1, 50)) for w in query_words: query_bow[0, w] += 1 # 计算查询向量与训练集中所有图像的距离 distances = [] for i in range(1, 11): img = cv2.imread(f'train/{i}.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) kp, des = surf.detectAndCompute(gray, None) words = kmeans.predict(des) bow_vector = np.zeros((1, 50)) for w in words: bow_vector[0, w] += 1 dist = np.linalg.norm(query_bow - bow_vector) distances.append((i, dist)) # 返回距离最近的前K张图片作为检索结果 k = 5 results = sorted(distances, key=lambda x: x[1])[:k] for r in results: print(f'train/{r[0]}.jpg') ``` 以上代码中,我们对查询图片提取SURF特征并构造其Bag of Words向量,然后计算查询向量与训练集中所有图像的距离,并返回距离最近的前K张图片作为检索结果。 ## 总结 BOW图像检索系统是一种基于特征向量的图像检索方法,在实际应用中具有广泛的应用。本文介绍了基于Python的BOW图像检索系统的设计思路和实现方法,希望能够对读者有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

打代码能当饭吃?

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值