前言:在特征匹配、跟踪、建图、闭环等过程中存在大量的地图点、关键帧、图结构相关操作,这里先对这些结构及常用的相应函数进行了解。
1. 地图点MapPoint
1.1 MapPoint类的定义
class MapPoint
{
public:
/**
* @brief 给定坐标与keyframe构造MapPoint
* @details 被调用:
* 双目: StereoInitialization(),CreateNewKeyFrame(),LocalMapping::CreateNewMapPoints()
* 单目: CreateInitialMapMonocular(), LocalMapping::CreateNewMapPoints()
* @param[in] Pos MapPoint的坐标(wrt世界坐标系)
* @param[in] pRefKF KeyFrame
* @param[in] pMap Map
*/
MapPoint(const cv::Mat &Pos, KeyFrame* pRefKF, Map* pMap);
/**
* @brief 给定坐标与frame构造MapPoint
* @detials 被双目:UpdateLastFrame()调用
* @param[in] Pos MapPoint的坐标(世界坐标系)
* @param[in] pMap Map
* @param[in] pFrame Frame
* @param[in] idxF MapPoint在Frame中的索引,即对应的特征点的编号
*/
MapPoint(const cv::Mat &Pos, Map* pMap, Frame* pFrame, const int &idxF);
// 获取当前地图点的被观测次数
int Observations();
/**
* @brief 添加观测
*
* 记录哪些KeyFrame的哪个特征点能观测到该MapPoint \n
* 并增加观测的相机数目nObs,单目+1,双目或者grbd+2
* 这个函数是建立关键帧共视关系的核心函数,能共同观测到某些MapPoints的关键帧是共视关键帧
* @param[in] pKF KeyFrame,观测到当前地图点的关键帧
* @param[in] idx MapPoint在KeyFrame中的索引
*/
void AddObservation(KeyFrame* pKF,size_t idx);
/**
* @brief 取消某个关键帧对当前地图点的观测
* @detials 如果某个关键帧要被删除,那么会发生这个操作
* @param[in] pKF
*/
void EraseObservation(KeyFrame* pKF);
/**
* @brief 计算具有代表的描述子
* @detials 由于一个MapPoint会被许多相机观测到,因此在插入关键帧后,需要判断是否更新当前点的最适合
* 的描述子. 先获得当前点的所有描述子,然后计算描述子之间的两两距离,最好的描述子与其他描述子应该具有
* 最小的距离中值
*/
void ComputeDistinctiveDescriptors();
/**
* @brief 更新平均观测方向以及观测距离范围
* 由于一个MapPoint会被许多相机观测到,因此在插入关键帧后,需要更新相应变量
*/
void UpdateNormalAndDepth();
public:
long unsigned int mnId; // 该MapPoint的全局ID
static long unsigned int nNextId;
const long int mnFirstKFid; // 创建该MapPoint的关键帧ID
const long int mnFirstFrame; // 创建该MapPoint的帧ID
int nObs; // MapPoint被观测到的相机数目,单目+1,双目或RGB-D则+2
protected:
cv::Mat mWorldPos; // MapPoint在世界坐标系下的坐标
// 观测到该MapPoint的KF和该MapPoint对应特征点在KF中的索引
std::map<KeyFrame*,size_t> mObservations;
// 该MapPoint平均观测方向, 用于判断点是否在可视范围内
cv::Mat mNormalVector;
// 每个3D点可对应多个特征点,mDescriptor表示最有代表性的特征点的描述子
cv::Mat mDescriptor;
// 参考关键帧, 通常情况下MapPoint的参考关键帧就是创建该MapPoint的那个关键帧
KeyFrame* mpRefKF;
};
1.2 地图点与关键帧间的相互观测
1.2.1 AddObservation
/**
* @brief 给地图点添加观测
* @调用方式: pMP->AddObservation(pKF,i); 主要更新变量mObservations和nObs
* 表示关键帧pKF的第i个特征点能够观测到地图点pMP, 并增加观测的相机数目nObs, 单目+1, 双目或者rgbd+2
* 这个函数是建立关键帧共视关系的核心函数,能共同观测到某些地图点的关键帧是共视关键帧
* @param pKF KeyFrame
* @param idx MapPoint在KeyFrame中的索引
*/
void MapPoint::AddObservation(KeyFrame* pKF, size_t idx)
{
unique_lock<mutex> lock(mMutexFeatures);
// mObservations:观测到该MapPoint的关键帧KF和该MapPoint在KF中对应特征点的索引
// 若mObservations中已经存在关键帧pKF,表示关键帧pKF可以观测到当前MapPoint,那么就直接返回
if(mObservations.count(pKF))
return;
// 如果没有添加过观测,表示关键帧pKF目前还没有观测到当前MapPoint
// 在将当前MapPoint添加到关键帧pKF的观测上时,需要将它关联到与之对应的特征点上
mObservations[pKF]=idx;
if(pKF->mvuRight[idx]>=0)
nObs+=2; // 双目或者rgbd
else
nObs++; // 单目
}
1.2.2 AddMapPoint
/** KeyFrame.cc
* @brief 将当前地图点pMP添加到所调用帧(pKF)对应地图点集合mvpMapPoints的idx处
* @调用方式: pKF->AddMapPoint(pMP,i);
* @param pKF 待添加的地图点
* @param idx 添加到的索引位置
*/
void KeyFrame::AddMapPoint(MapPoint *pMP, const size_t &idx)
{
unique_lock<mutex> lock(mMutexFeatures);
mvpMapPoints[idx]=pMP;
}
/* Map.cc
* @brief 将当前地图点pMP插入到所调用的地图中
* @调用方式: mpMap->AddMapPoint(pMP);
* @param pMP 待插入的地图点
*/
//向地图中插入地图点
void