orb-slam2 Inlitializer.h 头文件的学习
a.预备知识,主要读取了作者的论文。
作者在论文中提到,这个头文件定义的东西全是用于单目的,双目和RGBD不需要初始化。地图初始化的目的就是得到两帧的相对运动,R T, 然后根据 R T 和这两帧匹配好的关键点,三角化出初始的三 维地图。论文里面提到了一共有5步。
1.在当前帧与参考帧之间提取ORB特征,就行匹配。
2.开启两个同步线程,同时计算H矩阵和F矩阵,H=homography 用于特征点都是在同平面的情况,F=fundomental 用于特征点不在同一平面的情况。代码中使用8个点就能恢复出想要的H 和F,具体怎么处理 呢?代码中随机的选8个点,(当前帧和参考帧的8个匹配好的点对,一共8对),一共挑选选200次,选出得分最高的H,F。这里得分如何计算?作者论文中详细的提到了计算方法。
具体解释:M可取F H。我们以M=F为例,首先看到的是,SF是一个累加。因为选了8个点,所以累加8次。ρF的计算已经给出来了。这里最重要的是d2 的计算, 就是指把第一帧里面的每一个选中的点,重投影到第二帧后得到的重投影误差,平方,和第二帧里面选中的投影到第一帧里面形成的重投影误差,平方。然后Γ 取的是5.99.这里就计算得到了得分。
3.模型选择选H还是F。
RH>0.45选择H,否则选择F
4,恢复出运动和地图的三维结构
意思就是从H,或者F中分解出R 和 T ,然后根据R T 三角化匹配好的关键点,得到这些关键点的3D坐标。这就是所谓的初始化地图。
5 .BA
b.各个函数解释。
公共函数:
1. Initializer(const Frame &ReferenceFrame, float sigma = 1.0, int iterations = 200);
构造函数:给出参考帧,和迭代系数。
2. bool Initialize(const Frame &CurrentFrame, const vector<int> &vMatches12, cv::Mat &R21, cv::Mat &t21, vector<cv::Point3f> &vP3D, vector<bool> &vbTriangulated);
[email protected] Frame &CurrentFrame:输入的参考帧。 [email protected] vector<int> &vMatches12:输入的匹配。
c. @cv::Mat &R21 输出的motion d @cv::Mat &t21 输出的motion
[email protected]<cv::Point3f> &vP3D:输出的三维地图也就是初始化的地图。f:@vector<bool> &vbTriangulated) 输出。
具体实现: 首先是找到参考帧和当前帧的配对关系。把这个一一对应关系放入mvMatches12.push_back(make_pair(i,vMatches12[i])).中。然后构造一个200行8列的二维数组vector<vector<size_t> > mvSets 。最后就是开启两个个线程计算H,F,得到想要的结果。
私有函数:
3 .void FindHomography(vector<bool> &vbMatchesInliers, float &score, cv::Mat &H21); 4 .void FindFundamental(vector<bool> &vbInliers, float &score, cv::Mat &F21);
首先:3个参数全部都是输出。
具体实现:两个函数实现都是一样的。首先就是将第一帧的关键点和第二帧的关键点全部normalize. 循环200次,分别计算出每次循环的得分,找出最高的得分。以及最高得分对应的H(F),vbMatchesInliers(vbInliers)。
5.cv::Mat ComputeH21(const vector<cv::Point2f> &vP1, const vector<cv::Point2f> &vP2); 6.cv::Mat ComputeF21(const vector<cv::Point2f> &vP1, const vector<cv::Point2f> &vP2);
首先:两个参数都是输入,输出的就是H,F矩阵。
具体的实现:其实就是根据8个点对,由对极约束或者是,H的约束,来获得H F。具体可看高博的十四讲。
7. float CheckHomography(const cv::Mat &H21, const cv::Mat &H12, vector<bool> &vbMatchesInliers, float sigma); 8.float CheckFundamental(const cv::Mat &F21, vector<bool> &vbMatchesInliers, float sigma);
首先:输入 H(F),sigama.输出的是在这种H(F)下的得分,和vbMatchesInliers。
具体实现:见a.预备知识里面的2.
9.bool ReconstructF(vector<bool> &vbMatchesInliers, cv::Mat &F21, cv::Mat &K, cv::Mat &R21, cv::Mat &t21, vector<cv::Point3f> &vP3D, vector<bool> &vbTriangulated, float minParallax, int minTriangulated); 10.bool ReconstructH(vector<bool> &vbMatchesInliers, cv::Mat &H21, cv::Mat &K, cv::Mat &R21, cv::Mat &t21, vector<cv::Point3f> &vP3D, vector<bool> &vbTriangulated, float minParallax, int minTriangulated);
首先:[email protected] vector<bool> &vbMatchesInliers:输入参数。[email protected] cv::Mat &F21:输入参数,计算得到的F矩阵 [email protected] cv::Mat &K:输入参数,代表相机参数。4 @cv::Mat &R21:输出的R。 5 @cv::Mat &t21:输出的t 6 @ vector<cv::Point3f> &vP3D:输出的3D点。7 @ vector<bool> &vbTriangulated:输出。表示点是不是三角化了。[email protected] minParallax:输入,最小的视差。[email protected] int minTriangulated 输入。
具体解释:我们知道的从E,H中直接分解出R T 是不唯一的,会分解出4种(8种)情况,这两个函数就是根据一些手段,和先验知识恢复得到正确唯一的R T。
11.void Triangulate(const cv::KeyPoint &kp1, const cv::KeyPoint &kp2, const cv::Mat &P1, const cv::Mat &P2, cv::Mat &x3D);
首先:1 @const cv::KeyPoint &kp1:输入的第一帧关键点。 2 @const cv::KeyPoint &kp2:输入与第一帧匹配的第二帧关键点 。
3 @ const cv::Mat &P1 :第一帧的相机参数K*T。 4 @: const cv::Mat &P2 .第二帧的相机参数K*T。
5 @:cv::Mat &x3D 输出的三角化的点。
12.void Normalize(const vector<cv::KeyPoint> &vKeys, vector<cv::Point2f> &vNormalizedPoints, cv::Mat &T);
首先:1 @ const vector<cv::KeyPoint> &vKeys. 输入的关键点。2 @:vector<cv::Point2f> &vNormalizedPoints:输出的点。3 @:cv::Mat &T:输出的T,在 void FindHomography(vector<bool> &vbMatchesInliers, float &score, cv::Mat &H21);void FindFundamental(vector<bool> &vbInliers, float &score, cv::Mat &F21);函数里面用到了。
具体实现:首次先算出输入所有关键点的平均值meanX,meanY(关键点x,y的平均值)
其次每个关键点的x,y与这个平均值meanX,meanY做差。将所有的差绝对值加起来求平均值
得到meanDevX,meanDevY. 讲上面那些差除以meanDevXm,meanDevY,就得到输出的vNormalizedPoints
13.int CheckRT(const cv::Mat &R, const cv::Mat &t, const vector<cv::KeyPoint> &vKeys1, const vector<cv::KeyPoint> &vKeys2, const vector<Match> &vMatches12, vector<bool> &vbInliers, const cv::Mat &K, vector<cv::Point3f> &vP3D, float th2, vector<bool> &vbGood, float ¶llax);
首先:1 @ const cv::Mat &R, 输入1->2 2 @ const cv::Mat &t :输入 1->2 3 @ const vector<cv::KeyPoint> &vKeys1 输入
4 @ const vector<cv::KeyPoint> &vKeys2:输入 5 @ const vector<Match> &vMatches12 :输入 6 @ vector<bool> &vbInliers :输入
7 @ const cv::Mat &K :相机参数输入 8 @ vector<cv::Point3f> &vP3D 输出 9 @ float th2 :输入(重投影误差的平方误差)
10 @ vector<bool> &vbGood :输出 11 @ float ¶llax :输出视差。
具体实现:首先将第一个相机放在原点。构造两个3X4的矩阵。其等于相机参数K 乘以这帧的T。然后得到第二个相机中心在第一个相机坐标系(可以看成世界坐标系)下的坐标。然后进入一个循环,循环每次都要计算视差。啥叫视差?首先计算匹配好的点在世界坐标系下(第一个相机坐标系下)的3D坐标,从第一个相机中心出发连接这个3D点得到一条射线,从第二个相机的中心出发连接这个3 D点得到一条射线,这两条射线之间的夹角就是视差(parallax),检测视差,分别检测两帧下的深度,和重投影误差。返回3D点。因为没对返回视差。
14.void Initializer::DecomposeE(const cv::Mat &E, cv::Mat &R1, cv::Mat &R2, cv::Mat &t)
首先: 1 @ const cv::Mat &E :输入 2 @ cv::Mat &R1 :输出 3 @ cv::Mat &R2 :输出 4 @ cv::Mat &t :输出
具体解释:就是分解E