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.计算正确率
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:
👨💻个人简介:深度学习图像领域工作者🎉总结链接: 链接中主要是个人工作的总结,每个链接都是一些常用demo,代码直接复制运行即可。包括: 📌1.工作中常用深度学习脚本 📌2.torch、numpy等常用函数详解 📌3.opencv图片、视频等操作 📌4.个人工作中的项目总结(纯干活) 链接:https://blog.csdn.net/qq_28949847/article/details/128
1cv::rectangle介绍1.1功能: 绘制一个简单的、粗的或填充的直角矩形或直角矩形框。1.2c++代码形式rectangle()[1/2]#includevoidcv::rectangle ( InputOutputArray img, Point pt1, Point pt2, constScalar& color, int thickness=1, int lineType=LINE_8, int shift=0 ) img 图像。pt1 矩形的顶点。pt2 与pt1相对的矩形的顶点。意思是pt1和pt2是对角顶点color 颜色或亮
Canny边缘检测Canny边缘检测是一种使用多级边缘检测算法检测边缘的方法。1986年,JohnF.Canny发表了著名的论文AComputationalApproachtoEdgeDetection,在该论文中详述了如何进行边缘检测。Canny()边缘检测步骤Canny边缘检测分为如下几个步骤:步骤1:去噪。噪声会影响边缘检测的准确性,因此首先要将噪声过滤掉。步骤2:计算梯度的幅度与方向。步骤3:非极大值抑制,即适当地让边缘“变瘦”。步骤4:确定边缘。使用双阈值算法确定最终的边缘信息。下面对上述步骤分别进行简单的介绍。1.应用高斯滤波去除图像噪声由于图像边缘非常容易受到噪声的干扰,因此为了
我需要将.xmlOpenCVhaar级联转换为txt文件。(OpenCV有一个基于Haar特征的级联分类器用于目标检测。)所以我需要了解xml。我想知道什么是“阶段”和“树”。树代表弱分类器吗?同一阶段的树是否组合成一个强分类器?这些阶段是级联的吗???在haarcascade_frontalface_alt.xml的树中,它说:37144-1.391422.04.0141958743333817e-0030.03379419073462490.8378106951713562我想知道数字代表什么。 最佳答案 我将尝试解释级联xml
ImportError:DLLloadfailed:%1isnotavalidWin32application有人知道怎么解决吗?当我尝试导入cv2时会出现此问题。我的笔记本电脑是64位的,安装了64位的python,我也把cv2.pyd文件放到了Python的site-packages文件夹下。我的PYTHONPATH值=C:\Python35;C:\Python35\DLLs;C:\Python35\Lib;C:\Python35\libs;C:\Users\CV\OpenCV\opencv\build\python\2.7\x64;%OPENCV_DIR%\bin;我的OPENC
程序和版本:Windows10、Mingw32withgcc6.1.0、Cmake3.6.1、(Code::blocks16.01)首先,我应该提到构建静态构建确实可以完美地工作,仅构建共享构建是行不通的,而且我没有找到针对我的特定问题的解决方法。我尝试使用上述程序作为共享构建来构建OpenCV3.1。使用cmake的默认设置,出现以下错误:[34%]LinkingCXXexecutable..\..\bin\opencv_test_core.exe../../lib/libopencv_ts310.a(ts.cpp.obj):ts.cpp:(.text$_ZN6cvtest2TS4i
我刚开始使用OpenCV。我下载了OpenCV2.4.9,并安装了MSVS2010。我的Windows是X64。我遵循了以下步骤:一个。在ConfigurationProperties下,单击Debugging->Environment并复制粘贴:PATH=C:\opencv\build\x86\vc10\binVC++目录->包含目录并添加条目:C:\opencv\build\includeVC++目录->库目录并添加条目:C:\opencv\build\x86\vc10\libLinker->Input->AdditionalDependencies并添加以下内容:opencv_c
我知道之前有人提出过这个问题,我已经尝试了所有发现的修复方法,但都无济于事。当我尝试导入cv2时,我收到消息:DLLloadfailed:%1isnotavalidWin32application.我在windows7,64bit上运行python2.7。我尝试使用以下方法安装cv2:python-mpipinstallcv2以及安装.whl文件(opencv_python-2.4.12-cp27-none-win_amd64.whl)。两次,cmd提示都告诉我它们已正确安装,但我仍然无法导入cv2。接下来我尝试的是下载最新版本的opencv并按照说明进行操作here安装它。我还尝试在
当我尝试流式传输ipcam时,我遇到了如下所示的错误"[tcp@000000000048c640]Portmissinginuriwarning:Erroropeningfile(/build/opencv/modules/videoio/src/cap_ffmpeg_impl.hpp:901)"importnumpyasnpimportcv2cv2.__file__cap=cv2.VideoCapture('http://admin:password@http://192.168.1.***/')#cap=cv2.VideoCapture('https://www.youtube.c
刚刚在PC上使用VisualStudio2013构建了OpenCV3,现在我正在尝试编写代码,但遗憾的是我不知道出了什么问题?#include"opencv2/opencv.hpp"#includeusingnamespacestd;usingnamespacecv;intmain(){VideoCapturevcap(0);if(!vcap.isOpened()){cout>frame;video.write(frame);imshow("Frame",frame);charc=(char)waitKey(33);if(c==27)break;}return0;1>------Bui