目录
2.4 遍历当前提取器节点的vkeys中存储的特征点并分配给各个子节点
1.函数作用
ORB-SLAM2 ---- ORBextractor::DistributeOctTree函数_Courage2022的博客-CSDN博客
将一个传进来的节点分裂成四个并恢复其特征点在节点中的分布。
2.函数解析
2.1 函数代码
/** * @brief 将提取器节点分成4个子节点,同时也完成图像区域的划分、特征点归属的划分,以及相关标志位的置位 * * @param[in & out] n1 提取器节点1:左上 * @param[in & out] n2 提取器节点1:右上 * @param[in & out] n3 提取器节点1:左下 * @param[in & out] n4 提取器节点1:右下 */ void ExtractorNode::DivideNode(ExtractorNode &n1, ExtractorNode &n2, ExtractorNode &n3, ExtractorNode &n4) { //得到当前提取器节点所在图像区域的一半长宽,当然结果需要取整,step5 lit调用的这个函数当然就是当前节点的参数 const int halfX = ceil(static_cast<float>(UR.x-UL.x)/2); const int halfY = ceil(static_cast<float>(BR.y-UL.y)/2); //Define boundaries of childs //下面的操作大同小异,将一个图像区域再细分成为四个小图像区块 //n1 存储左上区域的边界 n1.UL = UL; n1.UR = cv::Point2i(UL.x+halfX,UL.y); n1.BL = cv::Point2i(UL.x,UL.y+halfY); n1.BR = cv::Point2i(UL.x+halfX,UL.y+halfY); //用来存储在该节点对应的图像网格中提取出来的特征点的vector n1.vKeys.reserve(vKeys.size()); //n2 存储右上区域的边界 n2.UL = n1.UR; n2.UR = UR; n2.BL = n1.BR; n2.BR = cv::Point2i(UR.x,UL.y+halfY); n2.vKeys.reserve(vKeys.size()); //n3 存储左下区域的边界 n3.UL = n1.BL; n3.UR = n1.BR; n3.BL = BL; n3.BR = cv::Point2i(n1.BR.x,BL.y); n3.vKeys.reserve(vKeys.size()); //n4 存储右下区域的边界 n4.UL = n3.UR; n4.UR = n2.BR; n4.BL = n3.BR; n4.BR = BR; n4.vKeys.reserve(vKeys.size()); //Associate points to childs //遍历当前提取器节点的vkeys中存储的特征点 for(size_t i=0;i<vKeys.size();i++) { //获取这个特征点对象 const cv::KeyPoint &kp = vKeys[i]; //判断这个特征点在当前特征点提取器节点图像的哪个区域,更严格地说是属于那个子图像区块 //然后就将这个特征点追加到那个特征点提取器节点的vkeys中 //NOTICE BUG REVIEW 这里也是直接进行比较的,但是特征点的坐标是在“半径扩充图像”坐标系下的,而节点区域的坐标则是在“边缘扩充图像”坐标系下的 if(kp.pt.x<n1.UR.x) { if(kp.pt.y<n1.BR.y) n1.vKeys.push_back(kp); else n3.vKeys.push_back(kp); } else if(kp.pt.y<n1.BR.y) n2.vKeys.push_back(kp); else n4.vKeys.push_back(kp); }//遍历当前提取器节点的vkeys中存储的特征点 //判断每个子特征点提取器节点所在的图像中特征点的数目(就是分配给子节点的特征点数目),然后做标记 //这里判断是否数目等于1的目的是确定这个节点还能不能再向下进行分裂 if(n1.vKeys.size()==1) n1.bNoMore = true; if(n2.vKeys.size()==1) n2.bNoMore = true; if(n3.vKeys.size()==1) n3.bNoMore = true; if(n4.vKeys.size()==1) n4.bNoMore = true; }
我们的目的是将一个传进来的节点分裂成四个并恢复其特征点在节点中的分布。
2.2 UR.x-UL.x这些变量怎么来的
我们在ORBextractor::DistributeOctTree函数中,lit迭代器调用这个函数。
即是对lit所指向的节点,而lit所指向节点的位置信息我们是在这里声明的。
2.3 分裂节点代码解释
const int halfX = ceil(static_cast<float>(UR.x-UL.x)/2); const int halfY = ceil(static_cast<float>(BR.y-UL.y)/2); //Define boundaries of childs //下面的操作大同小异,将一个图像区域再细分成为四个小图像区块 //n1 存储左上区域的边界 n1.UL = UL; n1.UR = cv::Point2i(UL.x+halfX,UL.y); n1.BL = cv::Point2i(UL.x,UL.y+halfY); n1.BR = cv::Point2i(UL.x+halfX,UL.y+halfY); //用来存储在该节点对应的图像网格中提取出来的特征点的vector n1.vKeys.reserve(vKeys.size()); //n2 存储右上区域的边界 n2.UL = n1.UR; n2.UR = UR; n2.BL = n1.BR; n2.BR = cv::Point2i(UR.x,UL.y+halfY); n2.vKeys.reserve(vKeys.size()); //n3 存储左下区域的边界 n3.UL = n1.BL; n3.UR = n1.BR; n3.BL = BL; n3.BR = cv::Point2i(n1.BR.x,BL.y); n3.vKeys.reserve(vKeys.size()); //n4 存储右下区域的边界 n4.UL = n3.UR; n4.UR = n2.BR; n4.BL = n3.BR; n4.BR = BR; n4.vKeys.reserve(vKeys.size());
2.4 遍历当前提取器节点的vkeys中存储的特征点并分配给各个子节点
for(size_t i=0;i<vKeys.size();i++) { //获取这个特征点对象 const cv::KeyPoint &kp = vKeys[i]; //判断这个特征点在当前特征点提取器节点图像的哪个区域,更严格地说是属于那个子图像区块 //然后就将这个特征点追加到那个特征点提取器节点的vkeys中 //NOTICE BUG REVIEW 这里也是直接进行比较的,但是特征点的坐标是在“半径扩充图像”坐标系下的,而节点区域的坐标则是在“边缘扩充图像”坐标系下的 if(kp.pt.x<n1.UR.x) { if(kp.pt.y<n1.BR.y) n1.vKeys.push_back(kp); else n3.vKeys.push_back(kp); } else if(kp.pt.y<n1.BR.y) n2.vKeys.push_back(kp); else n4.vKeys.push_back(kp); }//遍历当前提取器节点的vkeys中存储的特征点
2.5 判断节点是否可分裂
if(n1.vKeys.size()==1) n1.bNoMore = true; if(n2.vKeys.size()==1) n2.bNoMore = true; if(n3.vKeys.size()==1) n3.bNoMore = true; if(n4.vKeys.size()==1) n4.bNoMore = true;
如果节点中的特征点数目=1,置可分裂标志bNoMore 为-1。