首先,ORBSLAM2里的优化都是基于图优化的,使用的第三方库为g2o,这里先介绍一下g2o简要使用流程,然后再来看看ORBSLAM2里的几个优化函数。
g2o是一个图优化求解库,它将优化问题表现为图的形式:包含顶点和边。
在slam问题里,BA中参与优化的参数有位姿和地图点坐标,在g2o中,我们将这些需要进行优化的变量设置为顶点,一般一张图像的位姿为一个顶点,这张图像上所能观察到的每一个地图点坐标都为顶点。其次顶点间用边来建立联系(位姿和地图点之间的联系),也就是用边来表示误差项(在vslam里的重投影误差)。这样就建立好了一个图优化问题,接下来选择对应的优化方法求解器进行求解。
1、全局BA
// pMap中所有的MapPoints和关键帧做bundle adjustment优化
// 这个全局BA优化在本程序中有两个地方使用:
// a.单目初始化:CreateInitialMapMonocular函数
// b.闭环优化:RunGlobalBundleAdjustment函数
/**
* @brief bundle adjustment Optimization
*
* 3D-2D 最小化重投影误差 e = (u,v) - project(Tcw*Pw) \n
*
* 1. Vertex: g2o::VertexSE3Expmap(),即当前帧的Tcw
* g2o::VertexSBAPointXYZ(),MapPoint的mWorldPos
* 2. Edge:
* - g2o::EdgeSE3ProjectXYZ(),BaseBinaryEdge
* + Vertex:待优化当前帧的Tcw
* + Vertex:待优化MapPoint的mWorldPos
* + measurement:MapPoint在当前帧中的二维位置(u,v)
* + InfoMatrix: invSigma2(与特征点所在的尺度有关)
*
* @param vpKFs 关键帧
* vpMP MapPoints
* nIterations 迭代次数(20次)
* pbStopFlag 是否强制暂停
* nLoopKF 关键帧的个数
* bRobust 是否使用核函数
*/
void Optimizer::BundleAdjustment(const vector &vpKFs, const vector &vpMP,
int nIterations, bool* pbStopFlag, const unsigned long nLoopKF, const bool bRobust)
2、单帧位姿优化
// 该优化函数主要用于Tracking线程中:运动跟踪、参考帧跟踪、地图跟踪、重定位
/**
* @brief Pose Only Optimization
*
* 3D-2D 最小化重投影误差 e = (u,v) - project(Tcw*Pw) \n
* 只优化Frame的Tcw,不优化MapPoints的坐标
*
* 1. Vertex: g2o::VertexSE3Expmap(),即当前帧的Tcw
* 2. Edge:
* - g2o::EdgeSE3ProjectXYZOnlyPose(),BaseUnaryEdge
* + Vertex:待优化当前帧的Tcw
* + measurement:MapPoint在当前帧中的二维位置(u,v)
* + InfoMatrix: invSigma2(与特征点所在的尺度有关)
* - g2o::EdgeStereoSE3ProjectXYZOnlyPose(),BaseUnaryEdge
* + Vertex:待优化当前帧的Tcw
* + measurement:MapPoint在当前帧中的二维位置(ul,v,ur)
* + InfoMatrix: invSigma2(与特征点所在的尺度有关)
*
* @param pFrame Frame
* @return inliers数量
*/
int Optimizer::PoseOptimization(Frame *pFrame)
3、局部地图BA优化
/**
* @brief Local Bundle Adjustment
*
* 1. Vertex:
* - g2o::VertexSE3Expmap(),LocalKeyFrames,即当前关键帧的位姿、与当前关键帧相连的关键帧的位姿
* - g2o::VertexSE3Expmap(),FixedCameras,即能观测到LocalMapPoints的关键帧(并且不属于LocalKeyFrames)的位姿,在优化中这些关键帧的位姿不变
* - g2o::VertexSBAPointXYZ(),LocalMapPoints,即LocalKeyFrames能观测到的所有MapPoints的位置
* 2. Edge:
* - g2o::EdgeSE3ProjectXYZ(),BaseBinaryEdge
* + Vertex:关键帧的Tcw,MapPoint的Pw
* + measurement:MapPoint在关键帧中的二维位置(u,v)
* + InfoMatrix: invSigma2(与特征点所在的尺度有关)
* - g2o::EdgeStereoSE3ProjectXYZ(),BaseBinaryEdge
* + Vertex:关键帧的Tcw,MapPoint的Pw
* + measurement:MapPoint在关键帧中的二维位置(ul,v,ur)
* + InfoMatrix: invSigma2(与特征点所在的尺度有关)
*
* @param pKF KeyFrame
* @param pbStopFlag 是否停止优化的标志
* @param pMap 在优化后,更新状态时需要用到Map的互斥量mMutexMapUpdate
*/
void Optimizer::LocalBundleAdjustment(KeyFrame *pKF, bool* pbStopFlag, Map* pMap)
4、本质图位姿优化
/**
* @brief 闭环检测后,EssentialGraph优化
*
* 1. Vertex:
* - g2o::VertexSim3Expmap,Essential graph中关键帧的位姿
* 2. Edge:
* - g2o::EdgeSim3(),BaseBinaryEdge
* + Vertex:关键帧的Tcw,MapPoint的Pw
* + measurement:经过CorrectLoop函数步骤2,Sim3传播校正后的位姿
* + InfoMatrix: 单位矩阵
*
* @param pMap 全局地图
* @param pLoopKF 闭环匹配上的关键帧
* @param pCurKF 当前关键帧
* @param NonCorrectedSim3 未经过Sim3传播调整过的关键帧位姿
* @param CorrectedSim3 经过Sim3传播调整过的关键帧位姿
* @param LoopConnections 因闭环时MapPoints调整而新生成的边
*/
void Optimizer::OptimizeEssentialGraph(Map* pMap, KeyFrame* pLoopKF, KeyFrame* pCurKF,
const LoopClosing::KeyFrameAndPose &NonCorrectedSim3,
const LoopClosing::KeyFrameAndPose &CorrectedSim3,
const map > &LoopConnections, const bool &bFixScale)
5、两帧间Sim3优化
/**
* @brief 形成闭环时进行Sim3优化
*
* 1. Vertex:
* - g2o::VertexSim3Expmap(),两个关键帧的位姿
* - g2o::VertexSBAPointXYZ(),两个关键帧共有的MapPoints
* 2. Edge:
* - g2o::EdgeSim3ProjectXYZ(),BaseBinaryEdge
* + Vertex:关键帧的Sim3,MapPoint的Pw
* + measurement:MapPoint在关键帧中的二维位置(u,v)
* + InfoMatrix: invSigma2(与特征点所在的尺度有关)
* - g2o::EdgeInverseSim3ProjectXYZ(),BaseBinaryEdge
* + Vertex:关键帧的Sim3,MapPoint的Pw
* + measurement:MapPoint在关键帧中的二维位置(u,v)
* + InfoMatrix: invSigma2(与特征点所在的尺度有关)
*
* @param pKF1 KeyFrame
* @param pKF2 KeyFrame
* @param vpMatches1 两个关键帧的匹配关系
* @param g2oS12 两个关键帧间的Sim3变换
* @param th2 核函数阈值
* @param bFixScale 是否优化尺度,弹目进行尺度优化,双目不进行尺度优化
*/
int Optimizer::OptimizeSim3(KeyFrame *pKF1, KeyFrame *pKF2, vector &vpMatches1, g2o::Sim3 &g2oS12, const float th2, const bool bFixScale)