图像检索之基于vlfeat实现SIFT特征

概述

基于内容的图像检索技术是采用某种算法来提取图像中的特征,并将特征存储起来,组成图像特征数据库。当需要检索图像时,采用相同的特征提取技术提取出待检索图像的特征,并根据某种相似性准则计算得到特征数据库中图像与待检索图像的相关度,最后通过由大到小排序,得到与待检索图像最相关的图像,实现图像检索。图像检索的结果优劣取决于图像特征提取的好坏,在面对海量数据检索环境中,我们还需要考虑到图像比对(图像相似性考量)的过程,采用高效的算法快速找到相似图像也至关重要。

在构建图像特征库的时候,通常不会使用原始的图像特征,这是由于Raw Feature有很多冗余信息,而且维度过高在构建特征数据库和匹配的时候效率较低。所以,通常要对提取到的原始特征进行重新编码。比较常用的三种编码方式:

  • BoF , Bog of Feature 源于文本处理的词袋模型(Bog,Bag of Words)
  • VLAD , Vector of Aggragate Locally Descriptor
  • FV , fisher vector

构建图像特征数据库,通常有以下几个步骤:

  • 图像预处理流程(增强,旋转,滤波,缩放等)
  • 特征提取(全局特征,局部特征:SIFT,SURF,CNN等)
  • 对每张图片提取的原始特征重新编码(BoF,VLAD,FV)形成图像的特征库

图像的特征库构建完成后,在检索阶段,主要涉及到特征的相似性度量准则,排序,搜索

  • 提取图像的特征,
  • 特征编码
  • 在图像特征库中进行检索
  • 返回相似性较高的结果

SIFT特征

SIFT特征的讲解已经很多了,之前的博客也有过介绍。本文就借助vlfeat对SIFT特征的提取过程做一个总结。
一个SIFT特征有两部分组成:关键点(keypoint)和对应特征描述子(Descriptor)。使用SIFT detector 进行SIFT关键点的提取,然后使用SIFT descriptor计算关键点的描述子。也可以独立的使用SIFT detector进行SIFT 关键点的提取,或者使用SIFT descriptor进行别的关键点描述子的计算。

一个SIFT keypoint是一块圆形区域并且带有方向,使用4个参数描述该区域的几何结构:

  • keypoint的中心位置的坐标(x,y)
  • keypoint的scale(圆形区域的半径r)
  • keypoint的方向(使用弧度表示的角度θ)

一个SIFT关键点由4个参数确定:

  • 高斯尺度的组数o=log2min(m,n)−3=log2(512)−3=6
  • 构建第0组,将原图像进行上采样,宽和高增加一倍得到图像I0。
  • 第0层I0∗G(x,y,σ0)
  • 第1层I0∗G(x,y,kσ0)
  • 第2层I0∗G(x,y,k2σ0)
  • 构建第1组,将I0进行降采样,得到图像I1
  • 第0层I1∗G(x,y,2σ0)
  • 第1层I1∗G(x,y,2kσ0)
  • 第2层I1∗G(x,y,2k2σ0)
  • ...
  • 构建第o组,第s层 Io∗G(x,y,2oksσ)

在Lowe的算法实现中\(\sigma_0 = 1.6,o_min = -1\)。\(o_min = -1\)表示金字塔的第0组是原图像上采样得到的,宽和高加一倍。

DoG 极值点检测

高斯图像金字塔构建完成后,将同一组的相邻两层相减就得到了\(DoG\)金字塔。

每组的层数\(S = 3\),也就是说每组可以得到两层的\(DoG\)图像,以第一组为例:其尺度为\(\sigma,k\sigma\),只有两项是无法求取极值的,需要左右两边都有尺度。由于无法比较取得极值,那么我们就需要继续对每组的图像进行高斯模糊,使得尺度形成\(\sigma,k\sigma,k^2\sigma,k^3\sigma,k^4\sigma\)这样就可以选择中间的三项\(k\sigma,k^2\sigma,k^3\sigma\)

检测关键点,就是在\(DoG\)的图像空间中寻找极值点,每个像素点要和其图像域(同一尺度空间)和尺度域(相邻的尺度空间)的所有相邻点进行比较,当其大于(或者小于)所有相邻点时,改点就是极值点。如图所示,中间的检测点要和其所在图像的\(3 \times 3\)邻域8个像素点,以及其相邻的上下两层的\(3\times 3\)领域18个像素点,共26个像素点进行比较。

删除不好的极值点

删除两类极值点

  • 在对比度比较低低的区域检测到的极值点
  • 在图像的边缘部分检测到的极值点

确定关键点的方向

统计关键点邻域像素的梯度方向分布来确定关键点的方向。具体步骤如下:

  • 计算以特征点为中心,以\(3 \times1.5 \sigma\)为半径的区域图像的幅角和幅值,每个像点\(L(x,y)\)的梯度的模\(m(x,y)\)以及方向\(\theta(x,y)\)可通过下面公式求得

  • 统计像素点的幅角和幅值的直方图,梯度方向的直方图的横轴是梯度方向的角度(梯度方向的范围是0到360度,直方图每36度一个柱共10个柱,或者没45度一个柱共8个柱),纵轴是梯度方向对应梯度幅值的累加,在直方图的峰值就是特征点的主方向。在梯度直方图中,当存在一个相当于主峰值80%能量的柱值时,则可以将这个方向认为是该特征点辅助方向。所以,一个特征点可能检测到多个方向(也可以理解为,一个特征点可能产生多个坐标、尺度相同,但是方向不同的特征点)。

得到特征点的主方向后,对于每个特征点可以得到三个信息\(k(x,y,r,\theta)\),即位置、尺度和方向。由此可以确定一个SIFT特征区域,一个SIFT特征区域由三个值表示,中心表示特征点位置,半径表示关键点的尺度,箭头表示主方向。
具有多个方向的关键点可以被复制成多份,然后将方向值分别赋给复制后的特征点,一个特征点就产生了多个坐标、尺度相等,但是方向不同的特征点。

计算关键点描述子

在检测部分已经得到了SIFT关键点的位置,尺度和方向信息,生成关键点的描述子,就是使用一个向量来描述关键点及其邻域像素的信息。
由以下步骤生成描述子:

  • 为了保证旋转不变性,将关键点为中心的邻域像素的坐标轴进行旋转,将\(x\)轴旋转至关键点主方向,如下图:

  • 分块计算邻域内像素的梯度方向直方图,以关键点为中心的\(16\times16\)的区域内,划分\(4\times4\)个块,分别计算每个块的梯度直方图,如下图:

每个块的梯度直方方向直方图的计算方式,和求关键点主方向时类似:此时每个区域的梯度直方图在0-360之间划分为8个方向区间,每个区间为45度,即每个种子点有8个方向的梯度强度信息,最后将得到的\(4\times4\times8=128\)维的特征向量。

  • 为了去除光照变化的影响,需对上述生成的特征向量进行归一化处理。在归一化处理后,在128维的单位向量中,对大于0.2的要进行截断处理,即大于0.2的值只取0.2,然后重新进行一次归一化处理,其目的是为了提高鉴别性。0.2 是实验得出的经验值。

vlfeat实现的sift特征提取

vlfeat是一个开源的轻量级的计算机视觉库,主要实现图像局部特征的提取和匹配以及一些常用的聚类算法。其对sift特征提取的各个步骤进行了封装,使用的方法如下:

1.调用vl_sift_new初始化VlSiftFilt,设置sift提取时参数信息,如:图像的大小,Octave的个数,每个Octave的中的层数,起始的Octave的index. 各个参数的具体含义可以参考上面sift特征提取的方法。

2.设置剔除不稳定关键点的阈值。在上面提到,sift在进行极值检查后,要剔除两类不稳定的极值点:1.对比度较低区域的极值点;2.边缘部分的极值点。 可以调用

  • vl_sift_set_peak_thresh设置接受极值点是一个关键点的最小对比度。 该值越小,提取到的关键点就越多。
  • y vl_sift_set_edge_thresh()设置一个极值点是在边缘上的阈值。 该值越小,提取到的关键点就越多。

这两个参数对最终提取到的特征点个数有很大的影响。

3.初始化工作完成后,可以循环的对尺度空间的每个Octave进行处理了

  • 调用 vl_sift_process_first_octave()vl_sift_process_next_octave()来计算下一个DoG尺度空间。
  • 调用vl_sift_detect进行关键点提取
  • 对每一个提取到的关键点

vl_sift_calc_keypoint_orientations计算关键点的方向,可能多于一个

l_sift_calc_keypoint_descriptor计算每个方向的特征描述子。

4.vl_sift_delete释放资源。

具体代码如下:

// 初始化
    const string file = "../0.jpg";
    Mat img = imread(file,IMREAD_GRAYSCALE);
    Mat color_img = imread(file);
    Mat float_img;
    img.convertTo(float_img,CV_32F);

    int rows = img.rows;
    int cols = img.cols;
    VlSiftFilt* vl_sift =  vl_sift_new(cols,rows,4,3,0);
    vl_sift_set_peak_thresh(vl_sift,0.04);
    vl_sift_set_edge_thresh(vl_sift,10);

    vl_sift_pix *data = (vl_sift_pix*)(float_img.data);

    vector<VlSiftKeypoint> kpts;
    vector<float*> descriptors;

    vl_sift_extract(vl_sift,data,kpts,descriptors);

/*
    Extract sift using vlfeat
    parameters:
        vl_sfit, VlSiftFilt*
        data , image pixel data ,to be convert to float
        kpts, keypoint list
        descriptors, descriptor. Need to free the memory after using.
*/
void vl_sift_extract(VlSiftFilt *vl_sift, vl_sift_pix* data,
                    vector<VlSiftKeypoint> &kpts,vector<float*> &descriptors) {

    // Detect keypoint and compute descriptor in each octave
    if(vl_sift_process_first_octave(vl_sift,data) != VL_ERR_EOF){
        while(true){
            vl_sift_detect(vl_sift);

            VlSiftKeypoint* pKpts = vl_sift->keys;
            for(int i = 0; i < vl_sift->nkeys; i ++) {

                double angles[4];
                // 计算特征点的方向,包括主方向和辅方向,最多4个
                int angleCount = vl_sift_calc_keypoint_orientations(vl_sift,angles,pKpts);

                // 对于方向多于一个的特征点,每个方向分别计算特征描述符
                // 并且将特征点复制多个
                for(int i = 0 ; i < angleCount; i ++){
                    float *des = new float[128];
                    vl_sift_calc_keypoint_descriptor(vl_sift,des,pKpts,angles[0]);
                    descriptors.push_back(des);
                    kpts.push_back(*pKpts);
                }
                pKpts ++;
            }
            // Process next octave
            if(vl_sift_process_next_octave(vl_sift) == VL_ERR_EOF) {
                break ;
            }
        }
    }
}

vlfeat中sift提取接受的是float类型的数据,所以要先将读到的数据图像转换为float
和OpenCV中的sift提取的对比结果如下:

  1. vlfeat提取的特征点是用绿色画出来的,共有1961个特征点。
  2. OpenCV的是蓝色,有4617个特征点。

Summary

几年前写过一篇关于SIFT的文章,SIFT特征详解 当时多是从理论上。现在在做图像检索的时候,发现还是有很多东西理解的不是很清晰,比如:关键点的多个方向,不稳定极值点的剔除以及梯度方向直方图计算等等。

正在做一个图像检索的项目,陆续将项目的中学到一些知识总结下来,下一篇是关于均值聚类的,对提取到的图像特征进行聚类生成视觉特征(Visul Feature)

到此这篇关于图像检索之基于vlfeat实现SIFT的文章就介绍到这了,更多相关图像检索vlfeat内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 图像检索之IF-IDF,RootSift,VLAD

    TF-IDF TF-IDF是一种用于信息检索的常用加权技术,在文本检索中,用以评估词语对于一个文件数据库中的其中一份文件的重要程度.词语的重要性随着它在文件中出现的频率成正比增加,但同时会随着它在文件数据库中出现的频率成反比下降.像'的','我们','地'等这些常用词在所有文章中出现的频率会很高,并不能很好的表征一个文档的内容. 同样的在图像检索中也引入了IF-IDF权重, 词频(Term Frequency,TF) 一个visual word在一个图像中出现的频率的很高,则说明该visual

  • python实现图像检索的三种(直方图/OpenCV/哈希法)

    简介: 本文介绍了图像检索的三种实现方式,均用python完成,其中前两种基于直方图比较,哈希法基于像素分布. 检索方式是:提前导入图片库作为检索范围,给出待检索的图片,将其与图片库中的图片进行比较,得出所有相似度后进行排序,从而检索结果为相似度由高到低的图片.由于工程中还包含Qt界面类.触发函数等其他部分,在该文档中只给出关键函数的代码. 开发系统:MacOS 实现方式:Qt + Python 方法一:自定义的直方图比较算法 a) 基本思路 遍历图片像素点,提取R\G\B值并进行对应的计数,得

  • opencv3/C++ PHash算法图像检索详解

    PHash算法即感知哈希算法/Perceptual Hash algorithm,计算基于低频的均值哈希.对每张图像生成一个指纹字符串,通过对该字符串比较可以判断图像间的相似度. PHash算法原理 将图像转为灰度图,然后将图片大小调整为32*32像素并通过DCT变换,取左上角的8*8像素区域.然后计算这64个像素的灰度值的均值.将每个像素的灰度值与均值对比,大于均值记为1,小于均值记为0,得到64位哈希值. PHash算法实现 将图片转为灰度值 将图片尺寸缩小为32*32 resize(src

  • 图像检索之基于vlfeat实现SIFT特征

    概述 基于内容的图像检索技术是采用某种算法来提取图像中的特征,并将特征存储起来,组成图像特征数据库.当需要检索图像时,采用相同的特征提取技术提取出待检索图像的特征,并根据某种相似性准则计算得到特征数据库中图像与待检索图像的相关度,最后通过由大到小排序,得到与待检索图像最相关的图像,实现图像检索.图像检索的结果优劣取决于图像特征提取的好坏,在面对海量数据检索环境中,我们还需要考虑到图像比对(图像相似性考量)的过程,采用高效的算法快速找到相似图像也至关重要. 在构建图像特征库的时候,通常不会使用原始

  • opencv-python 提取sift特征并匹配的实例

    我就废话不多说,直接上代码吧! # -*- coding: utf-8 -*- import cv2 import numpy as np from find_obj import filter_matches,explore_match from matplotlib import pyplot as plt def getSift(): ''' 得到并查看sift特征 ''' img_path1 = '../../data/home.jpg' #读取图像 img = cv2.imread(i

  • 浅析ORB、SURF、SIFT特征点提取方法以及ICP匹配方法

    目录 main.cpp CMakeLists.txt 执行效果 ICP CMakeLists.txt 执行效果 在进行编译视觉SLAM时,书中提到了ORB.SURF.SIFT提取方法,以及特征提取方法暴力匹配(Brute-Force Matcher)和快速近邻匹配(FLANN).以及7.9讲述的3D-3D:迭代最近点(Iterative Closest Point,ICP)方法,ICP 的求解方式有两种:利用线性代数求解(主要是SVD),以及利用非线性优化方式求解. 完整代码代码如下: 链接:h

  • 基于OpenCV实现小型的图像数据库检索功能

    本文对前面的几篇文章进行个总结,实现一个小型的图像检索应用. 一个小型的图像检索应用可以分为两部分: train,构建图像集的特征数据库. retrieval,检索,给定图像,从图像库中返回最类似的图像 构建图像数据库的过程如下: 生成图像集的视觉词汇表(Vocabulary) 提取图像集所有图像的sift特征 对得到的sifte特征集合进行聚类,聚类中心就是Vocabulary 对图像集中的图像重新编码表示,可使用BoW或者VLAD,这里选择VLAD. 将图像集中所有图像的VLAD表示组合到一

  • 应用OpenCV和Python进行SIFT算法的实现详解

    应用OpenCV和Python进行SIFT算法的实现 如下图为进行测试的gakki101和gakki102,分别验证基于BFmatcher.FlannBasedMatcher等的SIFT算法,对比其优劣.为体现出匹配效果对于旋转特性的优势,将图gakki101做成具有旋转特性的效果. 基于BFmatcher的SIFT实现 BFmatcher(Brute-Force Matching)暴力匹配,应用BFMatcher.knnMatch( )函数来进行核心的匹配,knnMatch(k-nearest

  • python利用opencv实现SIFT特征提取与匹配

    本文实例为大家分享了利用opencv实现SIFT特征提取与匹配的具体代码,供大家参考,具体内容如下 1.SIFT 1.1.sift的定义 SIFT,即尺度不变特征变换(Scale-invariant feature transform,SIFT),是用于图像处理领域的一种描述.这种描述具有尺度不变性,可在图像中检测出关键点,是一种局部特征描述子. 1.2.sift算法介绍 SIFT由David Lowe在1999年提出,在2004年加以完善 .SIFT在数字图像的特征描述方面当之无愧可称之为最红

  • OpenCV实现特征检测和特征匹配方法汇总

    目录 1.SURF 2.SIFT 3.ORB 4.FAST 5.Harris角点 一幅图像中总存在着其独特的像素点,这些点我们可以认为就是这幅图像的特征,成为特征点.计算机视觉领域中的很重要的图像特征匹配就是一特征点为基础而进行的,所以,如何定义和找出一幅图像中的特征点就非常重要.这篇文章我总结了视觉领域最常用的几种特征点以及特征匹配的方法. 在计算机视觉领域,兴趣点(也称关键点或特征点)的概念已经得到了广泛的应用, 包括目标识别. 图像配准. 视觉跟踪. 三维重建等. 这个概念的原理是, 从图

  • 基于Python和openCV实现图像的全景拼接详细步骤

    基本介绍 图像的全景拼接,即"缝合"两张具有重叠区域的图来创建一张全景图.其中用到了计算机视觉和图像处理技术有:关键点检测.局部不变特征.关键点匹配.RANSAC(Random Sample Consensus,随机采样一致性)和透视变形. 具体步骤 (1)检测左右两张图像的SIFT关键特征点,并提取局部不变特征 : (2)使用knnMatch检测来自右图(左图)的SIFT特征,与左图(右图)进行匹配 : (3)计算视角变换矩阵H,用变换矩阵H对右图进行扭曲变换: (4)将左图(右图)

  • Python语言实现SIFT算法

    目录 一.什么是SIFT算法 二.准备工作 2.1 实验设备 2.2 OpenCV安装 三.实验工作 3.1 图像选择 3.2 程序实现 3.3 程序结果 本文侧重于如何使用Python语言实现SIFT算法 所有程序已打包:基于OpenCV-Python的SIFT算法的实现 一.什么是SIFT算法   SIFT,即尺度不变特征变换(Scale-invariant feature transform,SIFT),是用于图像处理领域的一种描述.这种描述具有尺度不变性,可在图像中检测出关键点,是一种局

随机推荐