1. 程式人生 > >【OpenCV】視覺SLAM漫談 (合集)

【OpenCV】視覺SLAM漫談 (合集)

視覺SLAM漫談

1.    前言

  開始做SLAM(機器人同時定位與建圖)研究已經近一年了。從一年級開始對這個方向產生興趣,到現在為止,也算是對這個領域有了大致的瞭解。然而越瞭解,越覺得這個方向難度很大。總體來講有以下幾個原因:

  • 入門資料很少。雖然國內也有不少人在做,但這方面現在沒有太好的入門教程。《SLAM for dummies》可以算是一篇。中文資料幾乎沒有。
  • SLAM研究已進行了三十多年,從上世紀的九十年代開始。其中又有若干歷史分枝和爭論,要把握它的走向就很費工夫。
  • 難以實現。SLAM是一個完整的系統,由許多個分支模組組成。現在經典的方案是“影象前端,優化後端,閉環檢測”的三部曲,很多文獻看完了自己實現不出來。
  • 自己動手程式設計需要學習大量的先決知識。首先你要會C和C++,網上很多程式碼還用了11標準的C++。第二要會用Linux。第三要會cmake,vim/emacs及一些程式設計工具。第四要會用openCV, PCL, Eigen等第三方庫。只有學會了這些東西之後,你才能真正上手編一個SLAM系統。如果你要跑實際機器人,還要會ROS。

  當然,困難多意味著收穫也多,坎坷的道路才能鍛鍊人(比如說走著走著才發現Linux和C++才是我的真愛之類的。)鑑於目前網上關於視覺SLAM的資料極少,我於是想把自己這一年多的經驗與大家分享一下。說的不對的地方請大家批評指正。

  這篇文章關注視覺SLAM,專指用攝像機,Kinect等深度像機來做導航和探索,且主要關心室內部分。到目前為止,室內的視覺SLAM仍處於研究階段,遠未到實際應用的程度。一方面,編寫和使用視覺SLAM需要大量的專業知識,演算法的實時性未達到實用要求;另一方面,視覺SLAM生成的地圖(多數是點雲)還不能用來做機器人的路徑規劃,需要科研人員進一步的探索和研究。以下,我會介紹SLAM的歷史、理論以及實現的方式,且主要介紹視覺(Kinect)的實現方式。

2.    SLAM問題

  SLAM,全稱叫做Simultaneous Localization and Mapping,中文叫做同時定位與建圖。啊不行,這麼講下去,這篇文章肯定沒有人讀,所以我們換一個講法。

3.    小蘿蔔的故事

  從前,有一個機器人叫“小蘿蔔”。它長著一雙烏黑髮亮的大眼睛,叫做Kinect。有一天,它被邪惡的科學家關進了一間空屋子,裡面放滿了雜七雜八的東西。

 

  小蘿蔔感到很害怕,因為這個地方他從來沒來過,一點兒也不瞭解。讓他感到害怕的主要是三個問題:

  1.          自己在哪裡?

  2.          這是什麼地方?

  3.          怎麼離開這個地方?

  在SLAM理論中,第一個問題稱為定位 (Localization),第二個稱為建圖 (Mapping),第三個則是隨後的路徑規劃。我們希望藉助Kinect工具,幫小蘿蔔解決這個難題。各位同學有什麼思路呢?

4.    Kinect資料

  要打敗敵人,首先要了解你的武器。不錯,我們先介紹一下Kinect。眾所周知這是一款深度相機,你或許還聽說過別的牌子,但Kinect的價格便宜,測量範圍在3m-12m之間,精度約3cm,較適合於小蘿蔔這樣的室內機器人。它採到的影象是這個樣子的(從左往右依次為rgb圖,深度圖與點雲圖):

 

  Kinect的一大優勢在於能比較廉價地獲得每個畫素的深度值,不管是從時間上還是從經濟上來說。OK,有了這些資訊,小蘿蔔事實上可以知道它採集到的圖片中,每一個點的3d位置。只要我們事先標定了Kinect,或者採用出廠的標定值。

  我們把座標系設成這個樣子,這也是openCV中採用的預設座標系。

 

  o’-uv是圖片座標系,o-xyz是Kinect的座標系。假設圖片中的點為(u,v),對應的三維點位置在(x,y,z),那麼它們之間的轉換關係是這樣的:

 

  或者更簡單的:

 

  後一個公式給出了計算三維點的方法。先從深度圖中讀取深度資料(Kinect給的是16位無符號整數),除掉z方向的縮放因子,這樣你就把一個整數變到了以米為單位的資料。然後,x,y用上面的公式算出。一點都不難,就是一箇中心點位置和一個焦距而已。f代表焦距,c代表中心。如果你沒有自己標定你的Kinect,也可以採用預設的值:s=5000, cx = 320, cy=240, fx=fy=525。實際值會有一點偏差,但不會太大。

5.    定位問題

  知道了Kinect中每個點的位置後,接下來我們要做的,就是根據兩幀影象間的差別計算小蘿蔔的位移。比如下面兩張圖,後一張是在前一張之後1秒採集到的:

   

  你肯定可以看出,小蘿蔔往右轉過了一定的角度。但究竟轉過多少度呢?這就要靠計算機來求解了。這個問題稱為相機相對姿態估計,經典的演算法是ICP(Iterative Closest Point,迭代最近點)。這個演算法要求知道這兩個影象間的一組匹配點,說的通俗點,就是左邊影象哪些點和右邊是一樣的。你當然看見那塊黑白相間的板子同時出現在兩張影象中。在小蘿蔔看來,這裡牽涉到兩個簡單的問題:特徵點的提取和匹配。

  如果你熟悉計算機視覺,那你應該聽說過SIFT, SURF之類的特徵。不錯,要解決定位問題,首先要得到兩張影象的一個匹配。匹配的基礎是影象的特徵,下圖就是SIFT提取的關鍵點與匹配結果:

  

  對實現程式碼感興趣的同學請Google“opencv 匹配”即可,在openCV的教程上也有很明白的例子。上面的例子可以看出,我們找到了一些匹配,但其中有些是對的(基本平等的匹配線),有些是錯的。這是由於影象中存在週期性出現的紋理(黑白塊),所以容易搞錯。但這並不是問題,在接下來的處理中我們會將這些影響消去。

  得到了一組匹配點後,我們就可以計算兩個影象間的轉換關係,也叫PnP問題。它的模型是這樣的:

 

  R為相機的姿態,C為相機的標定矩陣。R是不斷運動的,而C則是隨著相機做死的。ICP的模型稍有不同,但原理上也是計算相機的姿態矩陣。原則上,只要有四組匹配點,就可以算這個矩陣。你可以呼叫openCV的SolvePnPRANSAC函式或者PCL的ICP演算法來求解。openCV提供的演算法是RANSAC(Random Sample Consensus,隨機取樣一致性)架構,可以剔除錯誤匹配。所以程式碼實際執行時,可以很好地找到匹配點。以下是一個結果的示例。

 

  上面兩張圖轉過了16.63度,位移幾乎沒有。

  有同學會說,那隻要不斷匹配下去,定位問題不就解決了嗎?表面上看來,的確是這樣的,只要我們引入一個關鍵幀的結構(發現位移超過一個固定值時,定義成一個關鍵幀)。然後,把新的影象與關鍵幀比較就行了。至於建圖,就是把這些關鍵幀的點雲拼起來,看著還有模有樣,煞有介事的:

 

1-200幀的匹配結果

  然而,如果事情真這麼簡單,SLAM理論就不用那麼多人研究三十多年了(它是從上世紀90年代開始研究的)(上面講的那些東西簡直隨便哪裡找個小碩士就能做出來……)。那麼,問題難在什麼地方呢?

6.    SLAM端優化理論

  最麻煩的問題,就是“噪聲”。這種漸近式的匹配方式,和那些慣性測量裝置一樣,存在著累積噪聲。因為我們在不斷地更新關鍵幀,把新影象與最近的關鍵幀比較,從而獲得機器人的位移資訊。但是你要想到,如果有一個關鍵幀出現了偏移,那麼剩下的位移估計都會多出一個誤差。這個誤差還會累積,因為後面的估計都基於前面的機器人位置……哇!這後果簡直不堪設想啊(例如,你的機器人往右轉了30度,再往左轉了30度回到原來的位置。然而由於誤差,你算成了向右轉29度,再向左轉31度,這樣你構建的地圖中,會出現初始位置的兩個“重影”)。我們能不能想辦法消除這個該死的誤差呢?

  朋友們,這才是SLAM的研究,前面的可以說是“影象前端”的處理方法。我們的解決思路是:如果你和最近的關鍵幀相比,會導致累計誤差。那麼,我們最好是和更前面的關鍵幀相比,而且多比較幾個幀,不要只比較一次。

  我們用數學來描述這個問題。設:

 

  不要怕,只有藉助數學才能把這個問題講清楚。上面的公式中,xp是機器人小蘿蔔的位置,我們假定由n個幀組成。xL則是路標,在我們的影象處理過程中就是指SIFT提出來的關鍵點。如果你做2D SLAM,那麼機器人位置就是x, y加一個轉角theta。如果是3D SLAM,就是x,y,z加一個四元數姿態(或者rpy姿態)。這個過程叫做引數化(Parameterization)。

  不管你用哪種引數,後面兩個方程你都需要知道。前一個叫運動方程,描述機器人怎樣運動。u是機器人的輸入,w是噪聲。這個方程最簡單的形式,就是你能通過什麼方式(碼盤等)獲得兩幀間的位移差,那麼這個方程就直接是上一幀與u相加即得。另外,你也可以完全不用慣性測量裝置,這樣我們就只依靠影象裝置來估計,這也是可以的。

  後一個方程叫觀測方程,描述那些路標是怎麼來的。你在第i幀看到了第j個路標,產生了一個測量值,就是影象中的橫縱座標。最後一項是噪聲。偷偷告訴你,這個方程形式上和上一頁的那個方程是一模一樣的。

  在求解SLAM問題前,我們要看到,我們擁有的資料是什麼?在上面的模型裡,我們知道的是運動資訊u以及觀測z。用示意圖表示出來是這樣的:

 

  我們要求解的,就是根據這些u和z,確定所有的xp和xL。這就是SLAM問題的理論。從SLAM誕生開始科學家們就一直在解決這個問題。最初,我們用Kalman濾波器,所以上面的模型(運動方程和觀測方程)被建成這個樣子。直到21世紀初,卡爾曼濾波器仍在SLAM系統佔據最主要的地位,Davison經典的單目SLAM就是用EKF做的。但是後來,出現了基於圖優化的SLAM方法,漸漸有取而代之的地位[1]。我們在這裡不介紹卡爾曼濾波器,有興趣的同學可以在wiki上找卡爾曼濾波器,另有一篇中文的《卡爾曼濾波器介紹》也很棒。由於濾波器方法儲存n個路標要消耗n平方的空間,在計算量上有點對不住大家。儘管08年有人提出分治法的濾波器能把複雜度弄到O(n) [2],但實現手段比較複雜。我們要介紹那種新興的方法: Graph-based SLAM。

  圖優化方法把SLAM問題做成了一個優化問題。學過運籌學的同學應該明白,優化問題對我們有多麼重要。我們不是要求解機器人的位置和路標位置嗎?我們可以先做一個猜測,猜想它們大概在什麼地方。這其實是不難的。然後呢,將猜測值與運動模型/觀測模型給出的值相比較,可以算出誤差:

 

  通俗一點地講,例如,我猜機器人第一幀在(0,0,0),第二幀在(0,0,1)。但是u1告訴我機器人往z方向(前方)走了0.9米,那麼運動方程就出現了0.1m的誤差。同時,第一幀中機器人發現了路標1,它在該機器人影象的正中間;第二幀卻發現它在中間偏右的位置。這時我們猜測機器人只是往前走,也是存在誤差的。至於這個誤差是多少,可以根據觀測方程算出來。

  我們得到了一堆誤差,把這些誤差平方後加起來(因為單純的誤差有正有負,然而平方誤差可以改成其他的範數,只是平方更常用),就得到了平方誤差和。我們把這個和記作phi,就是我們優化問題的目標函式。而優化變數就是那些個xp, xL。

 

  改變優化變數,誤差平方和(目標函式)就會相應地變大或變小,我們可以用數值方法求它們的梯度和二階梯度矩陣,然後用梯度下降法求最優值。這些東西學過優化的同學都懂的。

 

  注意到,一次機器人SLAM過程中,往往會有成千上萬幀。而每一幀我們都有幾百個關鍵點,一乘就是幾百萬個優化變數。這個規模的優化問題放到小蘿蔔的機載小破本上可解嗎?是的,過去的同學都以為,Graph-based SLAM是無法計算的。但就在21世紀06,07年後,有些同學發現了,這個問題規模沒有想象的那麼大。上面的J和H兩個矩陣是“稀疏矩陣”,於是呢,我們可以用稀疏代數的方法來解這個問題。“稀疏”的原因,在於每一個路標,往往不可能出現在所有運動過程中,通常只出現在一小部分影象裡。正是這個稀疏性,使得優化思路成為了現實。

  優化方法利用了所有可以用到的資訊(稱為full-SLAM, global SLAM),其精確度要比我們一開始講的幀間匹配高很多。當然計算量也要高一些。

  由於優化的稀疏性,人們喜歡用“圖”來表達這個問題。所謂圖,就是由節點和邊組成的東西。我寫成G={V,E},大家就明白了。V是優化變數節點,E表示運動/觀測方程的約束。什麼,更糊塗了嗎?那我就上一張圖,來自[3]。

 

  圖有點模糊,而且數學符號和我用的不太一樣,我用它來給大家一個圖優化的直觀形象。上圖中,p是機器人位置,l是路標,z是觀測,t是位移。其中呢,p, l是優化變數,而z,t是優化的約束。看起來是不是像一些彈簧連線了一些質點呢?因為每個路標不可能出現在每一幀中,所以這個圖是蠻稀疏的。不過,“圖”優化只是優化問題的一個表達形式,並不影響優化的含義。實際解起來時還是要用數值法找梯度的。這種思路在計算機視覺裡,也叫做Bundle Adjustment。它的具體方法請參見一篇經典文章[4]。

  不過,BA的實現方法太複雜,不太建議同學們拿C來寫。好在2010年的ICRA上,其他的同學們提供了一個通用的開發包:g2o [5]。它是有圖優化通用求解器,很好用,我改天再詳細介紹這個軟體包。總之,我們只要把觀測和運動資訊丟到求解器裡就行。這個優化器會為我們求出機器人的軌跡和路標位置。如下圖,紅點是路標,藍色箭頭是機器人的位置和轉角(2D SLAM)。細心的同學會發現它往右偏轉了一些。:

 

7.    閉環檢測

  上面提到,僅用幀間匹配最大的問題在於誤差累積,圖優化的方法可以有效地減少累計誤差。然而,如果把所有測量都丟進g2o,計算量還是有點兒大的。根據我自己測試,約10000多條邊,g2o跑起來就有些吃力了。這樣,就有同學說,能把這個圖構造地簡潔一些嗎?我們用不著所有的資訊,只需要把有用的拿出來就行了。

  事實上,小蘿蔔在探索房間時,經常會左轉一下,右轉一下。如果在某個時刻他回到了以前去過的地方,我們就直接與那時候採集的關鍵幀做比較,可以嗎?我們說,可以,而且那是最好的方法。這個問題叫做閉環檢測。

  閉環檢測是說,新來一張影象時,如何判斷它以前是否在影象序列中出現過?有兩種思路:一是根據我們估計的機器人位置,看是否與以前某個位置鄰近;二是根據影象的外觀,看它是否和以前關鍵幀相似。目前主流方法是後一種,因為很多科學家認為前一種依靠有噪聲的位置來減少位置的噪聲,有點迴圈論證的意思。後一種方法呢,本質上是個模式識別問題(非監督聚類,分類),常用的是Bag-of-Words (BOW)。但是BOW需要事先對字典進行訓練,因此SLAM研究者仍在探討有沒有更合適的方法。

  在Kinect SLAM經典大作中[6],作者採用了比較簡單的閉環方法:在前面n個關鍵幀中隨機採k個,與當前幀兩兩匹配。匹配上後認為出現閉環。這個真是相當的簡單實用,效率也過得去。

  高效的閉環檢測是SLAM精確求解的基礎。這方面還有很多工作可以做。

8.    小結

  本文我們介紹了SLAM的基本概念,重點介紹了圖優化解決SLAM問題的思路。我最近正在編寫SLAM程式,它是一個Linux下基於cmake的工程。目前仍在開發當中。歡迎感興趣的同學來交流研究心得,我的郵件是:[email protected]

參考文獻

[1] Visual SLAM: Why filter? Strasdat et. al., Image and Vision Computing, 2012.

[2] Divide and Conquer: EKF SLAM in O(n), Paz Lina M et al., IEEE Transaction on Robotics, 2008

[3] Relative bundle adjustment, Sibley, Gabe, 2009

[4] Bundle adjustment - a Modern Synthesis. Triggs B et. el., Springer, 2000

[5] g2o: A General Framework for Graph Optimization, Kummerle Rainer, et. al., ICRA, 2011

[6] 3-D Mapping with an RGB-D Camera, IEEE Transaction on Robotics, Endres et al., 2014


視覺SLAM漫談(二):圖優化理論與g2o的使用

1    前言以及回顧

  各位朋友,自從上一篇《視覺SLAM漫談》寫成以來已經有一段時間了。我收到幾位熱心讀者的郵件。有的希望我介紹一下當前視覺SLAM程式的實用程度,更多的人希望瞭解一下前文提到的g2o優化庫。因此我另寫一篇小文章來專門介紹這個新玩意。

  在開始本篇文章正文以前,我們先來回顧一下圖優化SLAM問題的提法。至於SLAM更基礎的內容,例如SLAM是什麼東西等等,請參見上一篇文章。我們直接進入較深層次的討論。首先,關於我們要做的事情,你可以這樣想:

  l   已知的東西:感測器資料(影象,點雲,慣性測量裝置等)。我們的感測器主要是一個Kinect,因此資料就是一個視訊序列,說的再詳細點就是一個RGB點陣圖序列與一個深度圖序列。至於慣性測量裝置,可以有也可以沒有。

  l   待求的東西:機器人的運動軌跡,地圖的描述。運動軌跡,畫出來應該就像是一條路徑。而地圖的描述,通常是點雲的描述。但是點雲描述是否可用於導航、規劃等後續問題,還有待研究。

  這兩個點之間還是有挺長的路要走的。如果我們使用圖優化,往往會在整個視訊序列中,定義若干個關鍵幀:

  這個圖著實畫的有點醜,請大家不要吐槽……不管怎麼說,它表達出我想表達的意思。在這張圖中,我們有一個路標點(五角星),並在各個關鍵幀中都看到了這個點。於是,我們就能用PnP或ICP求解相鄰關鍵點的運動方向。這些在上篇文章都介紹過了,包括特徵選擇,匹配及計算等等。那麼,這個過程中有什麼問題呢?

2    為什麼要用全域性優化

  你一定已經注意到,理想的計算總和實際有差距的。好比說理想的科研就是“看論文——產生想法——做實驗——發文章”,那麼現實的科研就是“看論文——產生想法——做實驗——發現該想法在二十年前就有人做過了”,這樣一個過程。實際當中,僅通過幀間運動(ego-motion)來計算機器人軌跡是遠遠不夠的。如下圖所示:

  

  如果你只用幀間匹配,那麼每一幀的誤差將對後面所有的運動軌跡都要產生影響。例如第二幀往右偏了0.1,那麼後面第三、四、五幀都要往右偏0.1,還要加上它們自己的估算誤差。所以結果就是:當程式跑上十幾秒之後早就不知道飛到哪兒去了。這是經典的SLAM現象,在EKF實現中,也會發現,當機器人不斷運動時,不確定性會不斷增長。當然不是我們所希望的結果。

  那麼怎麼辦才好呢?想象你到了一個陌生的城市,安全地走出了火車站,並在附近遊蕩了一會兒。當你走的越遠,看到許多未知的建築。你就越搞不清楚自己在什麼地方。如果是你,你會怎麼辦?

  通常的做法是認準一個標誌性建築物,在它周圍轉上幾圈,弄清楚附近的環境。然後再一點點兒擴大我們走過的範圍。在這個過程中,我們會時常回到之前已經見過的場景,因此對它周圍的景象就會很熟悉。

  機器人的情形也差不多,除了大多數時候是人在遙控它行走。因而我們希望,機器人不要僅和它上一個幀進行比較,而是和更多先前的幀比較,找出其中的相似之處。這就是所謂的迴環檢測(Loop closure detection)。用下面的示意圖來說明:

  沒有迴環時,由於誤差對後續幀產生影響,機器人路徑估計很不穩定。加上一些區域性迴環,幾個相鄰幀就多了一些約束,因而誤差就減少了。你可以把它看成一個由彈簧連起來的鏈條(質點-彈簧模型)。當機器人經過若干時間,回到最初地方時,檢測出了大回環時,整個環內的結構都會變得穩定很多。我們就可以籍此知道一個房間是方的還是圓的,面前這堵牆對應著以前哪一堵牆,等等。

  相信講到這裡,大家對迴環檢測都有了一個感性的認識。那麼,這件事情具體是怎麼建模,怎麼計算,怎麼程式設計呢?下面我們就一步步來介紹。

3    圖優化的數學模型

  SLAM問題的優化模型可以有幾種不同的建模方式。我們挑選其中較簡單的一種進行介紹,即FrameSLAM,在2008年提出。它的特點是隻用位姿約束而不用特徵約束,減少了很多計算量,表達起來也比較直觀。下面我們給出一種6自由度的3D SLAM建模方法。

  符號:

  注意到這裡的建模與前文有所不同,是一個簡化版的模型。因為我們假設幀間匹配時得到了相鄰幀的變換矩陣,而不是把所有特徵也放到優化問題裡面來。所以這個模型看上去相對簡單。但是它很實用,因為不用引入特徵,所以結點和邊的數量大大減少,要知道在影象裡提特徵動輒成百上千的。

4    g2o是什麼

  g2o,就是對上述問題的一個求解器。它原理上是一個通用的求解器,並不限定於某些SLAM問題。你可以用它來求SLAM,也可以用ICP, PnP以及其他你能想到的可以用圖來表達的優化問題。它的程式碼很規範,就是有一個缺點:文件太少。唯一的說明文件還有點太裝叉(個人感覺)了,有點擺弄作者數學水平的意思,反正那篇文件很難懂就是了。話說程式文件不應該是告訴我怎麼用才對麼……

4.1     安裝

  g2o是一個用cmake管理的C++工程,我是用Linux編譯的,所以不要問我怎麼在win下面用g2o,因為我也不會……不管怎麼說,你下載了它的zip包或者用git拷下來之後,裡面有一個README檔案。告訴你它的依賴項。在ubuntu下,直接鍵入命令:

  sudo apt-get install cmake libeigen3-dev libsuitesparse-dev libqt4-dev qt4-qmake libqglviewer-qt4-dev

  我個人感覺還要 libcsparse-dev和freeglut3這兩個庫,反正多裝了也無所謂。注意libqglviewer-qt4-dev只在ubuntu 12.04庫裡有,14.04 裡換成另一個庫了。g2o的視覺化工具g2o_viewer是依賴這個庫的,所以,如果你在14.04下面編,要麼是去把12.04那個deb(以及它的依賴項)找出來裝好,要麼用ccmake,把build apps一項給去掉,這樣就不編譯這個工具了。否則編譯過不去。

  解開zip後,新建一個build資料夾,然後就是:

  cmake ..

  make

  sudo make install

  這樣g2o就裝到了你的/usr/local/lib和/usr/local/include下面。你可以到這兩個地方去看它的庫檔案與標頭檔案。

4.2     學習g2o的使用

  因為g2o的文件真的很裝叉(不能忍),所以建議你直接看它的原始碼,耐心看,應該比文件好懂些。它的example文件夾下有一些示例程式碼,其中有一個tutorial_slam2d資料夾下有2d slam模擬的一個程式。值得仔細閱讀。

  使用g2o來實現圖優化還是比較容易的。它幫你把節點和邊的型別都定義好了,基本上只需使用它內建的型別而不需自己重新定義。要構造一個圖,要做以下幾件事:

  l   定義一個SparseOptimizer. 編寫方式參見tutorial_slam2d的宣告方式。你還要寫明它使用的演算法。通常是Gauss-Newton或LM演算法。個人覺得後者更好一些。

  l   定義你要用到的邊、節點的型別。例如我們實現一個3D SLAM。那麼就要看它的g2o/types/slam3d下面的標頭檔案。節點標頭檔案都以vertex_開頭,而邊則以edge_開頭。在我們上面的模型中,可以選擇vertex_se3作為節點,edge_se3作為邊。這兩個型別的節點和邊的資料都可以直接來自於Eigen::Isometry,即上面講到過的變換矩陣T。

  l   編寫一個幀間匹配程式,通過兩張影象算出變換矩陣。這個用opencv, pcl都可以做。

  l   把你得到的關鍵幀作為節點,變換矩陣作為邊,加入到optimizer中。同時設定節點的估計值(如果沒有慣性測量就設成零)與邊的約束(變換矩陣)。此外,每條邊還需設定一個資訊矩陣(協方差矩陣之逆)作為不確定性的度量。例如你覺得幀間匹配精度在0.1m,那麼把資訊矩陣設成100的對角陣即可。

  l   在程式執行過程中不斷作幀間檢測,維護你的圖。

  l   程式結束時呼叫optimizer.optimize( steps )進行優化。優化完畢後讀取每個節點的估計值,此時就是優化後的機器人軌跡。

  程式碼這種東西展開來說會變得像字典一樣枯燥,所以具體的東西需要大家自己去看,自己去體會。這裡有我自己寫的一個程式,可以供大家參考。不過這個程式需要帶著資料集才能跑,學習g2o的同學只需參考裡面程式碼的寫法即可:https://github.com/gaoxiang12/slam3d_gx

5    效果

  最近我跑了幾個公開資料集(http://vision.in.tum.de/data/datasets/rgbd-dataset)上的例子(fr1_desk, fr2_slam)(,感覺效果還不錯。有些資料集還是挺難的。最後一張圖是g2o_viewer,可以看到那些關鍵路徑點與邊的樣子。

  以上,如有什麼問題,歡迎與我交流:[email protected]


1.  前言

  讀者朋友們大家好!(很久很久)之前,我們為大家介紹了SLAM的基本概念和方法。相信大家對SLAM,應該有了基本的認識。在忙完一堆寫論文、博士開題的事情之後,我準備回來繼續填坑:為大家介紹SLAM研究的方方面面。如果前兩篇文章算是"初識",接下來幾篇就是"漸入佳境"了。在第三篇中,我們要談談SLAM中的各個研究點,為研究生們(應該是部落格的多數讀者吧)作一個提綱挈領的摘要。然後,我們再就各個小問題,講講經典的演算法與分類。我有耐心講,你是否有耐心聽呢?

  在《SLAM for Dummy》中,有一句話說的好:"SLAM並不是一種演算法,而是一個概念。(SLAM is more like a concept than a single algorithm.)"所以,你可以和導師、師兄弟(以及師妹,如果有的話)說你在研究SLAM,但是,作為同行,我可能更關心:你在研究SLAM中的哪一個問題。有些研究者專注於實現一個具體的SLAM系統,而更多的人則是在研究SLAM裡某些方法的改進。做應用和做理論的人往往彼此看不起,不過二者對科研都是有貢獻的。作為研究生,我還是建議各位抓住SLAM中一個小問題,看看能否對現有的演算法進行改進或者比較。不要覺得這種事情膚淺,它是對研究有實際幫助和意義的。同時,我也有一些朋友,做了一個基於濾波器/圖優化的SLAM實現。程式是跑起來了,但他/她不知道自己有哪些貢獻,鑽研了哪個問題,寫論文的時候就很頭疼。所以,作為研究生,我建議你選擇SLAM中的一個問題,改進其中的演算法,而不是先找一堆程式跑起來再說。

  那麼問題來了:SLAM方面究竟有哪些可以研究的地方呢?我為大家上一個腦圖。

  這個圖是從我筆記本上拍下來的(請勿吐槽字和對焦)。可以看到,以SLAM為中心,有五個圈連線到它。我稱它為Basic Theory(基礎理論)、Sensor(感測器)、Mapping(建圖)、Loop Detection(迴環檢測)、Advanced Topic(高階問題)。這可以說是SLAM的研究方向。下面我們"花開五朵,各表一枝"。

2.  基本理論

  SLAM的基本理論,是指它的數學建模。也就是你如何用數學模型來表達這個問題。為什麼說它"基本"呢?因為數學模型影響著整個系統的效能,決定了其他問題的處理方法。在早先的研究中(86年提出[1]至21世紀前期[2]),是使用卡爾曼濾波器的數學模型的。那裡的機器人,就是一個位姿的時間序列;而地圖,就是一堆路標點的集合。什麼是路標點的集合?就是用(x,y,z)表示每一個路標,然後在濾波器更新的過程中,讓這三個數慢慢收斂。

  那麼,請問這樣的模型好不好?

  好處是可以直接套用濾波器的求解方法。卡爾曼濾波器是很成熟的理論,比較靠譜。

  缺點呢?首先,濾波器有什麼缺點,基於它的SLAM就有什麼缺點。所以EKF的線性化假設啊,必須儲存協方差矩陣帶來的資源消耗啊,都成了缺點(之後的文章裡會介紹)。然後呢,最直觀的就是,用(x,y,z)表示路標?萬一路標變了怎麼辦?平時我們不就把屋裡的桌子椅子挪來挪去的嗎?那時候濾波器就掛了。所以啊,它也不適用於動態的場合。

  這種侷限性就是數學模型本身帶來的,和其他的演算法無關。如果你希望在動態環境中跑SLAM,就要使用其他模型或改進現有的模型了。

  SLAM的基本理論,向來分為濾波器和優化方法兩類。濾波器有擴充套件卡爾曼濾波(EKF)、粒子濾波(PF),FastSLAM等,較早出現。而優化方向用姿態圖(Pose Graph),其思想在先前的文章中介紹過。近年來用優化的逐漸增多,而濾波器方面則在13年出現了基於Random Finite Set的方法[3],也是一個新興的浪潮[4]。關於這些方法的詳細內容,我們在今後的文章中再進行討論。

  作為SLAM的研究人員,應該對各種基本理論以及優缺點有一個大致的瞭解,儘管它們的實現可能非常複雜。

3.  感測器

  感測器是機器人感知世界的方式。感測器的選擇和安裝方式,決定了觀測方程的具體形式,也在很大程度上影響著SLAM問題的難度。早期的SLAM多使用鐳射感測器(Laser Range Finder),而現在則多使用視覺相機、深度相機、聲吶(水下)以及感測器融合。我覺得該方向可供研究點有如下幾個:

  • 如何使用新興感測器進行SLAM。    要知道感測器在不斷髮展,總有新式的東西會出來,所以這方面研究肯定不會斷。
  • 不同的安裝方式對SLAM的影響。    舉例來說,比如相機,頂視(看天花板)和下視(看地板)的SLAM問題要比平視容易很多。為什麼容易呢?因為頂/下視的資料非常穩定,不像平視,要受各種東西的干擾。當然,你也可以研究其他的安裝方式。
  • 改進傳統感測器的資料處理。        這部分就有些困難了,因為經常感測器已經有很多人在使用,你做的改進,未必比現有的成熟方法更好。

4.  建圖

  建圖,顧名思議,就是如何畫地圖唄。其實,如果知道了機器人的真實軌跡,畫地圖是很簡單的一件事。不過,地圖的具體形式也是研究點之一。比如說常見的有以下幾種:

  • 路標地圖。       

  地圖由一堆路標點組成。EKF中的地圖就是這樣的。但是,也有人說,這真的是地圖嗎(這些零零碎碎的點都是什麼啊喂)?所以路標圖儘管很方便,但多數人對這種地圖是不滿意的,至少看上去不像個地圖啊。於是就有了密集型地圖(Dense map)。

  • 度量地圖(Metric map)    

  通常指2D/3D的網格地圖,也就是大家經常見的那種黑白的/點雲式地圖。點雲地圖比較酷炫,很有種高科技的感覺。它的優點是精度比較高,比如2D地圖可以用0-1表示某個點是否可通過,對導航很有用。缺點是相當吃儲存空間,特別是3D,把所有空間點都存起來了,然而大多數角角落落裡的點除了好看之外都沒什麼意義……

  • 拓撲地圖(Topological map)       

  拓撲地圖是比度量地圖更緊湊的一種地圖。它將地圖抽象為圖論中的"點"和"邊",使之更符合人類的思維。比如說我要去五道口,不知道路,去問別人。那人肯定不會說,你先往前走621米,向左拐94.2度,再走1035米……(這是瘋子吧)。正常人肯定會說,往前走到第二個十字路口,左拐,走到下一個紅綠燈,等等。這就是拓撲地圖。

  • 混合地圖。        

  既然有人要分類,就肯定有人想把各類的好處揉到一起。這個就不多說了吧。

5.  迴環檢測

  迴環檢測,又稱閉環檢測(Loop closure detection),是指機器人識別曾到達場景的能力。如果檢測成功,可以顯著地減小累積誤差。

  迴環檢測目前多采用詞袋模型(Bag-of-Word),研究計算機視覺的同學肯定不會陌生。它實質上是一個檢測觀測資料相似性的問題。在詞袋模型中,我們提取每張影象中的特徵,把它們的特徵向量(descriptor)進行聚類,建立類別資料庫。比如說,眼睛、鼻子、耳朵、嘴等等(實際當中沒那麼高階,基本上是一些邊緣和角)。假設有10000個類吧。然後,對於每一個影象,可以分析它含有資料庫中哪幾個類。以1表示有,以0表示沒有。那麼,這個影象就可用10000維的一個向量來表達。而不同的影象,只要比較它們的向量即可。

  迴環檢測也可以建成一個模型識別問題,所以你也可以使用各種機器學習的方法來做,比如什麼決策樹/SVM,也可以試試Deep Learning。不過實際當中要求實時檢測,沒有那麼多時間讓你訓練分類器。所以SLAM更側重線上的學習方法。

6.  高階話題

  前面的都是基礎的SLAM,只有"定位"和"建圖"兩件事。這兩件事在今天已經做的比較完善了。近幾年的RGB-D SLAM[5], SVO[6], Kinect Fusion[7]等等,都已經做出了十分炫的效果。但是SLAM還未走進人們的實際生活。為什麼呢?

  因為實際環境往往非常複雜。燈光會變,太陽東昇西落,不斷的有人從門裡面進進出出,並不是一間安安靜靜的空屋子,讓一個機器人以2cm/s的速度慢慢逛。論文中看起來酷炫的演算法,在實際環境中往往捉襟見肘,處處碰壁。向實際環境挑戰,是SLAM技術的主要發展方向,也就是我們所說的高階話題。主要有:動態場景、語義地圖、多機器人協作等等。

7.  小結

  本文向大家介紹了SLAM中的各個研究點。我並不想把它寫成綜述,因為不一定有人願意看一堆的參考文獻,我更想把它寫成小故事的形式。

  最後,讓我們想象一下未來SLAM的樣子吧:

  有一天,小蘿蔔被領進了一家新的實驗樓。在短暫的自我介紹之後,他飛快地在樓裡逛了一圈,記住了哪裡是走廊,哪兒是房間。他刻意地觀察各個房間特有的物品,以便區分這些看起來很相似的房間。然後,他回到了科學家身邊,協助他的研究。有時,科學家會讓他去各個屋裡找人,找資料,有時,也帶著他去認識新安裝的儀器和裝置。在閒著沒事時,小蘿蔔也會在樓裡逛逛,看看那些屋裡都有什麼變化。每當新的參觀人員到來,小蘿蔔會給他們看樓裡的平面圖,向他們介紹各個樓層的方位與狀況,為他們導航。大家都很喜歡小蘿蔔。而小蘿蔔明白,這一切,都是過去幾十年裡SLAM研究人員不斷探索的結果。

References:

[1].    Smith, R.C. and P. Cheeseman, On the Representation and Estimation of Spatial Uncertainty. International Journal of Robotics Research, 1986. 5(4): p. 56--68.

相關推薦

OpenCV視覺SLAM漫談 ()

視覺SLAM漫談 1.    前言   開始做SLAM(機器人同時定位與建圖)研究已經近一年了。從一年級開始對這個方向產生興趣,到現在為止,也算是對這個領域有了大致的瞭解。然而越瞭解,越覺得這個方向難度很大。總體來講有以下幾個原因: 入門資料很少。雖然

題解AC自動機題解

  最近貌似大家都在搞字串?很長一段時間都沒有寫部落格了……還是補一補坑吧。   感覺AC自動機真的非常優美了,通過在trie樹上建立fail指標可以輕鬆解決多模匹配的問題。實際上在AC自動機上的匹配可以看做是拿著一個串在上面跑,在固定一個左端點的時候儘量地向右匹配。如果發現實在是匹配不下去了,就向右挪動左

福利計算機公開課(視訊教程)

計算機公開課合集   【公開課】23種設計模式 · 未名大學 樑立新   23種設計模式:http://www.chinesemooc.org/live/763912     【公開課】資料結構與演算法 北京大學 趙海燕

模板二叉樹

1501 二叉樹最大寬度和高度 時間限制: 1 s 空間限制: 128000 KB 題目等級 : 白銀 Silver 題解 題目描述 Description 給出一個二叉樹,輸出它的最大寬度和高度。 輸入描述 Input Descr

opencv機器視覺識別鋼板層數備忘錄

原圖: 首先想到的是基於邊緣檢測或者閾值分割的方法進行檢測: #include<opencv2\opencv.hpp> #include<iostream> using namespace std; using namespace cv; Mat o

OpenCV計算機視覺程式設計攻略用形態學濾波器檢測邊緣和角點

準備工作: 腐蝕和膨脹是最基本的形態學運算, 數學形態學中最基本的概念是結構元素。 結構元素可以簡單地定義為畫素的組合(下圖的正方形) , 在對應的畫素上定義了一個原點(也稱錨點) 。 形態學濾波器的應用過程就包含了用這個結構元素探測影象中每個畫素的操作過程。 把某個畫素設

OpenCV計算機視覺程式設計攻略全書總結

第1章 影象程式設計入門 1.1 簡介 1.2 安裝OpenCV庫 1.3 裝載、顯示和儲存影象 - imread——讀影象 - namedWindow——定義視窗 - imshow——顯示影象 - flip——翻轉影象 - waitKey——等待按鍵 -

動態規劃常見揹包問題

01揹包:  有N件物品和一個容量為V的揹包。(每件物品只有一件)第i件物品的費用是c[i],價值是v[i],求解將哪些物品裝入揹包使總價值最大。 轉移方程:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]},可以優化只用一維陣列. 程式碼

BZOJ3319黑白樹 並查

維護 2個 bzoj3 printf highlight 集合 else cst find 【BZOJ3319】黑白樹 Description 給定一棵樹,邊的顏色為黑或白,初始時全部為白色。維護兩個操作:1.查詢u到根路徑上的第一條黑色邊的標號。2.將u到v

OpenCVimread讀取數據為空

依賴 技術分享 分享 bug features 附加 分開 什麽 ont 直接加配置好的props文件到新的工程時,會出現imread讀出來的Mat為空的情形,搜了一下,發現是opencv的配置問題!!! 是這樣的,之前配置時為了省事兒,無論是Debug還是Release中

MongoDB管理之副本

bottom reference mil 沒有 options 過程 新版 會有 滿足 一、復制介紹 所謂的復制就是在多個主機之間同步數據的過程。 1、數據冗余及可用性 復制技術提供數據冗余及可用性,在不同的數據庫服務器上使用多個數據副本,復制技術防止單個數據庫服務器出現數

opencvJava實現的opencv3.x版本後Highhui報錯

-a sun div fan let 版本 ava line 報錯 隨筆為博主原創,如需轉載,請註明出處。 opencv3.x以後Highgui不再使用,用Imgcodecs代替,引入import org.opencv.imgcodecs.Imgcode

gitgit分支的

stat diff 出錯 傳輸 .html read 簡單 流程 保存 原文: http://gitbook.liuhui998.com/3_3.html http://gitbook.liuhui998.com/5_3.html 一、如何分支的合並 在gi

troubleshooting記一次Kafka群重啟導致消息重復消費問題處理記錄

進程 pid 導致 set pic 方法 sum tails log 因需要重啟了Kafka集群,重啟後發現部分topic出現大量消息積壓,檢查consumer日誌,發現消費的數據竟然是幾天前的。由於平時topic消息基本上無積壓,consumer消費的數據都是最新的,明顯

PANDAS 數據並與重塑(concat篇)

分享 levels 不同的 整理 con 簡單 post ignore num 轉自:http://blog.csdn.net/stevenkwong/article/details/52528616 1 concat concat函數是在pandas底下的方法,可以將數據

角落的開發工具之Vs(Visual Studio)2017插件推薦

diff image 下載 場景 圖像 部分 bundle emmet down 因為最近錄制視頻的緣故,很多朋友都在QQ群留言,或者微信公眾號私信我,問我一些工具和一些插件啊,怎麽使用的啊?那麽今天我忙裏偷閑整理一下清單,然後在這裏面公布出來。 Visual Stu

Quartz.net持久化與群部署開發詳解

疑惑 sum 常用 drive wid res net github hub 轉自:http://www.cnblogs.com/knowledgesea/p/5145239.html 序言 我前邊有幾篇文章有介紹過quartz的基本使用語法與類庫。但是他的執行計劃都是被寫

洛谷P3402 模板可持久化並查(可持久化線段樹,線段樹)

std 樹節點 https case 深度 build eof spa 復雜度 orz TPLY 巨佬,題解講的挺好的。 這裏重點梳理一下思路,做一個小小的補充吧。 寫可持久化線段樹,葉子節點維護每個位置的fa,利用每次只更新一個節點的特性,每次插入\(logN\)個節點,

OpenCV透視變換矯正

file info 事件 ima 變換 data include imshow spec 演示結果參考: 功能實現:運行程序,會顯示圖片的尺寸,按回車鍵後,依次點擊需矯正的圖片的左上、右上、左下、右下角,結果彈出矯正後的圖片,如圖上的PIC2對話框。按下字符‘q‘後

OpenCVMFC圖片、視頻、攝像頭輸入響應詳細圖解

tsp box 背景建模 img 有變 highgui 復制 creat int 記住新建項目後,要配置OpenCV環境!參考鏈接http://blog.csdn.net/zy122121cs/article/details/49180541 做工程搭建框架什麽的,基本的