本文对前面的几篇文章进行个总结,实现一个小型的图像检索应用。

一个小型的图像检索应用可以分为两部分:

  • train,构建图像集的特征数据库。
  • retrieval,检索,给定图像,从图像库中返回最类似的图像

构建图像数据库的过程如下:

  • 生成图像集的视觉词汇表(vocabulary)

提取图像集所有图像的sift特征

对得到的sifte特征集合进行聚类,聚类中心就是vocabulary

  • 对图像集中的图像重新编码表示,可使用bow或者vlad,这里选择vlad.
  • 将图像集中所有图像的vlad表示组合到一起得到一个vlad表,这就是查询图像的数据库。

得到图像集的查询数据后,对任一图像查找其在数据库中的最相似图像的流程如下:

  • 提取图像的sift特征
  • 加载vocabulary,使用vlad表示图像
  • 在图像数据库中查找与该vlad最相似的向量

构建图像集的特征数据库的流程通常是offline的,查询的过程则需要是实时的,基本流程参见下图:

由两部分构成:offline的训练过程以及online的检索查找

各个功能模块的实现

下面就使用vlad表示图像,实现一个小型的图像数据库的检索程序。下面实现需要的功能模块

  • 特征点提取
  • 构建vocabulary
  • 构建数据库

第一步,特征点的提取

不管是bow还是vlad,都是基于图像的局部特征的,本文选择的局部特征是sift,使用其扩展rootsift。提取到稳定的特征点尤为的重要,本文使用opencv体哦那个的siftdetecotr,实例化如下:

auto fdetector = xfeatures2d::sift::create(0,3,0.2,10);

create的声明如下:

static ptr<sift> cv::xfeatures2d::sift::create     (     int      nfeatures = 0,
        int      noctavelayers = 3,
        double      contrastthreshold = 0.04,
        double      edgethreshold = 10,
        double      sigma = 1.6 
    )
  • nfeatures 设置提取到的特征点的个数,每个sift的特征点都根据其对比度(local contrast)计算出来一个分数。设置了该值后,会根据分数排序,只保留前nfeatures个返回
  • noctavelayers 每个octave中的层数,该值可以根据图像的分辨率大小计算出来。d.lowe论文中该值为3
  • contrastthreshold 过滤掉低对比度的不稳定特征点,该值越大,提取到的特征点越少
  • edgethreshold 过滤边缘处的特征点,该值越大,提取到的特征点就越多
  • sigma 高斯滤波器的参数,该滤波器应用于第0个octave

个人的一些见解。

设置参数时,主要是设置contrastthresholdedgethresholdcontrastthreshold是过滤掉平滑区域的一些不稳定的特征点,edgethreshold是过虑类似边缘的不稳定关键点。设置参数时,应尽量保证提取的特征点个数适中,不易过多,也不要过少。另外,contrastthresholdedgethreshold的平衡,应根据要提取的目标是比较平滑的区域还是纹理较多的区域,来平衡这两个参数的设置。

对于有些图像,可能设置的提取特征点的参数叫严格,提取特征点的个数过少,这时候可改变宽松一些的参数。

auto fdetector = xfeatures2d::sift::create(0,3,0.2,10);
fdetector->detectandcompute(img,noarray(),kpts,feature);

if(kpts.size() < 10){
    fdetector = xfeatures2d::sift::create();
    fdetector->detectandcompute(img,noarray(),kpts,feature);
}

阈值10,可根据具体的情况进行调节。