摘自:策略算法工程师之路-基于内容的图像检索

BoW - Bag of Words

SIFT - Scale Invariant Feature Transform,

基于SIFT和CNN特征的通用检索流程 - AIUAI

From: https://www.robots.ox.ac.uk/~vgg/publications/2012/Arandjelovic12/presentation.pdf

1. BoW 模型

BoW 模型最初被用在文本分类中,将文档表示成特征矢量.

BoW 模型基本思想是,假定对于一个文本,忽略其词序和语法、句法仅仅将其看做是一些词汇的集合,而文本中的每个词汇都是独立的.

如:

文档1:John likes to watch movies. Mary likes too

文档2:John also likes to watch football games.

对于给定词典:

Vocabulary ={ "John": 1, "likes":2, "to": 3, "watch":4, "movies":5, "also":6, "football":7, "games":8, "Mary": 9, "too": 10 }

上述文档可以表示成:

文档1: [1, 2, 1, 1, 1, 0, 0, 0, 1, 1]

文档2: [1, 1,1, 1, 0, 1, 1, 1, 0, 0]

在计算机图像处理中也借鉴了BOW的思想,假设一张图像是有若干视觉词汇组成.

什么样的视觉词典是期望的?

  • 光照不敏感
  • 尺度不敏感
  • 视角变化不敏感
  • 旋转不变
  • ...

2. SIFT

SIFT特征之杂七杂八解析 - AIUAI

SIFT 算法简单来讲,可分为以下几步:

2.1. 多分辨率图像金字塔

想象人从不同距离看同一个事物,不同尺度的同一个事物从不同视角反映了事物的本质. 距离越远尺度越小更反映事物的全局特性,相反更反映事物的局部特性.

2.2. 极值点检测

为了寻找尺度空间的极值点,每个像素点要和其图像域(同一尺度空间)和尺度域(相邻的尺度空间)的所有相邻点进行比较,当其大于(或者小于)所有相邻点时,改点就是极值点.

如图所示,中间的检测点要和其所在图像的3×3邻域8个像素点,以及其相邻的上下两层的3×3领域18个像素点,共26个像素点进行比较.

2.3. 特征点梯度直方图生成

通过对特征点周围的像素进行分块,计算块内梯度直方图,生成具有独特性的向量,这个向量是该区域图像信息的一种抽象,具有唯一性.

得到的梯度直方图就是最后SIFT特征向量.

SIFT特征点的检测实例如图:

3. SIFT 特征构建 BoW

对提取的SIFT特征点K-means聚类:

如下三个Cluster:

如此,每个Cluster的中心即是需要的视觉词典(Visual Vocabulary),如下:

对图像检测出的SIFT特征点,指派给离它最近的中心点(将这一步称为hard-assignment),如此得到图像的视觉词汇分布.

基于BOW的图像检索算法可以描述如下:

[1] - 提取图像库中所有图像的局部特征(如SIFT、SURF、ORB等),得到特征集合 F.

[2] - 对特征集合 F 进行聚类,得到 k 个聚类中心 {Ci|i=1,...,k},每个聚类中心 Ci 表示一个视觉词汇. 聚类中心的集合就是视觉词典.

[3] - 计算特征 fi 属于哪个词汇 Ci(距离该聚类中心的距离最近.)

[4] - 统计每个词汇 Ci 在各图像中出现的频次,得到一维的特征向量,即 BoW 表示.

基于BOW的方法仅仅关注图像的局部特征而忽略了图像的全局语义,导致会召回不少语义差异较大的图像.

4. Python 实现

import cv2 import numpy as np from sklearn.cluster import KMeans from scipy.cluster.vq import * from sklearn import preprocessing from PIL import Image #加载数据集 imgFiles = ['1.jpg', '2.jpg', '3.jpg', '4.jpg', '5.jpg'] #聚类中心数/视觉词典数 numWords = 64 #提取图像SIFT特征 sift = cv2.xfeatures2d.SIFT_create() des_list=[] for i in range(0, len(imgFiles)): img=cv2.imread(imgFiles[i]) #转换成灰度图像 gray=cv2.cvtColor(img,cv2.COLOR_RGB2GRAY) #sift kp, des = sift.detectAndCompute(gray,None) #kp, des = sift.detectAndCompute(img1, None) des_list.append((image_path, des)) #视觉词典生成 #生成向量数组(堆叠所有sift特征,以进行 K-means聚类) descriptors = des_list[0][1] for image_path, descriptor in des_list[1:]: descriptors = np.vstack((descriptors, descriptor)) #K-means聚类生成视觉词典 print("开始K-means聚类: %d words, %d key points" %(numWords, descriptors.shape[0])) voc, variance = kmeans(descriptors, numWords, 1) #图像视觉单词抽取 im_features = np.zeros((len(image_paths), numWords), "float32") for i in range(0,len(imgFiles)): #将图像的SIFT特征转换成视觉单词分布 words, distance = vq(des_list[i][1],voc) for w in words: #单张图像单词出现频次统计 im_features[i][w] += 1 #Tf-Idf计算 #统计idf nbr_occurences = np.sum((im_features > 0) * 1, axis = 0) idf = np.array(np.log((1.0*len(imgFiles)+1) / (1.0*nbr_occurences + 1)), 'float32') # tf*idf im_features = im_features*idf # L2 归一化 im_features = preprocessing.normalize(im_features, norm='l2') #查询 #读取图像 query = imgFiles[idx] im = cv2.imread(query) # 提取图像sift特征 des_list = [] gray = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY) kp, des = sift_det.detectAndCompute(gray, None) des_list.append((image_path, des)) descriptors = des_list[0][1] # 抽取图像Tf-Idf特征 test_features = np.zeros((1, numWords), "float32") words, distance = vq(descriptors,voc) for w in words: test_features[0][w] += 1 test_features = test_features*idf # 归一化 test_features = preprocessing.normalize(test_features, norm='l2') # 计算所有图像的相似度 scores = np.dot(test_features, im_features.T) rank_ID = np.argsort(-scores) # 输出Top最相似的图像 for i, ID in enumerate(rank_ID[0][0:20]): img = Image.open(imgFiles[ID]) plt.imshow(img) plt.show()
Last modification:February 20th, 2021 at 06:59 pm