Bag of Visual Word (BoW, BoF, 词袋)

简介

BoW 是传统的计算机视觉方法,用一些特征(一些向量)来表示一个图像。BoW的核心思想是利用一组较为通用的特征,将图像用这些特征来表示,不同图像对于同一个特征的响应也是不同的,最终一个图像可以转化成关于这一组特征的一个频率直方图(向量)。这里有个挺清晰的介绍。BoW 常常用在 content-based image retrieval (CBIR) 任务上。

例如下面这张图(来源 Brown Computer Vision 2021 )形象的介绍了BoW的,首先有一堆图片,然后提取这些图片中的特征,然后提取具有代表性的通用特征,然后计算不同图像对于这些特征的响应,从而将图像转换成关于这组特征的一个特征向量。

实践

本文不过多的介绍理论部分,主要使用opencv来进行一些实践操作。

数据集

本文使用的是一个比较老的数据集是 ZuBuD 数据集,是苏黎世联邦理工构建的数据集,开放下载。数据集是苏黎世城市内的一些建筑,训练集有1005张图像,包含201个建筑,测试集有115张图像,用来测试 image retrieval,有ground truth信息,即指定来哪些图像是对应的,如下随便找了两张图片。


以下是 ground truth 的部分信息,例如第一行代表测试集中编号为 1 的图像对应到训练集中,应该是编号 100。

TEST	TRAIN
001 100
002 102
003 104
004 105
005 107
006 109
...
...

总体思路

  1. 对每个图像提取sift特征
  2. 将训练集的所有特征放在一起进行聚类
  3. 对训练集中的图像计算直方图
  4. 对测试集中的图像计算直方图
  5. 从训练集中找和测试图像直方图最接近的图像作为结果
  6. 计算正确率

代码部分

有了上述思路后,代码的逻辑也比较清晰了,下面给出所有的代码,详细的解释在注释里。

#1.对每个图像提取sift特征
#2.将训练集合的所有特征放在一起进行聚类
#3.对每个图像计算直方图
#4.对测试图像计算直方图
#5.从训练集中寻找和测试图像直方图最近接近的图像作为结果
#6.计算正确率 import cv2
import os
import matplotlib.pyplot as plt
import numpy as np
import time
from sklearn.cluster import MiniBatchKMeans DataPath = "../Dataset/ZuBuD" #数据集的根目录
TrainPath = os.path.join(DataPath, "png-ZuBuD") #训练集的根目录
TestPath = os.path.join(DataPath,"1000city","qimage") #测试集的根目录
trainList = os.listdir(TrainPath) #训练集图像的所有名字 TrainSIFTPath = "../Dataset/ZuBuD/Train_SIFT" #训练集图像SIFT保存的路径(保存在文件中时有用)
TestSIFTPath = "../Dataset/ZuBuD/Test_SIFT" #测试集图像SIFT保存的路径(保存在文件中时有用) TrainSIFT = []#训练集的SIFT特征,为了后面numpy方便拼接
TestSIFT = []#测试集的SIFT特征 Train_SIFT_dict = {}#同上,只不过用名字来索引特征
Test_SIFT_dict = {} #批量生成SIFT特征
def genSIFT(dataDir,outdir, outlist,outdict):
begin = time.time()
sift = cv2.SIFT_create()
imgList = os.listdir(dataDir)
if not os.path.exists(outdir):
os.mkdir(outdir)
count = 0
for name in imgList:
ext = os.path.splitext(name)[-1]
if ext!=".png" and ext!=".JPG" and ext!=".jpg" :
continue
#读取图片、转成灰度、提取描述子
path = os.path.join(dataDir,name)
imgdata = cv2.imread(path)
gray = cv2.cvtColor(imgdata,cv2.COLOR_BGR2GRAY)
_, des = sift.detectAndCompute(gray, None)
outlist.append(des)
outdict[name] = des
#np.save(os.path.join(outdir,name),des)
print(len(imgList),count)
count = count + 1
end = time.time() #聚类,也是生成通用特征、词袋,这里用的是MiniBatchKMeans,这个比KMeans快,精度没有差很多
def cluster(featureList, n):
#将所有训练图片的SIFT特征放在一起进行聚类
begin = time.time()
X = np.concatenate(featureList)
kmeans = MiniBatchKMeans(n_clusters=n, random_state=0,verbose=1).fit(X)
end = time.time()
return kmeans #计算余弦距离,为了计算相似度
def get_cos_similar(v1, v2):
num = float(np.dot(v1, v2))
denom = np.linalg.norm(v1) * np.linalg.norm(v2)
return 0.5 + 0.5 * (num / denom) if denom != 0 else 0 #读取groundtruth文件,生成数据对
def getGroundTruth(dataPath):
gtpair = {}
with open(os.path.join(dataPath,"zubud_groundtruth.txt")) as f:
gt = f.readlines()
for i, line in enumerate(gt):
if i == 0:
continue
test, train = line[:-1].split("\t")
gtpair[test] = train
return gtpair #根据聚类的结果,也就是词袋生成频率向量,这里就将图像转成了一个向量表示
def getFeatureHistogram(dataDict,kmeans):
outDict = {}
for k in dataDict.keys():
feat = dataDict[k]
his = np.bincount(kmeans.predict(feat))
if his.shape[0] < kmeans.n_clusters:
diff = kmeans.n_clusters - his.shape[0]
for i in range(diff):
his = np.append(his,0)
outDict[k] = his
return outDict #这里时进行测试,这里使用了一种比较朴素的方法,也就是测试图像
#和训练集里的图像挨个比较,取余弦距离最大的那个作为结果。
def predict(testHisDict, trainHisDict, gtpair):
predict = {} for testk in testHisDict.keys():
testhis = testHisDict[testk]
score = 0.0
index = ""
for traink in trainHisDict.keys():
trainhis = trainHisDict[traink]
s = get_cos_similar(testhis,trainhis)
if s > score:
score = s
index = traink
predict[testk] = index suc = 0
for k in predict.keys():
tk = k[5:8]
pk = predict[k][7:10]
if gtpair[tk] == pk:
suc = suc+1
return suc/len(predict) #将以上步骤串起来,调整聚类的类别,来观察精度
def pipeline(n_list):
result = [] #1.对训练集、测试集提取sift特征
t0 = time.time()
genSIFT(TrainPath,TrainSIFTPath,TrainSIFT,Train_SIFT_dict)
genSIFT(TestPath,TestSIFTPath,TestSIFT,Test_SIFT_dict)
t1 = time.time()
#2.读取ground truth
gtpair = getGroundTruth(DataPath) #3.对训练集提取的sift进行聚类,生成 visual word
for n in n_list:
t3 = time.time()
clu = cluster(TrainSIFT, n)
t4 = time.time()
#4.计算每个图像关于 visual word 的直方图
train_his = getFeatureHistogram(Train_SIFT_dict, clu)
test_his = getFeatureHistogram(Test_SIFT_dict, clu)
t5 = time.time()
#5.利用余弦距离计算相似度
acc = predict(test_his,train_his, gtpair)
t6 = time.time()
info = {"sift":t1-t0,"clu":t4-t3,"calvw":t5-t4,"predict":t6-t5,"acc":acc}
result.append(info)
print(info)
return result result = pipeline([50,100,300,600,1000,2000])
print(result)

测试结果

本文一共测试了6组聚类的类别,随着类别增多,准确的逐渐上升,但是太对类别准确度反而会下降,这是因为在实验中发现每张图像平均也就能提取1000~1500个特征点,2000个类别太多啦。下面是绘制的准确度折线图,因为1000 - 2000之间没有测试,因此可能准确率还会有所提升。600个类别的准确率为 75.65%, 1000个 准确率为 78.26%。

关于耗时,2020年 mac pro:

  • 提取所有图像 SIFT 特征,耗时 55s 左右。
  • 聚类 600 类,耗时 191s 左右,聚类 1000 类,耗时 251s 左右
  • 计算频率直方图,600 类大概 6s,1000 类 9s
  • 预测耗时基本都是 1.5s

[computer vision] Bag of Visual Word (BOW)的更多相关文章

  1. 模式识别之检索---Bag of visual word(词袋模型)

    visual words 视觉单词 http://blog.csdn.net/v_july_v/article/details/8203674 http://blog.csdn.net/pi9nc/a ...

  2. (转) WTF is computer vision?

        WTF is computer vision? Posted Nov 13, 2016 by Devin Coldewey, Contributor   Next Story   Someon ...

  3. 计算机视觉和人工智能的状态:我们已经走得很远了 The state of Computer Vision and AI: we are really, really far away.

    The picture above is funny. But for me it is also one of those examples that make me sad about the o ...

  4. Computer Vision Algorithm Implementations

    Participate in Reproducible Research General Image Processing OpenCV (C/C++ code, BSD lic) Image man ...

  5. Graph Cut and Its Application in Computer Vision

    Graph Cut and Its Application in Computer Vision 原文出处: http://lincccc.blogspot.tw/2011/04/graph-cut- ...

  6. Learning ROS for Robotics Programming Second Edition学习笔记(五) indigo computer vision

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

  7. Computer Vision Resources

    Computer Vision Resources Softwares Topic Resources References Feature Extraction SIFT [1] [Demo pro ...

  8. Computer Vision Tutorials from Conferences (3) -- CVPR

    CVPR 2013 (http://www.pamitc.org/cvpr13/tutorials.php) Foundations of Spatial SpectroscopyJames Cogg ...

  9. Computer Vision Tutorials from Conferences (2) -- ECCV

    ECCV 2012 (http://eccv2012.unifi.it/program/tutorials/) Vision Applications on Mobile using OpenCVGa ...

随机推荐

  1. Chapter08 面向对象(中级)

    Chapter08 面向对象(中级) 8.1 IDEA的使用 1. 快捷键 删除当前行, 默认是 ctrl + Y 自己配置 ctrl + d 复制当前行, 自己配置 ctrl + alt + 向下光 ...

  2. Excel VBA中写SQL,这些问题的方法你一定要牢记

    小爬之前的文章 [Excel VBA中写SQL,这些问题你一定为此头痛过]中详细讲诉了一些常见的VBA 中使用SQL遇到的问题,这里再补充两个常见的问题场景及对应的解决方案,希望你们看了后能够思路开阔 ...

  3. LeetCode-059-螺旋矩阵 II

    螺旋矩阵 II 题目描述:给你一个正整数 n ,生成一个包含 1 到 \(n^{2}\) 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix . 示例说明请见LeetCode ...

  4. zookeeper的JAVA API使用

    1.创建连接 2.创建节点 3.监听信息 Watcher.class 4.获取节点 Stat stat = new Stat(); zk.getData(Path,true,stat); 5.修改节点 ...

  5. 记一次NAS故障分析(ZFS NFS)

    问题: 使用vdbench进行单层100w目录,每个目录30个文件,共3000w文件读写时,在创建文件得时候IO会出现断断续续得情况. 分析过程: 1.  nfs抓包分析 使用vdbench创建一个文 ...

  6. git报错error: RPC failed; HTTP 500 curl 22 The requested URL returned error: 500

    报错 $ git push; Enumerating objects: 1002, done. Counting objects: 100% (1002/1002), done. Delta comp ...

  7. Kubernetes:Ingress总结(一)

    Blog:博客园 个人 参考:Ingress | Kubernetes.<Kubernetes进阶实战>.<Kubernetes网络权威指南 > 何谓Ingress?从字面意思 ...

  8. oneAPI DPC++学习资料和实验平台

    DPC++ 一种新的异构平台,弥补了OPENCL 编写复杂的难题.基于SYCL 抽象层.基于SYCL 有多种实现,其中DPC++是相对成熟的方案. 书籍 由Intel工程师撰写的免费电子图书 Data ...

  9. MATLAB绘制一幅中国地图

    今天博主跟大家讲一下如何用MATLAB制作一幅中国地图,那废话不多说,我们先看一下最终效果吧. mercator墨卡托圆柱投影地图 lambert兰伯特圆锥投影地图 一张中国地图大概包括以下要素: 中 ...

  10. 使用 Spring JdbcTemplate 框架出现 oracle 数据源连接泄露问题的解决方法

    1 问题 应用运行一段时间之后,无法执行写入数据库操作.底层使用的是 druid 连接池. 2 原因 使用 Spring JdbcTemplate 框架执行 oracle sql 语句之后,发现逻辑连 ...