SLAM——视觉里程计(一)feature
从现在开始下面两篇文章来介绍SLAM中的视觉里程计(Visual Odometry)。这个是我们正式进入SLAM工程的第一步,而之前介绍的更多的是一些基础理论。视觉里程计完成的事情是视觉里程计VO的目标是根据拍摄的图像估计相机的位姿。目前主要有两个方法,我们这一篇介绍的是特征点法。
首先,我们之前提到了路标。SLAM中是根据路标的位置变化来估计自身的运动的。路标是三维空间中固定不变的点,应该有这么几个特征:
- 数量充足,以实现良好的定位
- 具有较好的区分性,以实现数据关联
而图像的特征点可以比较好的满足上面的特点,可以通过特征点来作为SLAM中的路标。
特征点
特征点是图像当中比较具有代表性的部分。
我们想象一下,我们识别一个物体的时候,即使旋转了,或者光照不同,尺度变化,我们还是能认出。这一点上,人眼真的是太强了。如图:
即使糊成这样,我们依然能喊出来,诶呀真香。
而一种好的特征点,希望能做到上面几点,当然那是非常困难的。它应该有下面几个特征:
- 可重复性,也就是,换个视角来看它应该还是原来的样子。
- 可区分性,可区分意味着不同的特征点看起来不一样,这样我们才能辨别不同场景。
- 高效,这个作为特征点并不是必要的,但是为了实时SLAM的运行,我们必须把它纳入,而且它是非常重要的。
特征点一般由两部分组成:关键点和描述子(descriptor)。其中关键点包含了这个点的位置,大小,方向评分等信息,但是只靠关键点不足以区分各个特征点,而描述子描述了特征点周围的像素的一些信息。
一般来说特征点的选的部分都是角点或者边缘部分,因为它们有比较大的区分性,而区块点的区分性就比较差了,这个是符合我们的直觉的。
有一些比较有名的特征点,FAST,ORB,SIFT,SURF等等。一般来说,我们在SLAM中要兼顾特征点在各个条件下的性能(比如光照不同,旋转等情况下依然能得到基本一样的特征点,主要是靠描述子来实现),以及提取速度,这使得在SLAM中我们用的最多的是ORB特征点,我们可以在OpenCV feature2d模块中找到。下面对各个特征点做一个简单的介绍,同时会相对详细地介绍一下ORB特征点。
Fast特征点
首先介绍一下Fast特征点。Fast特征点是非常简单的一种特征点,它的提取速度也非常快。它的思路非常简单:若某像素与其周围邻域内足够多的像素点相差较大,则该像素可能是角点。
如上图,以一个像素p为中心,fast检测周围半径为3的圆上的16个像素点,在它的周围,如果有连续12个像素点与中心像素点的差都超过阈值,则它判断它是一个角点,这个方法是Fast12,其他的还有fast9等等,都只是个数不同而已。
为了提高效率,还有一个步骤,比如要超过12个像素点,那么首先检测p1,p5,p9,p13这几个像素点,如果有3个超过阈值,它才有可能是一个角点,当作候选点。相当于是一个预处理,这样可以大大提高提取的速度。
当然,通过这样的方法得到的特征点可能会在某个局部区域非常密集,因此我们需要进行极大值抑制。具体做法为:计算特征点出的FAST得分值(即score值,也即s值,定义为(16个点与中心差值的绝对值总和),判断以特征点p为中心的一个邻域(如3x3或5x5)内,若有多个特征点,则判断每个特征点的s值,若p是邻域所有特征点中响应值最大的,则保留;否则,抑制。若邻域内只有一个特征点(角点),则保留。
Fast特征点是非常直白的,它甚至没有描述子。而有意思的是它的提出(2006年)却没有SIFT等比较复杂的特征点那么早。
ORB特征点
Fast特征点虽然快,但是它并没有描述子,这样距离我们的应用还是有差距,因为它是没有办法匹配(match)的,仅仅靠关键点我们无法互相区分各个特征点。
ORB特征点是Fast特征点和BREIF特征描述子的改进,是Oriented Fast,它增加了描述子,具有局部旋转不变性。因为BREIF是二进制描述子,它的提取速度依然是非常迅速的。
除此之外,Fast特征点的数量往往很大而且不确定,我们一般希望对图像提取固定数量的特征点。假如我们需要提取N个角点,则ORB中可以对各个角点进行Harris响应值,然后选前N个具有最大响应值的角点。
下面稍微介绍一下ORB中对于Fast方向性和尺度方面的弱点的改进。
对于尺度方面,Fast由于计算的只是像素亮度的差异,有时候远处像角点的地方,离近了就不是角点了。尺度不变性由构建图像金字塔,并在金字塔的每一层上检测角点来实现。金字塔是对图像进行不同层次的降采样,以获得不同的分辨率。
对于方向性,是由灰度质心法实现的。我们知道一般来说,一个有质量的物体有个质心,那么图片呢?在图片中,我们把每个像素的灰度值当作“质量”来确定质心。
灰度质心法操作如下:
- 在小的图像块B中,图像块的矩为:上式中,$x,y$分别为坐标值,而$I(x,y)$为$(x,y)$的灰度值。
- 通过矩可以找到图像的质心:
- 连接图像0点$O$和质心$C$,得到一个方向向量$OC$,则特征点的方向可以定义为:
通过这个方法,Fast角点就有了尺度和旋转的描述,从而提升了它描述不同图像时候的鲁棒性。这种改进成为Oriented FAST。
此外,ORB特征点的另一个改进是对BREIF描述子的改进。
BREIF描述子是一种二进制描述子,其描述向量由许多个0和1组成,这里0和1编码了关键点附近两个像素($p,q$)的大小关系:如果$p>q$则为1,否则为0。如果我们取了127对这样的点,就得到了128维的二进制向量。p,q的选取一般会按照某个概率分布随机选取,速度很快。
原始的BREIF不具有旋转不变性。但是由于Oriented Fast有了方向,可以利用方向信息,计算旋转之后的“steer BRIEF”特征,使得ORB的描述子具有比较好的旋转不变性。
特征匹配
特征匹配可以说是SLAM中至关重要的一步,因为SLAM中的路标,在不同帧之间的位置,就是通过特征匹配完成的。如果特征匹配的好,可以大大减少后续姿态估计,优化等操作的负担。然而,由于图像中重复纹理等等原因,误匹配的情况一直得不到非常好的解决,仅仅利用局部特征解决误匹配是非常困难的。
不过对于一般的图像,我们还是可以通过一些办法消除一些错误的匹配。到后面我们可以知道,其实我们只需要较少的几个特征点就能得到比较好的效果,因此尽管很多消除误匹配的算法会使得很多正确的匹配也被剔除了,但是依然是够用的。
匹配的办法有多种,最简单的是暴力匹配,就是与另一幅图的特征点一个个对比,来得到相似度最高的那个特征点。一般这个相似度差了多少,我们用距离来衡量,距离越远相似度越低。距离的定义可以有多种,如果是浮点数,我们可以求欧式距离,对于ORB的二进制描述子,我们用Hamming距离来衡量,而汉明距离实际上就是二进制码中不同位数的个数。
当特征点数量很大的时候,暴力匹配的速度变得很慢。这时候,可以使用FLANN(快速近似最近邻算法库)来实现匹配。这些算法已经非常成熟,可以去翻看相关论文来了解它具体的内容。
实践:特征提取和特征匹配
下面有一个利用OpenCV提取ORB特征值并且进行匹配的程序,来总结这么一段关于ORB的内容。
1 |
#include<opencv2/core/core.hpp> |
对应的CMakeLists.txt:
1 |
cmake_minimum_required(VERSION 3.2) |
这个代码中剔除错误匹配的用的剔除掉大于2倍最小距离的特征点,这更多是一个经验上的做法。此外还有RANSAC(随机采样一致)等算法,以及二者结合等等,可能得到更好的剔除效果。我曾经写过一个SIFT提取和匹配的算法,在剔除中用到了ransac算法,是一个VS工程:feature_match_sift。有兴趣的可以看一下,其实我也忘得差不多了。
最后的结果:
- 特征提取
- 特征匹配
- 过滤后的特征匹配
SLAM——视觉里程计(一)feature的更多相关文章
- SLAM入门之视觉里程计(1):特征点的匹配
SLAM 主要分为两个部分:前端和后端,前端也就是视觉里程计(VO),它根据相邻图像的信息粗略的估计出相机的运动,给后端提供较好的初始值.VO的实现方法可以根据是否需要提取特征分为两类:基于特征点的方 ...
- SLAM入门之视觉里程计(2):相机模型(内参数,外参数)
相机成像的过程实际是将真实的三维空间中的三维点映射到成像平面(二维空间)过程,可以简单的使用小孔成像模型来描述该过程,以了解成像过程中三维空间到二位图像空间的变换过程. 本文包含两部分内容,首先介绍小 ...
- SLAM入门之视觉里程计(5):单应矩阵
在之前的博文OpenCV,计算两幅图像的单应矩阵,介绍调用OpenCV中的函数,通过4对对应的点的坐标计算两个图像之间单应矩阵\(H\),然后调用射影变换函数,将一幅图像变换到另一幅图像的视角中.当时 ...
- 视觉slam十四讲个人理解(ch7视觉里程计1)
参考博文::https://blog.csdn.net/david_han008/article/details/53560736 https://blog.csdn.net/n66040927/ar ...
- 第三篇 视觉里程计(VO)的初始化过程以及openvslam中的相关实现详解
视觉里程计(Visual Odometry, VO),通过使用相机提供的连续帧图像信息(以及局部地图,先不考虑)来估计相邻帧的相机运动,将这些相对运行转换为以第一帧为参考的位姿信息,就得到了相机载体( ...
- 关于视觉里程计以及VI融合的相关研究(长期更新)
1. svo 源码:https://github.com/uzh-rpg/rpg_svo 国内对齐文章源码的研究: (1)冯斌: 对其代码重写 https://github.com/yueying/O ...
- (3)视觉里程计 Visual Odometry
首先分析include头文件下的slamBase.h文件 # pragma once // 各种头文件 // C++标准库 #include <fstream> #include < ...
- SLAM入门之视觉里程计(2):两视图对极约束 基础矩阵
在上篇相机模型中介绍了图像的成像过程,场景中的三维点通过"小孔"映射到二维的图像平面,可以使用下面公式描述: \[ x = MX \]其中,\(c\)是图像中的像点,\(M\)是一 ...
- SLAM入门之视觉里程计(6):相机标定 张正友经典标定法详解
想要从二维图像中获取到场景的三维信息,相机的内参数是必须的,在SLAM中,相机通常是提前标定好的.张正友于1998年在论文:"A Flexible New Technique fro Cam ...
随机推荐
- VUE注册全局组件和局部组件
全局组件 第一步:在components文件夹下建立一个子文件Users.vue <template> <div class="users"> {{msg} ...
- SQL基础教程(第2版)第2章 查询基础:练习题
SELECT product_name, regist_date FROM Product WHERE regist_date > '2009-04-28'; ① ~ ③中的 SQL 语句都无法 ...
- Go语言-并发模式-goroutine池实例(work)
介绍 使用无缓冲的通道来创建一个 goroutine 池,这些 goroutine 执行并控制一组工作,让其并发执行.在这种情况下,使用无缓冲的通道要比随意指定一个缓冲区大小的有缓冲的通道好,因为这个 ...
- python刷LeetCode:2.两数相加
难度等级:中等 题目描述: 给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字. 如果,我们将这两个数相加起来,则会返 ...
- 运营商何时会取消40G或100G流量封顶呢?短期内有望实现吗?
一直以来,运营商的不限流量套餐就饱受人们的诟病.因为说是不限流量,但其实运营商故意设置了"封顶"!最常见的封顶限制,就是流量超过40G网速会降速到1Mbps--实际下载速度为128 ...
- PHP使用redis防止大并发下二次写入
php调用redis进去读写操作,大并发下会出现:读取key1,没有内容则写入内容,但是大并发下会出现同时多个php进程写入的情况,这个时候需要加一个锁,即获取锁的php进程有权限写. $lock_k ...
- EL表达式和JSTL(一)
一. 初始JavaBean 在软件开发时,有些数据时经常要用到的,为了方便进行移植,Sun公司提出了一种JavaBean技术,使用JavaBean对这些数据进行封装,做到一次编写,到处开发. Java ...
- 17.3.12--smtplib模块发送邮件__抄送,安装与下载
1-----在日常编程中,经常会用到处理email,发送,接收,抄送,下载邮件内容等操作,这时候就需要用Python的smtplib模块 smtplib与Email服务器(server)相互通信来传送 ...
- 01 语言基础+高级:1-3 常用API第一部分_day07【Scanner类、Random类、ArrayList类】
day07[Scanner类.Random类.ArrayList类] Scanner类Random类ArrayList类 教学目标 能够明确API的使用步骤能够使用Scanner类获得键盘录入数据能够 ...
- UML-SSD-定义
1.NextGen例子 SSD来自用例文本 2.定义 1).针对的是用例的一个特定场景 2).参与者与系统之间交互事件(跨系统边界,不画系统内部流转,即黑盒) 比如:收银员 访问系统A.系统B,此时只 ...