今天主要回顾一下关于图像检索中VLAD(Vector of Aggragate Locally Descriptor)算法,免得时间一长都忘记了。关于源码有时间就整理整理。

一、简介

  虽然现在深度学习已经基本统一了图像识别与分类这个江湖,但是我觉得在某些小型数据库上或者小型的算法上常规的如BoW,FV,VLAD,T-Embedding等还是有一定用处的,如果专门做图像检索的不知道这些常规算法也免得有点贻笑大方了。

  如上所说的这些算法都大同小异,一般都是基于局部特征(如SIFT,SURF)等进行特征编码获得一个关于图像的feature,最后计算feature之间的距离,即使是CNN也是这个过程。下面主要就是介绍一下关于VLAD算法,它主要是得优点就是相比FV计算量较小,相比BoW码书规模很小,并且检索精度较高。

二、VLAD算法

  1. 第一步自然是提取局部特征,有了OpenCV这一步就仅仅是函数调用的问题了:

    SurfFeatureDetector detector;
    SurfDescriptorExtractor extractor;
    detector.detect( image_0, keypoints );
    extractor.compute( image_0, keypoints, descriptors );

      如果对特征有什么要求也可以根据OpenCV的源码或者网上的源码进行修改,最终的结果就是提取到了一幅图像的局部特征(还有关于局部特征参数的控制);

  2. 第二步本应是量化的过程,但是在量化之前需要事先训练一本码书,而码书同BoW一样是用K-means算法训练得到的,同样OpenCV里面也集成了这个算法,所以这个过程也再简单不过了:
    	kmeans(descriptors, numClusters, labels,
    TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 0.01 ),
    3, KMEANS_PP_CENTERS, centers);

      需要做的就是定义一些参数,如果自己写的话就不清楚了。另外码书的大小从64-256甚至更大不等,理论上码书越大检索精度越高。

  3. 第三步就是量化每一幅图像的特征了,其实如果数据库较小,可以直接使用全部图像的特征作训练,然后Kmeans函数中的labels中存储的就是量化的结果:即每一个特征距离那一个聚类中心最近。但是通常训练和量化是分开的,在VLAD算法中使用的是KDTree算法,KDTree算法是一种快速检索算法,OpenCV里同样集成了KDTree算法:
    const int k=1, Emax=INT_MAX;
    KDTree T(centers,false);
    T.findNearest(descriptors_row, k, Emax, idx_t, noArray(), noArray());

      通过KDTree下的findNearest函数找到与之最近的聚类中心,需要注意的是输入的STL的vector类型,返回的是centers的索引值;

  4. 量化结束之后就是计算特征和中心的残差,并对每一幅图像落在同一个聚类中心上的残差进行累加求和,并进行归一化处理,最后每一个聚类中心上都会得到一个残差的累加和,进行归一化时需要注意正负号的问题(针对不同的特征)。假设有k个聚类中心,则每一个聚类中心上都有一个128维(SIFT)残差累加和向量;
  5. 把这k个残差累加和串联起来,获得一个超长向量,向量的长度为k*d(d=128),然后对这个超长矢量做一个power normolization处理可以稍微提升检索精度,然后对这个超长矢量再做一次归一化,现在这个超长矢量就可以保存起来了。
  6. 假设对N幅图像都进行了上面的编码处理之后就会得到N个超长矢量,为了加快距离计算的速度通常需要进行PCA降维处理,关于PCA降维的理论同KDTree一样都很成熟,OpenCV也有集成,没有时间自己写就可以调用了:
    PCA pca( vlad, noArray(), CV_PCA_DATA_AS_ROW, 256 );
    pca.project(vlad,vlad_tt);

      输入训练矩阵,定义按照行或列进行降维,和降维之后的维度,经过训练之后就可以进行投影处理了,也可以直接调用特征向量进行矩阵乘法运算。这里有一点就是PCA的过程是比较费时的,进行查询的时候由于同样需要进行降维处理,所以可以直接保存投影矩阵(特征值矩阵),也可以把特征向量、特征值、均值都保存下来然后恢复出训练的pca,然后进行pca.project进行投影处理;

  7. 如果不考虑速度或者数据库规模不是很大时,就可以直接使用降维后的图像表达矢量进行距离计算了,常用的距离就是欧式距离和余弦距离,这里使用余弦距离速度更快。当然进行距离计算的基础就是已经设计好了训练过程和查询过程。

三、总结

  可以看到,整个VLAD算法结合OpenCV实现起来还是非常简单的,并且小型数据库上的检索效果还可以,但是当数据库规模很大时只使用这一种检索算法检索效果会出现不可避免的下降。另外在作者的原文中,针对百万甚至千万级的数据库时单单使用PCA降维加速距离的计算仍然是不够的,所以还会使用称之为积量化或乘积量化(Product Quantization)的检索算法进行加速,这个也是一个很有意思的算法,以后有机会再介绍它。

图像检索——VLAD的更多相关文章

  1. 图像检索(4):IF-IDF,RootSift,VLAD

    TF-IDF RootSift VLAD TF-IDF TF-IDF是一种用于信息检索的常用加权技术,在文本检索中,用以评估词语对于一个文件数据库中的其中一份文件的重要程度.词语的重要性随着它在文件中 ...

  2. 图像检索(6):局部敏感哈希索引(LSH)

    图像检索中,对一幅图像编码后的向量的维度是很高.以VLAD为例,基于SIFT特征点,设视觉词汇表的大小为256,那么一幅图像编码后的VLAD向量的长度为$128 \times 256 = 32768 ...

  3. 图像检索(5):基于OpenCV实现小型的图像数据库检索

    本文对前面的几篇文章进行个总结,实现一个小型的图像检索应用. 一个小型的图像检索应用可以分为两部分: train,构建图像集的特征数据库. retrieval,检索,给定图像,从图像库中返回最类似的图 ...

  4. 图像检索(3):BoW实现

    在上一篇文章中图像检索(2):均值聚类-构建BoF中,简略的介绍了基于sift特征点的BoW模型的构建,以及基于轻量级开源库vlfeat的一个简单实现. 本文重新梳理了一下BoW模型,并给出不同的实现 ...

  5. 图像检索(2):均值聚类-构建BoF

    在图像检索时,通常首先提取图像的局部特征,这些局部特征通常有很高的维度(例如,sift是128维),有很多的冗余信息,直接利用局部特征进行检索,效率和准确度上都不是很好.这就需要重新对提取到的局部特征 ...

  6. 图像检索(1): 再论SIFT-基于vlfeat实现

    概述 基于内容的图像检索技术是采用某种算法来提取图像中的特征,并将特征存储起来,组成图像特征数据库.当需要检索图像时,采用相同的特征提取技术提取出待检索图像的特征,并根据某种相似性准则计算得到特征数据 ...

  7. 哈希学习(2)—— Hashing图像检索资源

    CVPR14 图像检索papers——图像检索 1.  Triangulation embedding and democratic aggregation for imagesearch (Oral ...

  8. CVPR14 图像检索papers

    CVPR14年关于图像检索方面的papers,汇总成一个list,方便阅读. 图像检索 Triangulation embedding and democratic aggregation for i ...

  9. Bag of Features (BOF)图像检索算法

    1.首先.我们用surf算法生成图像库中每幅图的特征点及描写叙述符. 2.再用k-means算法对图像库中的特征点进行训练,生成类心. 3.生成每幅图像的BOF.详细方法为:推断图像的每一个特征点与哪 ...

随机推荐

  1. spring cloud 2.x版本 Gateway动态路由教程

    摘要 本文采用的Spring cloud为2.1.8RELEASE,version=Greenwich.SR3 本文基于前面的几篇Spring cloud Gateway文章的实现. 参考 Gatew ...

  2. IT兄弟连 Java语法教程 数组 使用foreach循环遍历数组元素

    从JDK5之后,Java提供了一种更简单的循环:foreach循环,也叫作增强for循环,这种循环遍历数组和集合更加简洁.使用foreach循环遍历数组和集合元素时,无需获得数组或集合的长度,无需根据 ...

  3. php-laravel框架用户验证(Auth)模块解析(一)

    一.初始化 使用php artisan命令进行初始化:php artisan make:auth 和 php artisan migrate(该命令会生成users表.password_resets表 ...

  4. css文本省略号

    这里记录下如何用CSS实现单行.多行文本溢出容器的时候用省略号代替溢出部分. 单行文本溢出容器时显示省略号的CSS实现方法 /* 规定当内容溢出元素框(容器)时隐藏 */ overflow: hidd ...

  5. eclipse强行停止buliding workspace

    使用Eclipse的过程中可能会遇到buliding workspace卡在一半走不动的情况. 出现这个情况往往是因为Eclipse太调皮了,需要拉出去打屁股,打一顿就好了. 开玩笑的,事实上出现这个 ...

  6. .net core入门-跨域访问配置

    Asp.net Core 跨域配置   一般情况WebApi都是跨域请求,没有设置跨域一般会报以下错误 No 'Access-Control-Allow-Origin' header is prese ...

  7. C# - WinFrm应用程序MessageBox自动关闭小实验

    概述 在程序中MessageBox弹出的对话框,用于向用户展示消息,这是一个模式窗口,可阻止应用程序中的其他操作,直到用户将其关闭.但是有时候在自动化程序中,如果弹出对话框,程序将会中断,等待人工的干 ...

  8. 再来五道剑指offer题目

    再来五道剑指offer题目 6.旋转数组的最小数字 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4, ...

  9. Thread之模板模式

    我们知道,在实际使用线程的时候,真正的执行逻辑都是写在run方法里面,run方法是线程的执行单元,如果我们直接使用Thread类实现多线程,那么run方法本身就是一个空的实现,如下: /** * If ...

  10. jqgrid后台处理搜索

    jqgrid后台处理搜索, 如果点击jqgrid自带的搜索,则向后台传递“_search”参数,和searchField.searchOper.searchString三个值.如下所示: string ...