文章目录

  • 一、特征点法
    • 1.1 特征点
    • 1.2 ORB 特征
    • 1.3 特征匹配
    • 实践
  • 二、 计算相机运动
  • 三、2D-2D:对极几何
    • 3.1 对极约束
    • 3.2 本质矩阵
    • 3.3 单应矩阵
    • 讨论
  • 四、实践
  • 五、三角测量(Triangulation)
    • 讨论
  • 六、三角测量实践
  • 七、3D-2D:PnP
    • 7.1 直接线性变换

一、特征点法

特征点法特征:稳定,对光照、动态物体不敏感。

1.1 特征点

特征点:有代表性的点。视觉SLAM称这些点为路标(图像特征feature)。
特征点性质:不同的图像可以找到相同的特征(可重复性),不同特征有不同的表达(可区别性),特征点数量不多(高效率),特征仅与一小片图像区域相关(本地性)。
特征点主要包括 关键点(key-point, 该特征点在图像中的位置) + 描述子(descriptor,该特征点长什么样子)
比如:① SIFT(尺度不变特征变换):计算量大但考虑充分;
② FAST:快且没描述子;
③ ORB:Oriented FAST and Rotated BRIEF,速度还可以且特征子具有旋转、尺度不变性。

1.2 ORB 特征

提取ORB特征分两步骤:Fast角点提取+BRIEF描述子。
FAST关键点:
主要思想:比较一个像素IpI_pIp​和邻域像素的亮度。在半径为3的16个像素点比较亮度,连续12个点的亮度大于Ip+TI_p+TIp​+T或小于Ip−TI_p-TIp​−T则认定为角点。FAST-12为了更快,直接检测1,5,9,13个像素的亮度,只有4个像素中有3个同时大于Ip+TI_p+TIp​+T或小于Ip−TI_p-TIp​−T,当前像素才可能是角点。此外为了预防FAST角点出现扎堆的情况,用非极大值抑制,可以在一定区域内保留相应极大值的角点。
缺点:不具有方向性和尺度。
ORB添加尺度不变性:构建图像金字塔;
ORB添加旋转的描述:添加质心。
BRIEF描述子

1.3 特征匹配

最简单的特征匹配方法是暴力匹配,计算每个特征点描述子的距离,排序,找个最近的作为匹配点。这个方法计算量太大,**快速近似最近邻(FLANN)**更适合匹配点极多的情况。

实践

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/feature2d/feature2d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <chrone>using namespace std;
using namespace sv;int main(int argc, char **argv){if(argc != 3){cout<<""usage: feature_extraction img1 img2 "<< endl;return 1;}//参数为3,因为要输入 "./orb_cv 1.png 2.png " 这是三个参数,argc=3,argv储存这三个参数//读图像Mat img_1 = imread(argv[1], CV_LOAD_IMAGE_COLOR);Mat img_2 = imread(argv[2], CV_LOAD_IMAGE_COLOR);assert(img_1.data != nullptr && img_2.data != nullptr);//判断读进去的图片//cv::assert()计算括号内的表达式,若为FALSE (或0), 程序将报告错误并终止执行。若不为0,则继续执行后面的语句。//初始化vector<KeyPoint> keypoints_1, keypoints_2;   //关键点/角点/**opencv中keypoint类的默认构造函数为:CV_WRAP KeyPoint() : pt(0,0), size(0), angle(-1), response(0), octave(0), class_id(-1) {}pt(x,y):关键点的点坐标; // size():该关键点邻域直径大小; // angle:角度,表示关键点的方向,值为[0,360),负值表示不使用。response:响应强度,选择响应最强的关键点;   octacv:从哪一层金字塔得到的此关键点。class_id:当要对图片进行分类时,用class_id对每个关键点进行区分,默认为-1。**/Mat descriptors_1, descriptors_2;      //描述子//创建ORB对象,参数为默认值Ptr<FeatureDetector> detector = ORB::create();Ptr<DescriptorExtractor> descriptor = ORB::create();Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");/**“Ptr<FeatureDetector> detector = ”等价于 “FeatureDetector * detector =”Ptr是OpenCV中使用的智能指针模板类,可以轻松管理各种类型的指针。特征检测器FeatureDetetor是虚类,通过定义FeatureDetector的对象可以使用多种特征检测及匹配方法,通过create()函数调用。描述子提取器DescriptorExtractor是提取关键点的描述向量类抽象基类。描述子匹配器DescriptorMatcher用于特征匹配,"Brute-force-Hamming"表示使用汉明距离进行匹配。**///第一步,检测Oriented Fast角点位置chrono::steady_clock::time_point t1 = chrono::steady_clock::now();detector->detect(img_1, keypoints_1);     //对参数1图像进行特征的提取,并存放入参数2的数组中detector->detect(img_2, keypoints_2);//第二步,根据角点计算BREIF描述子descriptor->compute(img_1, keypoints_1, descriptors_1);   //computer()计算关键点的描述子向量(注意思考参数设置的合理性)descriptor->compute(img_2, keypoints_2, descriptors_2);chrono::steady_clock::time_point t2 = chrono::steady_clock::now();chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);cout << "extract ORB cost = " << time_used.count() << " seconds. " << endl;Mat outimg1;drawKeypoints(img_1, keypoints_1, outimg1, Scalar::all(-1), DrawMatchesFlags::DEFAULT);imshow("ORB features", outimg1);imwrite("feaure1.png", outimg1);//第三步, 对两幅图像中的描述子进行匹配,使用hamming距离vector<DMatch> matches;    //DMatch是匹配关键点描述子 类, matches用于存放匹配项t1 = chrono::steady_clock::now();matcher->match(descriptors_1, descriptors_2, matches); //对参数1 2的描述子进行匹配,并将匹配项存放于matches中t2 = chrono::steady_clock::now();time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);cout << "match the ORB cost: " << time_used.count() << "seconds. " << endl;//第四步,匹配点对筛选//计算最小距离和最大距离auto min_max = minmax_element(matches.begin(), matches.end(),[](const DMatch &m1, const DMatch &m2){ return m1.distance < m2.distance; });// auto 可以在声明变量的时候根据变量初始值的类型自动为此变量选择匹配的类型// minmax_element()返回指向范围内最小和最大元素的一对迭代器。参数1 2为起止迭代器范围// 参数3是二进制函数,该函数接受范围内的两个元素作为参数,并返回可转换为bool的值。// 返回的值指示作为第一个参数传递的元素是否小于第二个。该函数不得修改其任何参数。double min_dist = min_max.first->distance;  // min_max存储了一堆迭代器,first指向最小元素double max_dist = min_max.second->distance; // second指向最大元素printf("-- Max dist : %f \n", max_dist);printf("-- Min dist : %f \n", min_dist);//当描述子之间的距离大于两倍最小距离时,就认为匹配有误。但有时最小距离会非常小,所以要设置一个经验值30作为下限。vector<DMatch> good_matches;  //存放良好的匹配项for(int i = 0; i < descriptors_1.rows; ++i){if(matches[i].distance <= max(2 * min_dist, 30.0)){good_matches.push_back(matches[i]);}}//第五步,绘制匹配结果Mat img_match;         //存放所有匹配点Mat img_goodmatch;     //存放好的匹配点// drawMatches用于绘制两幅图像的匹配关键点。// 参数1是第一个源图像,参数2是其关键点数组;参数3是第二张原图像,参数4是其关键点数组// 参数5是两张图像的匹配关键点数组,参数6用于存放函数的绘制结果drawMatches(img_1, keypoints_1, img_2, keypoints_2, matches, img_match);drawMatches(img_1, keypoints_1, img_2, keypoints_2, good_matches, img_goodmatch);imshow("all matches", img_match);imshow("good matches", img_goodmatch);imwrite("match1.png", img_match);imwrite("goodmatch1.png", img_goodmatch);waitKey(0);return 0;
}

二、 计算相机运动

单目:根据两组2D点,用对极几何。
双目、RGB-D:根据两组3D点,用ICP。
一组3D、一组2D:用PnP。

三、2D-2D:对极几何

3.1 对极约束

基础矩阵(Fundamental Matrix)F
本质矩阵(Essential Matrix)E
p 像素点 , x 归一化平面的点

E 和 F 只相差相机内参K,相机位姿估计问题:

  1. 根据配对点的像素位置求出E 或 F。
  2. 根据E 或 F 求出R 和 t。

3.2 本质矩阵

E是一个3*3的矩阵,内有9个未知数。

  1. 对极约束是等式为0的约束,E乘以任何非零常数后对极约束仍然满足。E 在不同尺度下等价。
  2. 本质矩阵的内在性质:E的奇异值必定是[σ,σ,0]T[\sigma, \sigma, 0]^T[σ,σ,0]T的形式。
  3. 平移和旋转各有3个自由度,即E有6个自由度,由于尺度等价性,E实际上有5个自由度。即最少用5对点来求解E。
    八点法来估计E。线性代数的方法,E展开写成向量的形式,8个方程构成一个线性方程,利用线性性质求解。
    用E恢复R和t。存在两个可能的t和R。

    四个解如图,将任意点带入,检测该点在两个相机下的深度,就可以确定哪个正确。

    另,八点法求出的E可能不满足内在性质,因此会把E调整下,设奇异值矩阵为diag(σ1,σ2,σ3)diag(\sigma1, \sigma2, \sigma3)diag(σ1,σ2,σ3),得到E=Udiag(σ1+σ22,σ1+σ22,0)VTE = Udiag(\frac{\sigma1+\sigma2} 2,\frac{\sigma1+\sigma2} 2,0)V^TE=Udiag(2σ1+σ2​,2σ1+σ2​,0)VT, 更简单的做法是取diag(1,1,0)。
    另,F具有7个自由度。

3.3 单应矩阵

描述两个平面之间的映射关系。通常描述共处于共同平面上的一些点在两张图象之间的变换关系。

讨论

E和F之间相差了相机内参矩阵,E、F、H都能分解运动,不过H需要假设特征点位于平面上。E本身具有尺度等价性,分解得到的t和R也具有尺度等价性,通常让t进行归一化,让他的长度为1。
尺度不确定性
对t长度归一化,即固定了尺度。也被称为单目SLAM的初始化。初始化的两张图像必须有一定程度的平移,而后的轨迹和地图都以此的平移为单位。另一种初始化的方法是所有特征点平均深度为1。相比较t=1的做法,特征点归一化可以控制场景规模大小。
初始化的纯旋转问题
纯旋转,t=0,E=0。R也求不出来。总之初始化的话,不能只有旋转,必须加一定程度的平移。
多于8对点的情况
给定的匹配点多于8则构成一个超定方程,可以最小化一个二次型来求。不过当可能存在误匹配的情况,倾向于用随机采样一致性(Random Sample Concensus, RANSAC),适用于带错误数据的情况。

四、实践

五、三角测量(Triangulation)

单目SLAM仅通过单张图像无法得到像素的深度信息,因此需要用三角测量的方法估计地图点的深度。通过不同位置对同一路标点进行观察,从观察的位置推断路标点的距离。

x1和x2是两个特征点归一化坐标,s1和s2是两个特征点深度。运动后:s1x1=s2Rx2+ts_1x_1 = s_2Rx_2+ts1​x1​=s2​Rx2​+t
若先算s2, 右侧只有s2,可以直接求s2。其实更常见是用最小二乘法求解。

讨论

三角测量是由平移得到的,平移越大,三角测量越准确。为了提高三角化的精度,一种是提高特征点的提取精度,另一种是使平移量增大。

六、三角测量实践

七、3D-2D:PnP

前面提到2D-2D的对极几何需要8点或8以上点对,需要初始化、纯旋转和尺度的问题。但是如果其中一张图像中的3D位置已知,那么最少需要3对点即可。再双目或RGB-D的视觉里程计中直接使用PnP估计运动。
求解方法有:直接线性变换(DLT)、EPnP(Efficient PnP)、光束法平差(Bundle Adjustment,BA)等。

7.1 直接线性变换

**问题描述:**一组3D点的位置P=(X,Y,Z,1)TP = (X,Y,Z,1)^TP=(X,Y,Z,1)T,另一个坐标系中的平面位置(投影位置)x1=(u1,v1,1)Tx_1 = (u_1,v_1,1)^Tx1​=(u1​,v1​,1)T,求解两个相机的相对运动问题[R∣t][R|t][R∣t]。

主要步骤:
把定义TTT行向量为t1,t2,t3t_1, t_2, t_3t1​,t2​,t3​,

t1TP−t3TPu1=0t_1^TP-t_3^TPu_1=0t1T​P−t3T​Pu1​=0 和 t2TP−t3TPu1=0t_2^TP-t_3^TPu_1=0t2T​P−t3T​Pu1​=0

<视觉SLAM十四讲> ch7 视觉里程计1相关推荐

  1. 视觉SLAM十四讲——ch7

    视觉SLAM十四讲--ch7 ch7视觉里程计 本章目标: 1.理解图像特征点的意义,并掌握在单副图像中提取出特征点及多副图像中匹配特征点的方法 2.理解对极几何的原理,利用对极几何的约束,恢复出图像 ...

  2. 视觉slam十四讲 pdf_视觉SLAM十四讲|第12讲 回环检测

    1. 什么是回环检测 前面有说过累积误差的问题,前一时刻的误差会积累到后面,导致画不成圈圈,如图12-1所示,而画圈圈(全局一致性)很重要,所以需要有一个步骤来纠正当前的计算偏差. 回环检测通过判断相 ...

  3. 【视觉SLAM十四讲】视觉里程计—特征点法

    本文为视觉 SLAM 学习笔记,讲解视觉里程计中的特征点法. 本讲内容概要 图像特征的意义,在单幅及多幅图像中提取特征点. 对极几何的原理,利用对极几何的约束恢复图像间相机的三维运动 PnP 问题,利 ...

  4. 视觉SLAM十四讲学习笔记-第七讲-视觉里程计-三角测量和实践

     专栏汇总 视觉SLAM十四讲学习笔记-第一讲_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习笔记-第二讲-初识SLAM_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习笔记-第 ...

  5. 视觉SLAM十四讲学习笔记-第七讲-视觉里程计-特征点法和特征提取和匹配实践

    专栏系列文章如下: 视觉SLAM十四讲学习笔记-第一讲_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习笔记-第二讲-初识SLAM_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习 ...

  6. 视觉SLAM十四讲学习笔记-第七讲-视觉里程计-PnP和实践

      专栏汇总 视觉SLAM十四讲学习笔记-第一讲_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习笔记-第二讲-初识SLAM_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习笔记- ...

  7. 视觉SLAM十四讲学习笔记-第七讲-视觉里程计-对极几何和对极约束、本质矩阵、基础矩阵

    专栏系列文章如下:  专栏汇总 视觉SLAM十四讲学习笔记-第一讲_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习笔记-第二讲-初识SLAM_goldqiu的博客-CSDN博客 视觉SLA ...

  8. 高博-《视觉SLAM十四讲》

    0 讲座 (1)SLAM定义 对比雷达传感器和视觉传感器的优缺点(主要介绍视觉SLAM) 单目:不知道尺度信息 双目:知道尺度信息,但测量范围根据预定的基线相关 RGBD:知道深度信息,但是深度信息对 ...

  9. 《视觉SLAM十四讲 第二版》笔记及课后习题(第七讲)

    读书笔记:视觉里程计1 之前的内容,介绍了运动方程和观测方程的具体形式,并讲解了以非线性优化为主的求解方法.从本讲开始,我们结束了基础知识的铺垫,开始步入正题:按照第二讲的内容,分别介绍视觉里程计.优 ...

  10. 视觉SLAM总结——视觉SLAM十四讲笔记整理

    视觉SLAM总结--视觉SLAM十四讲笔记整理 说明 基础知识点 1. 特征提取.特征匹配 (1)Harris (2)SIFT (3)SUFT (4)ORB (5)特征匹配 2. 2D-2D:对极约束 ...

最新文章

  1. VK Cup 2012 Qualification Round 2 C. String Manipulation 1.0 字符串模拟
  2. C#中JSON序列化和反序列化
  3. Spring Boot - 自动配置实现原理
  4. java到android_Java到Android?
  5. Connection is not open httpClient 的问题解决方案
  6. 两个凸多边形的公共面积
  7. Postman自动化接口测试实战详解
  8. oracle替换指定字符串字符_实例:替换方框内字符串内容
  9. 教案设计计算机,计算机应用基础教案设计
  10. 弦截法求根c语言,弦截法求方程的根(c++)
  11. Wasserstein距离
  12. linux端口占满,Linux查看端口占用情况,并强制释放占用的端口
  13. cv2.error: OpenCV(4.5.1) C:\Users\appveyor\AppData\Local\Temp\1\pip-req-buil
  14. 三步教你安装微软系统,使用uiso制作U盘启动盘
  15. ftrace跟踪内核_ftrace追踪内核函数调用
  16. k8s 出现各种问题解决方案
  17. 探地雷达技术在道路检测中的应用
  18. 《深入理解计算机系统》 练习题3.49详解
  19. 华为2016开发者大赛:赢的不仅仅是百万元奖金
  20. H5中需要掌握的 ANIMATION 动画效果

热门文章

  1. allegro学习之总结pcb设计流程
  2. 你知道怎样做好一个老板吗?先来看看不适合做老板的三种人
  3. 关于Redis配置文件不生效的问题
  4. 银行对帐java程序_使用用友软件如何进行银行对账
  5. 京东主图如何优化,一键自动替换长图
  6. 【速记】zipf distribution 实现算法
  7. 如何写好一个软件项目的技术标书?
  8. 简单工厂模式 - Unity
  9. Windows下安装DM8(超详细版)
  10. 【2022.1.3】手脱压缩壳练习(含练习exe)