---
# System prepended metadata

title: Viewer.cpp

---

# Viewer.cpp

### Viewer::Viewer()
Viewer的參數初始化
在[System::System()](#System::System())中引用

#### 定義
```
Viewer::Viewer(System* pSystem, 
               FrameDrawer *pFrameDrawer, 
               MapDrawer *pMapDrawer, 
               Tracking *pTracking, 
               const string &strSettingPath):
               mpSystem(pSystem), 
               mpFrameDrawer(pFrameDrawer),
               mpMapDrawer(pMapDrawer), 
               mpTracker(pTracking),
               mbFinishRequested(false), 
               mbFinished(true), 
               mbStopped(false), 
               mbStopRequested(false)
```

#### 函式流程
1. 讀取配置檔案
2. 參數初始化 


#### 流程詳解
1. 讀取配置檔案
```
cv::FileStorage fSettings(strSettingPath, cv::FileStorage::READ);
```

2. 參數初始化 
```
float fps = fSettings["Camera.fps"];
if(fps<1)
    fps=30;
mT = 1e3/fps;

mImageWidth = fSettings["Camera.width"];
mImageHeight = fSettings["Camera.height"];
if(mImageWidth<1 || mImageHeight<1)
{
    mImageWidth = 640;
    mImageHeight = 480;
}

mViewpointX = fSettings["Viewer.ViewpointX"];
mViewpointY = fSettings["Viewer.ViewpointY"];
mViewpointZ = fSettings["Viewer.ViewpointZ"];
mViewpointF = fSettings["Viewer.ViewpointF"];
```


### Viewer::Run()
跑可視化界面線程
在[System::System()](#System::System())中引用

#### 函式流程
1. 可視化界面初始化
2. 建立可視化界面選單
3. 建立虛擬相機
4. 定義可視化界面面板
5. 線程開始
6. 得到最新的相機姿態
7. 根據相機姿態調整視角
8. 繪製當前相機
9. 繪製當前關鍵幀
10. 繪製當前地圖點
11. 顯示有特徵點的影像
12. 當reset按下時，重設系統
13. 停止系統


#### 流程詳解
1. 可視化界面初始化
```
//這個變數配合 SetFinish 函數用於指示該函數是否執行完畢
mbFinished = false;

pangolin::CreateWindowAndBind("ORB-SLAM2: Map Viewer",1024,768);

// 3D Mouse handler requires depth testing to be enabled
// 啟動深度測試，OpenGL只繪製最前面的一層，繪製時檢查當前像素前面是否有別的像素，如果別的像素擋住了它，那它就不會繪製
glEnable(GL_DEPTH_TEST);

// Issue specific OpenGl we might need
// 在OpenGL中使用顏色混合
glEnable(GL_BLEND);
// 選擇混合選項
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
```

2. 建立可視化界面選單
```
// 新建按鈕和選擇框，第一個參數為按鈕的名字，第二個為默認狀態，第三個為是否有選擇框
pangolin::CreatePanel("menu").SetBounds(0.0,1.0,0.0,pangolin::Attach::Pix(175));
pangolin::Var<bool> menuFollowCamera("menu.Follow Camera",true,true);
pangolin::Var<bool> menuShowPoints("menu.Show Points",true,true);
pangolin::Var<bool> menuShowKeyFrames("menu.Show KeyFrames",true,true);
pangolin::Var<bool> menuShowGraph("menu.Show Graph",true,true);
pangolin::Var<bool> menuLocalizationMode("menu.Localization Mode",false,true);
pangolin::Var<bool> menuReset("menu.Reset",false,false);
```

3. 建立虛擬相機
```
// Define Camera Render Object (for view / scene browsing)
// 定義相機投影模型：ProjectionMatrix(w, h, fu, fv, u0, v0, zNear, zFar)
// 定義觀測方位向量：觀測點位置：(mViewpointX mViewpointY mViewpointZ)
//                觀測目標位置：(0, 0, 0)
//                觀測的方位向量：(0.0,-1.0, 0.0)
pangolin::OpenGlRenderState s_cam(
            pangolin::ProjectionMatrix(1024,768,mViewpointF,mViewpointF,512,389,0.1,1000),
            pangolin::ModelViewLookAt(mViewpointX,mViewpointY,mViewpointZ, 0,0,0,0.0,-1.0, 0.0)
            );
```

4. 定義可視化界面面板
```
// Add named OpenGL viewport to window and provide 3D Handler
// 定義顯示面板大小，orbslam中有左右兩個面板，昨天顯示一些按鈕，右邊顯示圖形
// 前兩個參數（0.0, 1.0）表明寬度和麵板縱向寬度和窗口大小相同
// 中間兩個參數（pangolin::Attach::Pix(175), 1.0）表明右邊所有部分用於顯示圖形
// 最後一個參數（-1024.0f/768.0f）為顯示長寬比
pangolin::View& d_cam = pangolin::CreateDisplay()
        .SetBounds(0.0, 1.0, pangolin::Attach::Pix(175), 1.0, -1024.0f/768.0f)
        .SetHandler(new pangolin::Handler3D(s_cam));
```

5. 線程開始
```
pangolin::OpenGlMatrix Twc;
Twc.SetIdentity();

cv::namedWindow("ORB-SLAM2: Current Frame");

bool bFollow = true;
bool bLocalizationMode = false;

while(1)
{
    // 清除緩衝區中的當前可寫的顏色緩衝 和 深度緩衝
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
```

6. 得到最新的相機姿態
```
    mpMapDrawer->GetCurrentOpenGLCameraMatrix(Twc);
```
跳到[MapDrawer::GetCurrentOpenGLCameraMatrix()](#MapDrawer::GetCurrentOpenGLCameraMatrix())

7. 根據相機姿態調整視角
```
    // menuFollowCamera為按鈕的狀態，bFollow為真實的狀態
     //相機正在跟隨
    if(menuFollowCamera && bFollow)   
    {
        // 相機跟隨Twc位置的設置
        s_cam.Follow(Twc);
    }
    //相機剛剛啟動跟隨
    else if(menuFollowCamera && !bFollow)    
    {
       
        //確保在啟用相機跟隨功能時，相機的視角能夠根據使用者指定的位置和朝向進行調整。
        s_cam.SetModelViewMatrix(pangolin::ModelViewLookAt(mViewpointX,mViewpointY,mViewpointZ, 0,0,0,0.0,-1.0, 0.0));
        s_cam.Follow(Twc);
        bFollow = true;
    }
    //相機不進行跟隨
    else if(!menuFollowCamera && bFollow)
    {
        bFollow = false;
    }

    if(menuLocalizationMode && !bLocalizationMode)
    {
        //打開定位模式
        mpSystem->ActivateLocalizationMode();
        bLocalizationMode = true;
    }
    else if(!menuLocalizationMode && bLocalizationMode)
    {
        //關閉定位模式
        mpSystem->DeactivateLocalizationMode();
        bLocalizationMode = false;
    }

    d_cam.Activate(s_cam);
    // 設置為白色，glClearColor(red, green, blue, alpha），數值範圍(0, 1)
    glClearColor(1.0f,1.0f,1.0f,1.0f);
```

8. 繪製當前相機
```
    //繪製當前相機
    mpMapDrawer->DrawCurrentCamera(Twc);
```
mpMapDrawer->DrawCurrentCamera: 跳到[MapDrawer::DrawCurrentCamera()](#MapDrawer::DrawCurrentCamera())

9. 繪製當前關鍵幀
```
    if(menuShowKeyFrames || menuShowGraph)
        mpMapDrawer->DrawKeyFrames(menuShowKeyFrames,menuShowGraph);        
```
跳到[MapDrawer::DrawKeyFrames()](#MapDrawer::DrawKeyFrames())

10. 繪製當前地圖點
```
    if(menuShowPoints)
        mpMapDrawer->DrawMapPoints();
    
    //刷新視窗
    pangolin::FinishFrame();
```
跳到[MapDrawer::DrawMapPoints()](#MapDrawer::DrawMapPoints())

11. 繪製有特徵點的影像
```
    cv::Mat im = mpFrameDrawer->DrawFrame();
    cv::imshow("ORB-SLAM2: Current Frame",im);
    cv::waitKey(mT);
```
跳到[FrameDrawer::DrawFrame()](#FrameDrawer::DrawFrame())

12. 當reset按下時，重設系統
```
    //reset按鈕是否有被按下
    if(menuReset)
    {
        menuShowGraph = true;
        menuShowKeyFrames = true;
        menuShowPoints = true;
        menuLocalizationMode = false;
        if(bLocalizationMode)
            mpSystem->DeactivateLocalizationMode();
        bLocalizationMode = false;
        bFollow = true;
        menuFollowCamera = true;
        mpSystem->Reset();
        menuReset = false;
    }
```
13. 停止系統
```
    if(Stop())
    {
        while(isStopped())
        {
            //usleep(3000);
            std::this_thread::sleep_for(std::chrono::milliseconds(3));

        }
    }

    if(CheckFinish())
        break;
}

SetFinish();
```