当前位置:   article > 正文

ROS-3DSLAM(十二)lvi-sam源代码阅读10 —— visual_loop阅读3 + ORB学习_dvision的orb检测

dvision的orb检测

2021SC@SDUSC

(十二)lvi-sam源代码阅读10 —— visual_loop阅读3 + ORB学习

visual_loop

DUtils文件夹

DException

定义异常信息

Timestamp
//成员变量
    /// Seconds
    unsigned long m_secs;	// seconds
    /// Microseconds
    unsigned long m_usecs;	// microseconds

//主要方法
 setTime //设置时间戳的时间
 getTime //获取时间戳中的之间
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
Random

生成符合高斯分布的随机数

/**
 * Returns a random number in the range [0..1]
 * @return random T number in [0..1]
 */
template <class T>
static T RandomValue(){
	return (T)rand()/(T)RAND_MAX;
}

/**
 * Returns a random number in the range [min..max]
 * @param min
 * @param max
 * @return random T number in [min..max]
 */
template <class T>
static T RandomValue(T min, T max){
    return Random::RandomValue<T>() * (max - min) + min;
}

/** 
 * Returns a random number from a gaussian distribution
 * @param mean
 * @param sigma standard deviation
 */
template <class T>
//给定数学期望和标准差
static T RandomGaussianValue(T mean, T sigma)
{
    // Box-Muller transformation
    T x1, x2, w, y1;

    do {
      //2.就是2.0 是double
      x1 = (T)2. * RandomValue<T>() - (T)1.;
      x2 = (T)2. * RandomValue<T>() - (T)1.;
      w = x1 * x1 + x2 * x2;
    } while ( w >= (T)1. || w == (T)0. );

    w = sqrt( ((T)-2.0 * log( w ) ) / w );
    y1 = x1 * w;

    return( mean + y1 * sigma );
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

生成符合高斯分布或者其他任意分布的随机数 https://www.cnblogs.com/mightycode/p/8370616.html

DVision文件夹

DVision.h

DVision本身是一个开源的库,在python和c++中都有相应的依赖和库,具有计算机视觉功能的类的集合。

本项目应该是嵌入了该开源库的部分内容。

在文件内部定义了一个命名空间DVision,但是里面并没有内容(应该是将原本的库中命名空间中的内容删除了)

BRIEF

BRIEF是ORB特征点中的描述子。为了对BRIEF有更多的了解,我首先学习了《SLAM14讲》中第七讲的特征点的部分,这一部分也主要是以ORB为例进行讲解的。

该文件的作用是对于给定的图像和图像中的关键点,求出每个点的BRIEF描述子。

//成员变量
/// Descriptor length in bits
int m_bit_length;

/// Patch size
int m_patch_size;

/// Type of pairs
Type m_type;

/// Coordinates of test points relative to the center of the patch
std::vector<int> m_x1, m_x2;
std::vector<int> m_y1, m_y2;

//关键函数

//生成选择的随机点的位置,存储在m_的vector中
void BRIEF::generateTestPoints()

//返回给定图像中给定关键点的简要描述符
void BRIEF::compute(const cv::Mat &image,  //图像
    const std::vector<cv::KeyPoint> &points,   //
    vector<bitset> &descriptors,  //描述子
    bool treat_image) const
{
  const float sigma = 2.f;
  const cv::Size ksize(9, 9);
  
  cv::Mat im;
  if(treat_image)
  {
    cv::Mat aux;
    if(image.depth() == 3)
    {
      cv::cvtColor(image, aux, CV_RGB2GRAY);
    }
    else
    {
      aux = image;
    }

    cv::GaussianBlur(aux, im, ksize, sigma, sigma);
    
  }
  else
  {
    im = image;
  }
  
  assert(im.type() == CV_8UC1);
  assert(im.isContinuous());
  
  // use im now
  const int W = im.cols;
  const int H = im.rows;
  
  descriptors.resize(points.size());
  //C++的 bitset 在 bitset 头文件中,它是一种类似数组的结构,它的每一个元素只能是0或1,每个元素仅用1bit空间。
  std::vector<bitset>::iterator dit; // 存储每个特征子

  std::vector<cv::KeyPoint>::const_iterator kit;
  
  int x1, y1, x2, y2;
  
  dit = descriptors.begin();
  for(kit = points.begin(); kit != points.end(); ++kit, ++dit)
  {
    dit->resize(m_bit_length);
    dit->reset();

    for(unsigned int i = 0; i < m_x1.size(); ++i)
    {
      x1 = (int)(kit->pt.x + m_x1[i]);
      y1 = (int)(kit->pt.y + m_y1[i]);
      x2 = (int)(kit->pt.x + m_x2[i]);
      y2 = (int)(kit->pt.y + m_y2[i]);
      
      if(x1 >= 0 && x1 < W && y1 >= 0 && y1 < H 
        && x2 >= 0 && x2 < W && y2 >= 0 && y2 < H)
      {
        //判断这两个被选中的像素点的大小
        if( im.ptr<unsigned char>(y1)[x1] < im.ptr<unsigned char>(y2)[x2] )
        {
          //将dit的第i位设置成1
          dit->set(i);
        }        
      } // if (x,y)_1 and (x,y)_2 are in the image
            
    } // for each (x,y)
  } // for each keypoint
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91

bitset https://www.cnblogs.com/magisk/p/8809922.html

前置学习

特征点法

基于特征点的前端,长久以来都是视觉里程计的主流方法。

1.1 特征点

视觉里程计的核心问题是如何根据图像估计相机运动。比较方便的做法是:从图像中选择比较有代表性的点,这些点在相机视角发生变化后会保持不变。在经典SLAM问题中,我们称这些点为路标。而在视觉SLAM问题中,路标则是指图像特征

特征(featrue):是图像信息的另一种数字表达形式。

仅凭像素的灰度值特征,不能判定哪些地方是同一个点(灰度值受光照、形变、物体材质的影响严重)。

特征点:图像里一些特别的地方。

一种直观的提取特征点的方式就是在不同图像间辨认角点,确定他们的对应关系。在这种做法中,角点就是所谓的特征

角点的提取算法:Harris角点、FAST角点、GFTT角点…

但是单纯的角点不能满足很多需求(eg:从远处看上去是角点的地方,当相机距离靠近后就可能不再显示为角点了)。为此,出现了很多更加稳定的局部图像特征,如SIFT、SURF、ORB等等。

这些人工设计的特征点能够拥有如下性质:

  • 可重复性(Repeatability):相同的特征点可以在不同的图像中找到
  • 可区别性(Distinctiveness):不同的特征有不同的表述
  • 高效性(Efficiency):同一图像中,特征点的数量应远小于像素的数量
  • 本地性(Locality):特征仅与一小片图像区域相关

特征点:由关键点(Key-Point)和描述子(descriptor)

  • 关键点:是指该特征点在图像里的位置,有些特征点还具有朝向、大小等信息。
  • 描述子:通常是一个向量,按照某种人为设计的方式,描述该关键点周围像素的信息。描述子按照“外观相似的特征应该具有相似的描述子”的原则来设计。因此,只要两个特征点的描述子在向量空间上的距离相近,我们可以认为他们是同样的特征点。

ORB(Oriented FAST and Rotated BRIEF)特征,是目前比较有代表性的实时图像特征。改进了FAST检测子中不具有方向性的问题,采用速度极快的二进制描述子BRIEF(Binary Robust Independenct Elementary Feature)。ORB在保持了特征子具有旋转、尺度不变性的同时,在速度方面提升明显,对于实时性要求很高的SLAM来说是个很好的选择。

1.2 ORB特征

ORB特征由关键点和描述子两部分组成。它的关键点称为“Oriented FAST”,是一种改进的FAST角点;它的描述子称为BRIEF。提取ORB特征分为如下两个步骤:

  1. FAST角点提取:找出图像中的角点。相较于原版的FAST,ORB中计算了特征点的主方向,为后续BRIEF描述子增加了旋转不变特性
  2. BRIEF描述子:对前一步提取出特征点的周围图像区进行描述。ORB和BRIEF进行了一些改进,主要是指在BRIEF中使用了先前计算的方向信息。
FAST关键点

FAST是一种角点,主要检测局部像素灰度变化明显的地方。思想:如果一个像素与邻域的像素差别较大(过亮或者过暗),那么他更可能是角点。

检测过程:

  1. 在图像中选择像素p,假设亮度为Ip。
  2. 设置一个阈值T(不如,Ip的20%)。
  3. 以像素p为中心,选择半径为3的圆上的16个像素点
  4. 假如选取的圆上有连续的N个点的亮度大于Ip+T或者小于Ip-T,那么像素p可以被认为是特征点(N通常取12,即FAST-12)
  5. 循环上述4步,对每一个像素执行相同操作
  • 在FAST-12算法中,为了更加高效,可以添加一项预测试操作,从而快速地排除绝大多数不是角点的像素:对于每个像素,直接检查邻域圆上1 5 9 13个像素的亮度,只有这4个点中有至少3个符合条件,当前像素才可能是一个角点
  • 原始的FAST角点容易出现角点扎堆的现象,所以在第一遍检测完成后,还需要用非极大值抑制,在一定区域内仅仅保留响应极大值的角点,避免角点集中的问题。

在这里插入图片描述

FAST角点的优缺点:仅仅比较像素间亮度的差异,所以速度很快;但是重复性不强,分布不均匀;且FAST角点不具备方向信息;由于固定取半径为3的圆,所以存在尺度问题。

针对于FAST角点不具有方向性和尺度的缺点,ORB添加了尺度和旋转的描述。

尺度不变性:由构建图像金字塔,并在金字塔的每一层上检测角点来实现

  • 金字塔底座是原始图像,每往上一层,就对图像进行一个固定倍率的缩放,这样就有了不同分辨率的图像。较小的图像可以看作是远处看过来的场景。在特征匹配算法中,我们可以匹配不同层上的图像,从而实现了尺度不变性。
  • eg:如果相机后退,那么我们应该能够在上一个图像金字塔的上层和下一个图像金字塔的下层中找到匹配

旋转:由灰度质心法实现

  • 计算特征点附近的图像灰度质心。

  • 质心是指以图像灰度值作为权重的中心

  • 步骤:

    在这里插入图片描述

    在这里插入图片描述

将这种改进后的FAST称为Oriented FAST。

BRIEF描述子

在提取了Oriented FAST角点后,我们对其中的每一个点计算其描述子。ORB使用改进后的BRIEF特征描述。

BRIEF是一种二进制描述子,其描述向量由0/1组成,这里的0和1编码了关键点附近两个随机像素(比如p和q)的大小关系:如果p比q大,则取1;反之就取0。如果我们随机去了128组这样的p和q,最后就能得到128维由0和1组成的向量。

BRIEF使用了随机选点的比较,速度非常快,而且由于使用二进制进行表达,存储起来也十分方便,适用于实时的图像匹配。

原始的BRIEF描述子不具有旋转不变性,因此在图像发生旋转以后容易丢失。而ORB在FAST特征点提取阶段计算了关键点的方向,所以可以利用方向信息,计算旋转之后的steer BRIEF特征使ORB的描述子具有较好的旋转不变性。

1.3 特征匹配

特征匹配解决了SLAM问题中的数据关联问题。

由于图像特征的局部特性,误匹配的情况广泛存在,而且长期以来一直没有得到有效解决,目前已经成为视觉SLAM中制约性能提成的一大瓶颈。部分原因是因为场景中经常存在大量的重复纹理,使得特征描述非常相似。在这种情况下,仅利用局部特征解决误匹配是非常困难的。

最简单的匹配方法是暴力匹配

对于二进制描述子,可以使用汉明距离作为度量----两个二进制串之间的汉明距离,指的是不同位数的个数

FLANN(快速近似最近邻)算法适用于匹配点数量极多的情况。

非极大值抑制

NMS(non maximum suppression),中文名非极大值抑制,在很多计算机视觉任务中都有广泛应用,如:边缘检测、目标检测等。

NMS顾名思义就是抑制不是极大值的元素,可以理解为局部最大搜索。这个局部代表的是一个邻域,邻域有两个参数可变,一是邻域的维数,二是邻域的大小。这里讨论用于目标检测中提取分数最高的窗口。例如在行人检测中,滑动窗口经提取特征,经分类器分类识别后,每个窗口都会得到一个分数。但是滑动窗口会导致很多窗口与其他窗口存在包含或者大部分交叉的情况。这时就需要用到NMS来选取那些邻域里分数最高(是行人的概率最大),并且抑制那些分数低的窗口

NMS在计算机视觉领域有着非常重要的应用,如视频目标跟踪、数据挖掘、3D重建、目标识别以及纹理分析等。

以下图为例,由于滑动窗口,同一个人可能有好几个框(每一个框都带有一个分类器得分)

在这里插入图片描述

而我们的目标是一个人只保留一个最优的框:

于是我们就要用到非极大值抑制,来抑制那些冗余的框: 抑制的过程是一个迭代-遍历-消除的过程。

**(1)**将所有框的得分排序,选中最高分及其对应的框:

在这里插入图片描述

**(2)**遍历其余的框,如果和当前最高分框的重叠面积(IOU)大于一定阈值,我们就将框删除。

在这里插入图片描述

**(3)**从未处理的框中继续选一个得分最高的,重复上述过程。

在这里插入图片描述

NSM – 非极大值抑制 https://blog.csdn.net/shuzfan/article/details/52711706

https://www.cnblogs.com/makefile/p/nms.html

FLANN算法

opencv中可以直接调用FLANN库。

FLANN是快速最近邻搜索包(Fast_Library_for_Approximate_Nearest_Neighbors)的简称。它是一个对大数据集和高维特征进行最近邻搜索的算法的集合,而且这些算法都已经被优化过了。在面对大数据集是它的效果要好于BFMatcher。

https://blog.csdn.net/jinxueliu31/article/details/37768995

https://blog.csdn.net/Bluenapa/article/details/88371512

http://www.whudj.cn/?p=920

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/116697
推荐阅读
相关标签
  

闽ICP备14008679号