ORB-SLAM2源码学习:ORBextractor.cc:ExtractorNode::DivideNode节点一分为四④
前言
该函数将当前节点所代表的图像区域划分为四个子区域,同时将该区域内的特征点分配到相应的子区域节点中。
1.函数的声明
/*将提取器节点分成4个子节点,同时也完成图像区域的划分、特征点归属的划分,以及相关标志位的置位n1 提取器节点1:左上n2 提取器节点1:右上n3 提取器节点1:左下n4 提取器节点1:右下*/
void ExtractorNode::DivideNode(ExtractorNode &n1, //提取器节点1:左上ExtractorNode &n2, //提取器节点1:右上ExtractorNode &n3, //提取器节点1:左下ExtractorNode &n4) //提取器节点1:右下
{....
}
2.函数定义
1.划分子节点的区域
//得到当前提取器节点所在图像区域的一半长宽,向上取整。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);//用来存储在该节点对应的图像网格中提取出来的特征点的vectorn1.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.遍历节点中的特征点数,划分到对应节点区域中。
注:这里特征点坐标和节点边界坐标对比不在同一个坐标系下
//Associate points to childs//遍历当前提取器节点的vkeys中存储的特征点for(size_t i=0;i<vKeys.size();i++){//获取这个特征点对象const cv::KeyPoint &kp = vKeys[i];//判断这个特征点在当前特征点提取器节点图像的哪个区域//然后就将这个特征点追加到那个特征点提取器节点的vkeys中//这里也是直接进行比较的,但是特征点的坐标是在“半径扩充图像”坐标系下的,而节点区域的坐标则是在“边缘扩充图像”坐标系下的if(kp.pt.x<n1.UR.x){if(kp.pt.y<n1.BR.y)n1.vKeys.push_back(kp);elsen3.vKeys.push_back(kp);}else if(kp.pt.y<n1.BR.y)n2.vKeys.push_back(kp);elsen4.vKeys.push_back(kp);}//遍历当前提取器节点的vkeys中存储的特征点
3.判断节点区域是否能在分裂
//判断每个子特征点提取器节点所在的图像中特征点的数目(就是分配给子节点的特征点数目),然后做标记//这里判断是否数目等于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;
3.完整代码
/*将提取器节点分成4个子节点,同时也完成图像区域的划分、特征点归属的划分,以及相关标志位的置位n1 提取器节点1:左上n2 提取器节点1:右上n3 提取器节点1:左下n4 提取器节点1:右下*/
void ExtractorNode::DivideNode(ExtractorNode &n1, //提取器节点1:左上ExtractorNode &n2, //提取器节点1:右上ExtractorNode &n3, //提取器节点1:左下ExtractorNode &n4) //提取器节点1:右下
{//得到当前提取器节点所在图像区域的一半长宽,向上取整。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);//用来存储在该节点对应的图像网格中提取出来的特征点的vectorn1.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中//这里也是直接进行比较的,但是特征点的坐标是在“半径扩充图像”坐标系下的,而节点区域的坐标则是在“边缘扩充图像”坐标系下的if(kp.pt.x<n1.UR.x){if(kp.pt.y<n1.BR.y)n1.vKeys.push_back(kp);elsen3.vKeys.push_back(kp);}else if(kp.pt.y<n1.BR.y)n2.vKeys.push_back(kp);elsen4.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;
}
结束语
以上就是我学习到的内容,如果对您有帮助请多多支持我,如果哪里有问题欢迎大家在评论区积极讨论,我看到会及时回复。