ORB-SLAM2中四叉树管理特征点

当从图像金字塔中的每一层图像上提取特征点之后,都要先用四叉树技术对这些特征点进行管理

//该类中定义了四叉树创建的函数以及树中结点的属性
//bool bNoMore: 根据该结点中被分配的特征点的数目来决定是否继续对其进行分割
//DivisionNode():实现如何对一个结点进行分割
//vKeys:用来存储被分配到该结点区域内的所有特征点
//UL, UR, BL, BR:四个点定义了一个结点的区域
//lit:list的迭代器,遍历所有生成的节点
class ExtractorNode
{
public:
    ///用初始化列表来初始化本类内的成员变量
    ExtractorNode():bNoMore(false){}

    void DivideNode(ExtractorNode &n1, ExtractorNode &n2, ExtractorNode &n3, ExtractorNode &n4);

    std::vector<cv::KeyPoint> vKeys;
    cv::Point2i UL, UR, BL, BR;
    std::list<ExtractorNode>::iterator lit;
    bool bNoMore;
};

下面的函数实现利用四叉树来管理从金字塔中的每一层图像上提取的特征点

//vToDistributeKeys变量中存储的是从金字塔中某一层图像上提取的特征点
//minX, maxX, minY, maxY:是该层图像去除了边界的区域
//N: mnFeaturesPerLevel[i]表示该层图像上应该提取的特征点的个数
//level: 该图像处在金字塔上的层数
vector<cv::KeyPoint> ORBextractor::DistributeOctTree(const vector<cv::KeyPoint>& vToDistributeKeys, const int &minX,
                                       const int &maxX, const int &minY, const int &maxY, const int &N, const int &level)
{
    //常用的相机kinect v1的分辨率是:640*480 kinect v2的分辨率是:1920*1080
    //为了尽量使得每一个结点的区域形状接近正方形所以图像的长宽比决定了四叉树根节点的数目
    //如果使用kinect v1那么只有一个根结点,如果使用kinect v2那么就会有两个根结点
    const int nIni = round(static_cast<float>(maxX-minX)/(maxY-minY));
    
    //hX变量可以理解为一个根节点所占的宽度  
    const float hX = static_cast<float>(maxX-minX)/nIni;
    //lNodes中存储生成的树结点
    list<ExtractorNode> lNodes;
    //vpIniNodes变量中存储的是结点的地址
    vector<ExtractorNode*> vpIniNodes;
    //vpIniNodes的大小先设置成根结点的个数
    vpIniNodes.resize(nIni);
    
    for(int i=0; i<nIni; i++)
    {
        ExtractorNode ni;
        //四叉树是每次根据特定条件将一个结点分成四等分,四个区域左上(UL),右上(UR), 
        //左下(BL),右下(BR)
        //左上角位置坐标
        ni.UL = cv::Point2i(hX*static_cast<float>(i),0);
        //右上角位置坐标
        ni.UR = cv::Point2i(hX*static_cast<float>(i+1),0);
        ///左下角的位置坐标
        ni.BL = cv::Point2i(ni.UL.x,maxY-minY);
        ///右下角的位置坐标
        ni.BR = cv::Point2i(ni.UR.x,maxY-minY);

        //vKeys的大小为在上面的这个根节点范围内总共提取的特征点的个数
        ni.vKeys.reserve(vToDistributeKeys.size());
        //将创建的根节点插入到list lNodes中
        lNodes.push_back(ni);
        ////将lNodes变量中的最后存储的那个结点的地址存储到vector变量vpIniNodes中
        //暂时还不知道这个变量做何用
        //看都了吧vpIniNodes总是把最后插入到lNodes中的结点的地址拿走,然后要为
        //该结点的vKeys成员变量内部添加属于该结点的特征点。
        vpIniNodes[i] = &lNodes.back();
    }

    //Associate points to childs
    //要一直记得vToDistributeKeys变量中存储的是该层图像中提取的特征点
    //遍历在该层图像上提取的所有特征点
    for(size_t i=0;i<vToDistributeKeys.size();i++)
    {
        const cv::KeyPoint &kp = vToDistributeKeys[i];
        //将所有提取的特征点根据坐标位置将其分配到对应的根节点中去
       //如果使用kinect b=v1那么所有的kp.pt.x都小于hX,所以所有的特征点都被分配到
        //vpIniNodes的第0个元素中存储的结点指针所指向的空间中去了
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值