Advertisement

SLAM——ORB-SLAM3代码分析(六)MapDrawer

阅读量:

2021SC@SDUSC

MapDrawer分析

今天来到带 Map 标签的最后一部分——对 MapDrawer 进行分析。在基于 Map 和 MapPoint 的基础上,采用 MapDrawer 技术来绘制地图点的方式。

首先该函数具有重要意义,并负责执行一系列关键操作。它会完成以下步骤:第一步会提取全部的地图数据;随后会提取与之相关的参考地图数据;接着会将vpRefMPs转换为集合类型(这一转换有助于快速统计集合中的元素数量);最后会分别展示全局的地图数据及其局部区域的数据

复制代码
    void MapDrawer::DrawMapPoints()
    {
    const vector<MapPoint*> &vpMPs = mpAtlas->GetAllMapPoints();
    const vector<MapPoint*> &vpRefMPs = mpAtlas->GetReferenceMapPoints();
    
    set<MapPoint*> spRefMPs(vpRefMPs.begin(), vpRefMPs.end());
    
    if(vpMPs.empty())
        return;
    
    glPointSize(mPointSize);
    glBegin(GL_POINTS);
    glColor3f(0.0,0.0,0.0);
    
    for(size_t i=0, iend=vpMPs.size(); i<iend;i++)
    {
        if(vpMPs[i]->isBad() || spRefMPs.count(vpMPs[i]))
            continue;
        cv::Mat pos = vpMPs[i]->GetWorldPos();
        glVertex3f(pos.at<float>(0),pos.at<float>(1),pos.at<float>(2));
    }
    glEnd();
    
    glPointSize(mPointSize);
    glBegin(GL_POINTS);
    glColor3f(1.0,0.0,0.0);
    
    for(set<MapPoint*>::iterator sit=spRefMPs.begin(), send=spRefMPs.end(); sit!=send; sit++)
    {
        if((*sit)->isBad())
            continue;
        cv::Mat pos = (*sit)->GetWorldPos();
        glVertex3f(pos.at<float>(0),pos.at<float>(1),pos.at<float>(2));
    
    }
    
    glEnd();
    }

随后介绍另一个关键函数DrawKeyFrames 。考虑到该函数拥有大量代码量较为庞大 ,为了提高可读性 以便更好地理解其运行逻辑 我会在代码中直接添加注释来进行分析 而不再将其单独列出作为外部说明

复制代码
    void MapDrawer::DrawKeyFrames(const bool bDrawKF, const bool bDrawGraph, const bool bDrawInertialGraph)
    {
    //历史关键帧图标
    const float &w = mKeyFrameSize;
    const float h = w*0.75;
    const float z = w*0.6;
    // step 1:取出所有的关键帧
    const vector<KeyFrame*> vpKFs = mpAtlas->GetAllKeyFrames();
    
    // step 2:显示所有关键帧图标
    //通过显示界面选择是否显示历史关键帧图标
    if(bDrawKF)
    {
        for(size_t i=0; i<vpKFs.size(); i++)
        {
            KeyFrame* pKF = vpKFs[i];
            cv::Mat Twc = pKF->GetPoseInverse().t();
            unsigned int index_color = pKF->mnOriginMapId;
    
            glPushMatrix();
            //因为OpenGL中的矩阵为列优先存储,因此实际为Tcw,即相机在世界坐标下的位姿
            glMultMatrixf(Twc.ptr<GLfloat>(0));
    
            if(!pKF->GetParent()) // It is the first KF in the map
            {
                //设置绘制图形时线的宽度
                glLineWidth(mKeyFrameLineWidth*5);
                glColor3f(1.0f,0.0f,0.0f);
                //用线将下面的顶点两两相连
                glBegin(GL_LINES);
            }
            else
            {
                glLineWidth(mKeyFrameLineWidth);
                glColor3f(mfFrameColors[index_color][0],mfFrameColors[index_color][1],mfFrameColors[index_color][2]);
                glBegin(GL_LINES);
            }
    
            glVertex3f(0,0,0);
            glVertex3f(w,h,z);
            glVertex3f(0,0,0);
            glVertex3f(w,-h,z);
            glVertex3f(0,0,0);
            glVertex3f(-w,-h,z);
            glVertex3f(0,0,0);
            glVertex3f(-w,h,z);
    
            glVertex3f(w,h,z);
            glVertex3f(w,-h,z);
    
            glVertex3f(-w,h,z);
            glVertex3f(-w,-h,z);
    
            glVertex3f(-w,h,z);
            glVertex3f(w,h,z);
    
            glVertex3f(-w,-h,z);
            glVertex3f(w,-h,z);
            glEnd();
    
            glPopMatrix();
    
            glEnd();
        }
    }
    
    // step 3:显示所有关键帧的Essential Graph (本征图),通过显示界面选择是否显示关键帧连接关系。
    /**已知共视图中存储了所有关键帧的共视关系,本征图中对边进行了优化,
    保存了所有节点,只存储了具有较多共视点的边,用于进行优化,
    而生成树则进一步进行了优化,保存了所有节点,但是值保存具有最多共视地图点的关键帧的边**/
    if(bDrawGraph)
    {
        glLineWidth(mGraphLineWidth);
        glColor4f(0.0f,1.0f,0.0f,0.6f);
        glBegin(GL_LINES);
    
        for(size_t i=0; i<vpKFs.size(); i++)
        {
            // Covisibility Graph
            // step 3.1 共视程度比较高的共视关键帧用线连接
            //遍历每一个关键帧,得到它们共视程度比较高的关键帧
            const vector<KeyFrame*> vCovKFs = vpKFs[i]->GetCovisiblesByWeight(100);
            //遍历每一个关键帧,得到它在世界坐标系下的相机坐标
            cv::Mat Ow = vpKFs[i]->GetCameraCenter();
            if(!vCovKFs.empty())
            {
                for(vector<KeyFrame*>::const_iterator vit=vCovKFs.begin(), vend=vCovKFs.end(); vit!=vend; vit++)
                {
                //单向绘制
                    if((*vit)->mnId<vpKFs[i]->mnId)
                        continue;
                    cv::Mat Ow2 = (*vit)->GetCameraCenter();
                    glVertex3f(Ow.at<float>(0),Ow.at<float>(1),Ow.at<float>(2));
                    glVertex3f(Ow2.at<float>(0),Ow2.at<float>(1),Ow2.at<float>(2));
                }
            }
    
            // Spanning tree
            // step 3.2 连接最小生成树
            KeyFrame* pParent = vpKFs[i]->GetParent();
            if(pParent)
            {
                cv::Mat Owp = pParent->GetCameraCenter();
                glVertex3f(Ow.at<float>(0),Ow.at<float>(1),Ow.at<float>(2));
                glVertex3f(Owp.at<float>(0),Owp.at<float>(1),Owp.at<float>(2));
            }
    
            // Loops
            // step 3.3 连接闭环时形成的连接关系
            set<KeyFrame*> sLoopKFs = vpKFs[i]->GetLoopEdges();
            for(set<KeyFrame*>::iterator sit=sLoopKFs.begin(), send=sLoopKFs.end(); sit!=send; sit++)
            {
                if((*sit)->mnId<vpKFs[i]->mnId)
                    continue;
                cv::Mat Owl = (*sit)->GetCameraCenter();
                glVertex3f(Ow.at<float>(0),Ow.at<float>(1),Ow.at<float>(2));
                glVertex3f(Owl.at<float>(0),Owl.at<float>(1),Owl.at<float>(2));
            }
        }
    
        glEnd();
    }
    
    if(bDrawInertialGraph && mpAtlas->isImuInitialized())
    {
        glLineWidth(mGraphLineWidth);
        glColor4f(1.0f,0.0f,0.0f,0.6f);
        glBegin(GL_LINES);
    
        //Draw inertial links
        for(size_t i=0; i<vpKFs.size(); i++)
        {
            KeyFrame* pKFi = vpKFs[i];
            cv::Mat Ow = pKFi->GetCameraCenter();
            KeyFrame* pNext = pKFi->mNextKF;
            if(pNext)
            {
                cv::Mat Owp = pNext->GetCameraCenter();
                glVertex3f(Ow.at<float>(0),Ow.at<float>(1),Ow.at<float>(2));
                glVertex3f(Owp.at<float>(0),Owp.at<float>(1),Owp.at<float>(2));
            }
        }
    
        glEnd();
    }
    
    vector<Map*> vpMaps = mpAtlas->GetAllMaps();
    
    if(bDrawKF)
    {
        for(Map* pMap : vpMaps)
        {
            if(pMap == mpAtlas->GetCurrentMap())
                continue;
    
            vector<KeyFrame*> vpKFs = pMap->GetAllKeyFrames();
    
            for(size_t i=0; i<vpKFs.size(); i++)
            {
                KeyFrame* pKF = vpKFs[i];
                cv::Mat Twc = pKF->GetPoseInverse().t();
                unsigned int index_color = pKF->mnOriginMapId;
    
                glPushMatrix();
    
                glMultMatrixf(Twc.ptr<GLfloat>(0));
    
                if(!vpKFs[i]->GetParent()) // It is the first KF in the map
                {
                    glLineWidth(mKeyFrameLineWidth*5);
                    glColor3f(1.0f,0.0f,0.0f);
                    glBegin(GL_LINES);
                }
                else
                {
                    glLineWidth(mKeyFrameLineWidth);
                    glColor3f(mfFrameColors[index_color][0],mfFrameColors[index_color][1],mfFrameColors[index_color][2]);
                    glBegin(GL_LINES);
                }
    
                glVertex3f(0,0,0);
                glVertex3f(w,h,z);
                glVertex3f(0,0,0);
                glVertex3f(w,-h,z);
                glVertex3f(0,0,0);
                glVertex3f(-w,-h,z);
                glVertex3f(0,0,0);
                glVertex3f(-w,h,z);
    
                glVertex3f(w,h,z);
                glVertex3f(w,-h,z);
    
                glVertex3f(-w,h,z);
                glVertex3f(-w,-h,z);
    
                glVertex3f(-w,h,z);
                glVertex3f(w,h,z);
    
                glVertex3f(-w,-h,z);
                glVertex3f(w,-h,z);
                glEnd();
    
                glPopMatrix();
            }
        }
    }
    }
  • 随后实现了DrawCurrentCamera 功能模块,在初始化阶段设置了历史关键帧图标,并根据绘图参数如宽度、颜色等具体绘制点如何连接进行了详细参数设置。与之前分析过的功能模块类似,在此从略不做详细代码展示。
    • 最后实现了SetCurrentCameraPose 功能模块负责对当前相机位姿进行配置,并主要目的是为了优化多线程操作性能。
复制代码
    void MapDrawer::SetCurrentCameraPose(const cv::Mat &Tcw)
    {
    unique_lock<mutex> lock(mMutexCamera);
    mCameraPose = Tcw.clone();
    }

该函数负责将相机姿态mCameraPose从Mat数据格式转换为OpenGl矩阵格式

这一部分主要介绍了MapDrawer类的主要内容,在功能上与Map和MapPoint相比相对较少但作用明确非常简洁明了。接下来将对带map tag的三个类进行详细分析然后介绍Converter类的相关内容

全部评论 (0)

还没有任何评论哟~