前言
由于关键帧之间的联系比较复杂,因此如果要删除一个关键帧,就会产生“牵一发而动全身”的效应,需要清除和该关键帧相连关键帧的联系,需要清除该关键帧观测到的地图点的联系,需要为该关键帧的子关键帧重新寻找合适的父关键帧。前面两个操作相对容易,第三个操作会比较复杂,它涉及整个关键帧的父子关系,处理不好会造成整个关键帧维护的生成树的断裂或混乱。
下面主要介绍一下为待删除关键帧的子关键帧重新寻找合适的父关键帧。
其中涉及的一些变量:
变量 | 含义 |
mpParent | 当前待删除关键帧的父关键帧 |
sParentCandidates | 候选父关键帧,初始化时只有一个元素—mpParent |
mspChildrens | 当前待删除关键帧的子关键帧,可能有多个 |
pKF | 当前待删除关键帧的某个子关键帧, mspChildrens 中的一个元素 |
vpConnected | 和pKF 共视的关键帧 |
pC | vpConnected和sParentCandidates中相同的元素中和pKF共视程度最高的子关键帧 |
pP | vpConnected 和sParentCandidates 中相同的元素中和pKF 共视程度最高的vpConnected 中的元素 |
1.函数声明
void KeyFrame::SetBadFlag()
这个SetBadFlag函数主要完成了以下操作:
1.处理删除条件:如果关键帧不能删除(如正在进行回环检测或SIM3计算),则将其标记为待删除,但不实际删除。
2.删除与其他关键帧的连接:遍历当前关键帧与其他关键帧的连接,并删除它们之间的关系。
3.删除与地图点的连接:删除当前关键帧与所有地图点之间的关系。
4.更新父子关系:遍历当前关键帧的子关键帧,重新为它们分配父关键帧,确保没有孤立的子关键帧。
5.删除当前关键帧:标记当前关键帧为无效(mbBad = true),并从地图和关键帧数据库中删除它。
2.函数定义
为待删除关键帧的子关键帧重新寻找合适的父关键帧的主要流程:
1. 将mpParent 放入sParentCandidates 中,在第一阶段sParentCandidates中只有这一个元素,它其实是mspChildrens 元素的爷爷。
2.开始遍历mspChildrens 中的每个元素pKF, 它是当前待删除关键帧的子关键帧。对于每个pKF, 遍历和它共视的关键帧vpConnected,判断其中有没有sParentCandidates 中的元素mpParent, 如果有,则记录mpParent 和pKF 的权重(共视地图点数目)。找出其中权重值最高时对应的pKF作为pC , 此时的mpParent作为pP 。左侧的子关键帧和mpParent 的权重为60, 大于右侧子关键帧和mpParent 的权重50, 所以左侧的子关键帧升级为pC, mpParent 记为pP。更新记录标志bContinue 为true。
3.如果bContinue 为true, 则说明发生了第2 步中的更新, 此时将pC 的父关键帧更新为pP, 并把pC 从子关键帧列表mspChildrens 中删除,并放到sParentCandidates 中。也就是说, 当前待删除关键帧不能作为pC 的父关键帧了, 由于pC和pP共视程度高于其他所有子关键帧, 因此pC从子关键帧升级为爷关键帧。第一阶段结束。