1. 程式人生 > >ORB-SLAM2 論文&程式碼學習 —— LocalMapping 執行緒

ORB-SLAM2 論文&程式碼學習 —— LocalMapping 執行緒

轉載請註明出處,謝謝
原創作者:Mingrui
原創連結:https://www.cnblogs.com/MingruiYu/p/12360913.html


本文要點:

  • ORB-SLAM2 LocalMapping 執行緒 論文內容介紹
  • ORB-SLAM2 LocalMapping 執行緒 程式碼結構介紹

寫在前面

之前的 ORB-SLAM2 系列文章中,我們已經對 Tracking 執行緒和其中的單目初始化部分進行了介紹。我們將在本文中,對 ORB-SLAM2 系統的 LocalMapping 執行緒進行介紹。

依舊祭出該圖,方便檢視:

也再次獻上我繪製的程式導圖全圖:ORB-SLAM2 程式導圖

老規矩,還是分兩部分:以 ORB-SLAM 論文為參考 和 以 ORB-SLAM2 程式碼(程式導圖)為參考。

以 ORB-SLAM 論文為參考

LocalMapping 執行緒的大致步驟如下:

  • 接收從 Tracking 執行緒插入的 KF,並進行預處理
  • 剔除質量較差的 MapPoints
  • 通過三角化生成新的 MapPoints
    • Current KF 未與現有 MapPoints 匹配的 FeaturePoints 與其 Covisible KFs 的 FeaturePoints 進行匹配,並三角化
  • Local BA
  • 剔除冗餘的區域性 KF

LocalMapping 執行緒的存在主要有這麼幾個意義:

  • 篩選 KFs
  • 進一步優化 Tracking 執行緒得到的 KFs 位姿以及 MapPoints 座標,但這個優化還是相對輕量級的(與 LoopClosing 執行緒相比),且這裡的優化不涉及迴環

下面我們對每一個步驟進行詳細的介紹。

插入 KF

當 Tracking 執行緒確定一個要插入的 KF 時,實際上它並沒有真的完成將 KF 插入 Map 的動作。當我們將一個 KF 插入 Map 中時,我們需要同時做很多更新工作:

  • 更新 Covisibility Graph(在 Covisibility Graph 中新增新的 KF node,根據共視關係新增新的 edge)
  • 更新生成樹
  • 計算新 KF 的 BoW (便於後面通過特徵匹配和三角化生成新的 MapPoints)

剔除質量較差的 MapPoints

儲存在 Map 中的 MapPoints 需要有較高的質量(追蹤良好,三角化正確),所以此處需要採取一些措施去掉質量較差的 MapPoints。判斷 MapPoints 質量較差的標準為,在該 MapPoint 被創造後的3個 KFs 時間範圍內:

  • 實際看到該 MapPoints 的幀數 / 應該看到該 MapPoints 的幀數 < 25% (注意不只是 KFs)
    • 應該看到該 MapPoints 的幀:當我們有了某 MapPoint,也有了某幀的位姿時,我們可以通過投影判斷該 MapPoint 是否在該幀的視野內,這些幀就是應該看到該 MapPoints 的幀
    • 實際看到該 MapPoints 的幀:通過各種匹配方式,該 MapPoints 與某幀的某個 FeaturePoint 匹配上了,這些幀就是實際看到該 MapPoints 的幀
  • 該 MapPoints 在被創造後,未能被至少3個 KFs 觀測到(此處論文表達似乎不太清楚)

注意:即使 MapPoints 在創造滿足上述要求,得以保留,但不代表它們以後不可能被剔除。如果之後因為 KF 的剔除(下文會講)導致觀測到該 MapPoint 的 KF 數少於3個,或者在 local BA 中該觀測被認為是 outlier,那麼它依然會被剔除。

通過三角化生成生成新的 MapPoints

對於單目 ORB-SLAM 來說,整個系統中只有兩處可以在 Map 中新增 MapPoints:一處是初始化的時候,另一處就是這裡。

ORB-SLAM 將在 Current KF 的未能與已存在 MapPoints 匹配上的 FeaturePoints,與其 Covisible KFs 中同樣未能與已存在 MapPoints 匹配上的 FeaturePoints 進行匹配。如果匹配上了,則可以通過三角化,生成一個新的 MapPoint(生成之後要檢查其位置,視差,重投影誤差,尺度一致性)。這個 FeaturePoint 與 FeaturePoint 之間的匹配是通過 BoW 搜尋實現的。

通過兩個 KFs 生成新的 MapPoint 後,還要檢查它有沒有在別的 KFs 中出現。所以要將該 MapPoint 投影至其他的 Covisible KFs,與它們的 FeaturePoints 進行匹配。匹配上的話就將該 MapPoint 與那個 KF 的那個 FeaturePoint 連結上。

區域性 BA

對 Current KF 及其 Covisible KFs 及其它們所觀察到的所有 MapPoints 進行 BA 優化。

注意,其他觀測到這些 MapPoints,但是不再上述 KFs 之列的 KFs,也會作為約束參與該優化(其本身不會被優化)。

剔除冗餘的區域性 KF

在 Tracking 執行緒中,ORB-SLAM 以非常寬鬆的條件,向 Map 中插入了很多很多 KFs,但顯然 Map 中是不能永久保留這麼多 KFs 的,這會使 Map 過於龐大,且極大增加各種 BA 的運算量。所以要剔除一些資訊冗餘的。

如果 Current KF 及其 Covisible KFs 中,有哪個 KF 它所觀測到的 90% 的 MapPoints 都能被其它至少3個(尺度相同或更好的)KFs 觀測到,則這個 KF 的資訊就算作是冗餘的,就把它去掉。這樣做的目的是讓 Map 的 KF 數不要太多,且在規模一定的場景內,Map 中的 KF 數目不要無上限的增長。這樣也有利於減輕 BA 優化的負擔。

以 ORB-SLAM2 程式碼(程式導圖)為參考

上圖就是 LocalMapping 執行緒的程式導圖,從中可以很清晰地看出 LocalMapping 執行緒的邏輯,並且和論文中的步驟進行對應。

如果嫌這張圖不夠清晰的話,可以點選 ORB-SLAM2 程式導圖連結(文首)檢視清晰全圖

插入 KF

在插入 KF 後,會通過 LocalMapping::SetAcceptKeyFrames(false) 通知 Tracking 執行緒,LocalMapping 執行緒正忙。記得在 Tracking 執行緒中最後一步決定是否插入關鍵幀時,有一個條件就是:

  • LocalMapping 執行緒正閒置,但如果已經有連續20幀內沒有插入過 KF 了,那麼 LocalMapping 執行緒不管忙不忙,都要插入 KF 了

另外,LocalMapping 執行緒通過維護一個佇列來儲存 Tracking 執行緒送入,但還未被 LocalMapping 處理的 KFs。LocalMapping::CheckNewKeyFrames() 用來檢查該佇列裡有沒有 KF。

從上述佇列中取出隊首 KF,使用 LocalMapping::ProcessNewKeyFrame() 對其進行處理,包括計算該 KF 的 BoW,以及更新 Covisibility Graph。最後,經過上述處理的 KF 才可以真正插入 Map 之中。

剔除質量較差的 MapPoints

LocalMapping::MapPointCulling()

通過三角化生成新的 MapPoints

LocalMapping::CreateNewMapPoints()

MapPoints 融合

當佇列中所有的 KFs 都經過上述處理了(佇列空了),那麼才會開始接下來的步驟。

MapPoints 融合,這部分其實是屬於通過三角化生成新的 MapPoints 裡的,論文中說過:“通過兩個 KFs 生成新的 MapPoint 後,還要檢查它有沒有在別的 KFs 中出現。所以要將該 MapPoint 投影至其他的 Covisible KFs,與它們的 FeaturePoints 進行匹配。匹配上的話就將該 MapPoint 與那個 KF 的那個 FeaturePoint 連結上”,這一步的目的就在與完成這項工作。

但是,這裡需要注意,在上述表述中,“匹配上的話就將該 MapPoint 與那個 KF 的那個 FeaturePoint 連結上”,但如果這些條件都麼滿足,但那個 FeaturePoint 已經連結上了某個 MapPoint 怎麼辦?ORB-SLAM 採取的策略很簡單,用新的 MapPoint 替換掉原來連結的 MapPoint。

舉一個可能出現這種情況的情景:同時有4個剛送入 LocalMapping 執行緒的 KFs 觀測到了 MapPoint_1 (MapPoint_1 此前未在 Map 中建立)。在上文三角化的過程中,假設 KF_1 和 KF_2 三角化生成了 MapPoint_1,但同時 KF_3 和 KF_4 也三角化生成了 MapPoint_1。佇列中所有 KFs 處理完畢後,此時,我在將 KF_1 的 MapPoint 投影至 KF_3 時,就會發現 KF_3 的匹配 FeaturePoint 已經連結了 MapPoint了。此時需要一個融合策略(ORB-SLAM 簡單的採用了替換的方法)。

Local BA

當佇列中所有的 KFs 都經過上述處理了(佇列空),且 其他執行緒沒有讓 LocalMapping 執行緒暫停(後面會提到 LoopClosing 執行緒中有地方會讓 LocalMapping 執行緒中的 Local BA 先暫停),則進行 Optimizer::LocalBundleAdjustment()。

剔除冗餘的 KFs

LocalMapping::KeyFrameCulling()

最後通過 LocalMapping::SetAcceptKeyFrames(true) 通知 Tracking 執行緒,LocalMapping 執行緒閒下來了,可以有條件的接收 KFs 了。

ORB-SLAM2 系列博文

ORB-SLAM2 初體驗 —— 配置安裝

ORB-SLAM2 論文&程式碼學習 —— 概覽

ORB-SLAM2 論文&程式碼學習 —— Tracking 執行緒

ORB-SLAM2 論文&程式碼學習 —— 單目初始化

ORB-SLAM2 論文&程式碼學習 —— LocalMapping 執行緒

相關推薦

ORB-SLAM2 論文&amp;程式碼學習 —— LocalMapping 執行

轉載請註明出處,謝謝 原創作者:Mingrui 原創連結:https://www.cnblogs.com/MingruiYu/p/12360913.html 本文要點: ORB-SLAM2 LocalMapping 執行緒 論文內容介紹 ORB-SLAM2 LocalMapping 執行緒 程式碼結構介紹

ORB-SLAM2 論文&amp;程式碼學習 ——Tracking 執行

轉載請註明出處,謝謝 原創作者:MingruiYu 原創連結:https://www.cnblogs.com/MingruiYu/p/12352960.html 本文要點: ORB-SLAM2 Tracking 執行緒 論文內容介紹 ORB-SLAM2 Tracking 執行緒 程式碼結構介紹 寫在前面

ORB-SLAM2 論文&amp;程式碼學習 —— 概覽

轉載請註明出處,謝謝 原創作者:MingruiYU 原創連結:https://www.cnblogs.com/MingruiYu/p/12347171.html 本文要點: ORB-SLAM2 簡介 ORB-SLAM2 實體物件之間的關係 ORB-SLAM2 系統概覽 (參考論文 + 程式碼) 以思維導圖

ORB-SLAM2 論文&amp;程式碼學習 —— 單目初始化

轉載請註明出處,謝謝 原創作者:Mingrui 原創連結:https://www.cnblogs.com/MingruiYu/p/12358458.html 本文要點: ORB-SLAM2 單目初始化部分 論文內容介紹 ORB-SLAM2 單目初始化部分 程式碼結構介紹 寫在前面 之前的 ORB-SLA

《Frustum PointNets for 3D Object Detection from RGB-D Data》論文程式碼學習(二)程式碼部分

《Frustum PointNets for 3D Object Detection from RGB-D Data》論文及程式碼學習(二)程式碼部分 文章目錄 《Frustum PointNets for 3D Object Detection from RG

《Frustum PointNets for 3D Object Detection from RGB-D Data》論文程式碼學習

《Frustum PointNets for 3D Object Detection from RGB-D Data》論文及程式碼學習 《Frustum PointNets for 3D Object Detection from RGB-D Data》一文是Charles R.Qi

ORB-SLAM2論文解讀與總結

最近閱讀了Raúl Mur-Artal and Juan D. Tardós寫的ORB_SLAM2論文,並做了一些小結ORB-SLAM2: an Open-Source SLAM System for Monocular, Stereo and RGB-D Cameras本人

Anndroid學習---使用執行Handler

Anndroid學習—使用執行緒 Handler 使用Java裡面常用的執行緒呼叫方式,發現不可以 1 . package com.example.administrator.myapplication; import android.os.Handler; import

Java學習|多執行學習筆記

什麼是執行緒?     可以理解為程序中獨立執行的字任務。   使用多執行緒:     1.繼承Thread類:從原始碼可以看到,Thread累實現了Runnable介面。     &n

記今天學習Linux執行遇到的關於sleep(0)的問題

寫了一段小程式碼,目的是實現 在程序裡用pthread_create()建立新執行緒thread,然後sleep當前的main執行緒,程式就會進入剛建立的新執行緒thread,然後新執行緒thread再sleep,main執行緒sleep結束後又可以獲得CPU,如此迴圈幾次。 一開始以為第一

muduo_base程式碼剖析之執行本地單例物件ThreadLocalSingleton

執行緒本地單例物件的封裝ThreadLocalSingleton<T>,也就是說,每一個執行緒都有一個T型別的單例物件 直接看測試程式碼 #include <muduo/base/ThreadLocalSingleton.h> #include &l

muduo_base程式碼剖析之執行特定資料的封裝ThreadLocal

執行緒特定資料 (執行緒內私有的全域性變數)來源 在單執行緒程式中,我們經常要用到“全域性變數”以實現多個函式間能共享資料 在多執行緒環境下,由於資料空間是共享的,因此全域性變數也為所有執行緒共享 但有時應用程式設計中有必要提供執行緒私有的全域性變數,僅在某個執行

muduo_base程式碼剖析之執行安全的Sigleton模式

預備知識 什麼是單例模式? 一個類有且僅有一個例項,並且對外提供統一的訪問該例項的介面 單例模式分為餓漢式、懶漢式,對於餓漢式要保證執行緒安全需要使用double-check lock機制 muduo中實現的執行緒安全的Sigleton類,沒使用鎖,而使用效率更高

Java基礎學習——多執行執行

1.執行緒池介紹     執行緒池是一種執行緒使用模式。執行緒由於具有空閒(eg:等待返回值)和繁忙這種不同狀態,當數量過多時其建立、銷燬、排程等都會帶來開銷。執行緒池維護了多個執行緒,當分配可併發執行的任務時,它負責排程執行緒執行工作,執行完畢後執行緒不關閉而是返回執行緒池,

day 33 執行學習執行程序效率對比. 鎖. 訊號量 . 事件

一  . 執行緒    執行緒是cpu最小的執行單位,是能獨立執行的基本單位,程序是資源分配的最小單位。且:每個程序中最小有一個執行緒   執行緒與程序的區別:   1)地址空間和其它資源(如開啟檔案):程序間相互獨立,同一程序的各執行緒間共享。某程序內的執行緒在其它程序不可見。

高併發學習1--執行的基礎

執行緒的實現 繼承Thread類 必須重寫run()方法 class MyThread extends Thread{ private static int num = 0; public MyThread(){ num++;

2行python程式碼打造多執行工具,這是史上最強的黑科技?

  Python黑科技 兩行程式碼實現多執行緒操作 學習Python中有不明白推薦加入交流群                 號:960410445     &

Java學習——多執行例子:李四王五

  package cys; public class Example9_2 { public static void main(String[] args) { // TODO Auto-generated method stub P

Linux 學習筆記—執行間通訊的概念和執行控制函式

1 執行緒間通訊 執行緒間無需特別的手段進行通訊,由於執行緒間能夠共享資料結構,也就是一個全域性變數能夠被兩個執行緒同一時候使用。只是要注意的是執行緒間須要做好同步,一般用mutex。執行緒間的通訊目的主要是用於執行緒同步,所以執行緒沒有像程序通訊中的用於資料交

Linux 學習筆記—執行同步之互斥量與條件變數

執行緒同步(同步的意思是協同步調) 執行緒同步機制包括互斥,讀寫鎖以及條件變數等 3.2.1 互斥量(互斥鎖) **互斥量本質是一把鎖,在訪問公共資源前對互斥量設定(加鎖),確保同一時間只有一個執行緒訪問資料,在訪問完成後再釋放(解鎖)互斥量。**在互斥量加鎖之