研究SLAM,對編程的要求有多高?
研究SLAM,學習的重點應該放在演算法上,但是覺得編程也很重要。要驗證一些演算法,比如閉環檢測,視覺里程計等部分,要用什麼語言,像比較容易上手和學習的MATLAB能滿足嗎?
看到開源的解決方案中基本都是用C++,除了考慮到效率的問題,還有其他原因嗎。是不是自己做演算法驗證可以不拘泥於編程語言的選擇?
最近想驗證一個閉環檢測演算法,但是網上找到的代碼都是完整的SLAM方案,比如ORB-SLAM, RGBD-SLAM等,請問是否有單獨的實現閉環檢測的代碼可供參考?
我還沒寫你們就開始點贊了,有點過意不去啊……
題主說MATLAB,主要原因是大多數人本科階段接觸的都是MATLAB,所以希望之後研究SLAM也用它。
MATLAB確實有很多優點:語法簡單,開發速度快,調試方便,功能豐富。然而,在SLAM領域,MATLAB缺點也很明顯,主要是這兩個:
- 需要正版軟體(你不能實機上也裝個盜版MATLAB吧);
- 運行效率不高;
- 需要一個巨大的安裝包;
而相對的,C++的優勢在於直接使用,有很高的運行效率,不過開發速度和調試方面慢於MATLAB。不過光運行效率這一條,就夠許多SLAM方案選擇C++作為開發語言了,因為運行效率真的很重要。同一個演算法,拿MATLAB寫出來實現不能實時,拿C++寫的能實時,你說用哪個?
當然MATLAB也有一些用武之地。我見過一些SLAM相關的公開課程,讓學生用MATLAB做模擬,交作業,這沒有問題,比如SLAM toolbox 。同樣的,比較類似於MATLAB的Python(以及octave)亦常被用於此道。它們在開發上的快捷帶來了很多便利,當你想要驗證一些數學理論、思想時,這些都是不錯的工具。所謂技多不壓身,題主掌握MATLAB和Python當然是很棒的。
但是一牽涉到實用,你會發現幾乎所有的方案都在用C++。 因為運行效率實在是太重要了。
那既然有心思學MATLAB,為什麼不學好C++呢?
---------------------分割線------------------
接下來說說C++大概要學到什麼程度。用程序員的話說,C++語言比較特殊,你可以說自己精通了Java,但千萬不要說自己精通了C++。C++非常之博大精深,有數不清的特性,而且隨著時間還會不斷變化更新。不過,大多數人都用不著學會所有的C++特性,因為許多東西一輩子都用不到。
作為SLAM研究人員,我們面對的主要是演算法層面的開發,所以更關心如何有效地實現各種相關的演算法。而相對的,那些複雜的軟體架構,設計模式,我個人認為在SLAM中倒是佔次要地位的。畢竟您用SLAM的目的是計算一個位置以及建個地圖,並不是要去寫一套能夠自動更新的、多人網上對戰功能的機器人大戰平台。您的主要精力可能會花在矩陣運算、分塊、非線性優化的實現、圖像處理上面;您可能對並發、指令集加速、GPU加速等話題感興趣,也可以花點時間學習;你還可能想用模板來拓展你的演算法,也不妨一試。相應的,很多功能性的東西,比如說UI、網路通信等等,當你用到的時候不妨接觸一下,但專註於SLAM上時就不必專門去學習了。
話雖如此,SLAM所需的C++水平,大抵要高於你在書本上看到的那些個示例代碼。因為那些代碼是作者用來向初學者介紹語法的,所以會盡量簡單。而實際見到的代碼往往結合了各種奇特的技巧,乍看起來會顯得高深莫測。比方說你在教科書里看的大概是這樣:
你看了C++ Primer Plus,覺得C++也不過如此,並沒有啥特別難以理解的地方。然而實際代碼大概是這樣的: 嵌套的模板類(來自g2o的塊求解器): 模板元(來自ceres的自動求導): C11新特性(來自SVO特徵提取部分) std::for_each(fts_.begin(), fts_.end(), [](Feature* ftr){ if(ftr-&>point != NULL) checkKeyPoints(ftr); });int main ( int argc, char** argv )
{
vector&
vec.push_back("abc");
for ( int i=0; i&g2o::BlockSolver&< g2o::BlockSolverTraits&<3,1&> &>::LinearSolverType* linearSolver = new g2o::LinearSolverDense&
g2o::BlockSolver&< g2o::BlockSolverTraits&<3,1&> &>* solver_ptr = new g2o::BlockSolver&< g2o::BlockSolverTraits&<3,1&> &>( linearSolver );
g2o::OptimizationAlgorithmLevenberg* solver = new g2o::OptimizationAlgorithmLevenberg( solver_ptr );
g2o::SparseOptimizer optimizer;
optimizer.setAlgorithm( solver );
virtual bool Evaluate(double const* const* parameters,
double* residuals,
double** jacobians) const {
if (!jacobians) {
return internal::VariadicEvaluate&<
CostFunctor, double, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9&>
::Call(*functor_, parameters, residuals);
}
return internal::AutoDiff&
*functor_,
parameters,
SizedCostFunction&
residuals,
jacobians);
}
void Frame::setKeyPoints()
{
for(size_t i = 0; i &< 5; ++i)
if(key_pts_[i] != NULL)
if(key_pts_[i]-&>point == NULL)
key_pts_[i] = NULL;
}
謎之運算(來自SVO的深度濾波器):
void DepthFilter::updateSeed(const float x, const float tau2, Seed* seed)
{
float norm_scale = sqrt(seed-&>sigma2 + tau2);
if(std::isnan(norm_scale))
return;
boost::math::normal_distribution&
float s2 = 1./(1./seed-&>sigma2 + 1./tau2);
float m = s2*(seed-&>mu/seed-&>sigma2 + x/tau2);
float C1 = seed-&>a/(seed-&>a+seed-&>b) * boost::math::pdf(nd, x);
float C2 = seed-&>b/(seed-&>a+seed-&>b) * 1./seed-&>z_range;
float normalization_constant = C1 + C2;
C1 /= normalization_constant;
C2 /= normalization_constant;
float f = C1*(seed-&>a+1.)/(seed-&>a+seed-&>b+1.) + C2*seed-&>a/(seed-&>a+seed-&>b+1.);
float e = C1*(seed-&>a+1.)*(seed-&>a+2.)/((seed-&>a+seed-&>b+1.)*(seed-&>a+seed-&>b+2.))
+ C2*seed-&>a*(seed-&>a+1.0f)/((seed-&>a+seed-&>b+1.0f)*(seed-&>a+seed-&>b+2.0f));
// update parameters
float mu_new = C1*m+C2*seed-&>mu;
seed-&>sigma2 = C1*(s2 + m*m) + C2*(seed-&>sigma2 + seed-&>mu*seed-&>mu) - mu_new*mu_new;
seed-&>mu = mu_new;
seed-&>a = (e-f)/(f-e/f);
seed-&>b = seed-&>a*(1.0f-f)/f;
}
我不知道你們看到這些代碼是什麼心情,總之我當時內心的感受是:卧槽這怎麼和教科書里的完全不一樣啊!而且研究了半天發現人家居然是對的啊!
[我不是很擅長貼表情圖總之你們腦補一下就好]
總而言之,對C++的水平要求應該是在教科書之上的。而且這個水平的提高,多數時候建立在你不斷地看別人代碼、碼自己代碼的過程之上。它是反覆練習出來的,並不是僅僅通過看書就能領會的。特別是對於視覺SLAM問題,很多時候你沒法照著論文把一套方案實現出來,這很大程度上取決於你的理論和代碼功底。
所以,請儘早開始學習C++,儘早開始使用C++,才是研究SLAM的正確之道。不要長期彷徨在自己的舒適區里猶豫不決,這樣是沒有進步的。(同樣的道理亦適用於想研究SLAM但不願意學習Linux的朋友們)
---------------------分割線------------------
題主還提到閉環檢測的庫,稍微列幾個:
DBoW系列,來自TRO12的一篇文章,裡頭用k-means++訓練的字典樹。與OpenCV結合緊密,原理亦比較簡單。
GitHub - dorian3d/DBoW2: Enhanced hierarchical bag-of-word library for C++
GitHub - rmsalinas/DBow3: Improved version of DBow2
FABMAP系列,用了Chow-Liu樹,來自Cummins的一系列論文。作者自己提供過一個開源版本,OpenCV也有人實現了一個,所以一共兩種。
FabMap原版
OpenCV:OpenFABMAP
DLoopDetector:在DBoW2基礎上開發的迴環檢測庫
https://github.com/dorian3d/DLoopDetector
建議題主從DBoW2或者DBoW3開始入手研究。原理和實現都相對簡單一些,效果也比較好。
我自己也在寫一本SLAM的書籍,裡頭帶有大量的演算法實驗。現在還在草稿期,明年出版後題主可以參考一下。鑒於評論區對新書比較感興趣,那我貼個草稿的目錄吧。(由於是草稿所以最後見到的可能會有出入,而且有幾節我也還沒寫完。)所有寫著「實踐部分」的都附有實例代碼。
先回答一下問題:
研究SLAM,學習的重點應該放在演算法上,但是覺得編程也很重要。要驗證一些演算法,比如閉環檢測,視覺里程計等部分,要用什麼語言,像比較容易上手和學習的MATLAB能滿足嗎?
==========================================================
可以應該可以,但是現在有的可用教程並不多。SLAM大多的實現都是基於C++的,尤其是vision SLAM,與閉環檢測相關的。在早期的SLAM模擬代碼里,其實MATLAB code是不少的,例如Tim Bailey提供了幾乎所有早期基於濾波SLAM的模擬實現Homepage of Tim Bailey
還有很多map joining的工作也是matlab的Dr. Shoudong Huang"s Personal Page
以及當初Inverse depth 的monoslam 工作
Javier Civera
總結,用MATLAB不是不行,但是工作都比較老,新的code不多。但是matlab其實圖像處理的工具也很多了,vlfeat,bag-of-words都很成熟了,我覺得如果樓主想嘗試的話,其實把論文或者C代碼看熟了,做一個matlab的實現也沒有問題
看到開源的解決方案中基本都是用C++,除了考慮到效率的問題,還有其他原因嗎。是不是自己做演算法驗證可以不拘泥於編程語言的選擇?
==========================================================
1. 效率原因;2. C語言的靈活性和各種庫。但是,自己做演算法驗證可以不拘泥於編程語言的選擇。
最近想驗證一個閉環檢測演算法,但是網上找到的代碼都是完整的SLAM方案,比如ORB-SLAM, RGBD-SLAM等,請問是否有單獨的實現閉環檢測的代碼可供參考?
==========================================================
有句港句,現在SLAM裡面做閉環檢測的演算法真的很一般很一般,給任何一個CV或者ML出身的人都會說,你們怎麼還用這個代碼去檢測閉環,圖像之間的相似性。而如果你想做這個,用MATLAB來做也可以,至於閉環實現的代碼,之前已經有人說了,不再贅述。其實我挺鼓勵用DL做loop closure detection,現在肯定有人做了。
總問題
研究SLAM,對編程的要求有多高?
=========================================================
我覺得還是挺高的,先從後端說起吧
g2o, gtsam,ceres知道是肯定需要知道的,三者其實學習曲線都挺難的,你覺得你會用了是一回事,然後用好是一回事,自己寫vertex, edge, factor, cost function又是另外一回事,如果你會寫g2o裡面的solver應該又是一個級別了吧。但是這三個在網上的資源而論g2o &> ceres &> gtsam。再者,你會調用api就代表你懂優化了嗎,自己動手matlab寫一下gauss-newton應該也可以試一試吧。當然,遠古一點了levmar也很不錯哦。直到這裡,你確定你明白各種演算法底層suitesparse裡面的效率問題嗎,如果挖掘到了這一層,還有各種線性代數庫的比較哦,肯定是又快有慢。所以說,想要學會一到兩個優化器不難,學會自定義有一點難,考慮到後端的效率自己寫solver更難,深入到線性代數庫的最底層,考慮問題結構,提升效率就更難了
前端,其實僅僅考慮點特徵,也就那麼多東西,V-SLAM用OPENCV也就夠用了,而且opencv我覺得到API調用那一層也就足夠了。如果考慮上RGBD,再加上一個PCL。理論知識方面基本的Multiview geometry其實也就足夠了。但是前端的問題在於很多都是經驗的東西,參數的選擇,循環的次數等等。說白了我個人覺得視覺部分調參的問題更多,理論倒是不容易出問題。
前後段一起的話,什麼線程管理就不用說了,該用的庫都得上,例如boost啥的。有時候做visualization可能還需要一些別的庫。
說完好像要求也就那樣,反正我又不是CS出身活得還好好的拋磚引來大玉,高神出手了~下面的答案就留檔吧,不再增補了。
----------------------------------------------------------------
要搞SLAM,編程能力非常非常重要。編程能力就像運動員的力量和體能,是一切技巧和戰術的基礎。雖然研究的是演算法,但良好的編程能力能夠使你節省大量的時間,並且達到更好的效果。
根據我的經驗,演算法搞得特別好的人很少有編程不行的,因為編程好可以使你能夠迅速驗證想法。見過不少學生因為編程基礎不好,在實現和debug上浪費大把大把的時間。這樣的人當然很難把演算法搞好。
這裡編程能力有很多方面,以下簡單說幾個。贊多了再補( ̄▽ ̄)/
1. 閱讀代碼的能力
未說寫,先說讀。搞科研和搞工程都大忌閉門造車,除了paper外,開源代碼是最有效的學習途徑。一般而言,paper中只是著重描述比較創新的部分,80%以上的實現細節(甚至很多很關鍵的東西)需要從代碼中了解。編程不好的人,往往也不太會讀代碼。
2. 架構軟體,管理複雜項目的能力
一個SLAM方案通常由很多模塊組成。我見過不少實驗室的內部代碼,一鍋粥,學生們各種胡亂修補。這樣必然導致效率低下。如果能做到模塊化、低耦合,可以使開發事半功倍。
3. 高效實現的能力
過去八年間,我最少的一年也碼了兩萬多行。。。根據我的體會,同樣的演算法,好的實現可以比不好的實現快2-10倍。複雜度越高越如是,例如3D SLAM。要擁有高效實現的能力,必須熟悉常用的數據結構,對複雜度分析形成很好的直覺。
4. 管理多線程、非同步程序的能力
SLAM往往涉及到多線程和非同步程序,例如用於後端優化等。玩兒不轉這個就會出現程序不穩定,或效率低。
Matlab不能滿足需要。Matlab對數據結構的支持太差,而且速度慢。即使不考慮產品,只是做演算法,也很不適合。自己做演算法驗證基本上就是C++或python,如果你因為不熟悉這些而選其他語言,會因為參考少、輪子少的原因效率很低。強烈建議題主學習C++,推薦《吸加加,從入門到放棄》一書。
俟補。我也準備湊個熱鬧... 貼點自己寫的估計網上不好找的簡單的matlab代碼...
但是我寫答案總是寫很久啊
----------
已經占坑半年了,還沒提供一點點乾貨。 @半閑居士 @Kache @邵天蘭 都講的很好很多了,尤其關於用C++的好處大家都說了很多(我這兩年因為做產品開發所以拋棄了MatLab),但是這篇回答主要也就展示下我為什麼寫了很多matlab的代碼。因為居士是自動化系的,邵總是軟體學院的,而我是機械系的,我不懂C++好吧~ 而且我也不熟悉g2o, gtsam, ceres... 我對視覺SLAM的研究不深入,但是我肯定是非常了解SLAM的對吧~ 聊一聊matlab的好處。MatLab不用處理數據類型。。。好吧,如果編程習慣差,你都不知道這是個變數還是一個script文件。但是寫起來真快。
按照我自己的習慣,從自己的例子說起,都僅代表一己之見。
第一點,幾乎沒有人的代碼是平地而起的。所以我們選用什麼編程語言,影響很大的是我們能找到那個編程語言版本的參考。早期的很多機器人的文章不開放源碼,只有偽代碼,這時候我們做演算法驗證,MatLab是非常不錯的選擇,偽代碼變matlab代碼,簡直加不了幾行。而且MatLab的圖表可視化工具做的不錯,寫論文要這樣那樣的表格,MatLab就信手拈來了。所以如 @Kache 所說,現在MatLab主要問題是新代碼不多,但是如果想要全部自己寫,MatLab沒什麼問題。
下面是論文里的pseudo code,演算法叫做『select with replacement』,是particle filter中做resample的一種方法。
根據別人論文中描述的這個演算法,在MatLab中重現。我早期的代碼,大概08年,不要用來作參考,因為寫的太爛了。
%Resample
sumWeight = 0;
accSum = 0;
for i = 1:N
sumWeight = particle(i).w + sumWeight;
accSum(i) = sumWeight;
end
來,定義個數組
a = sumWeight * rand(N,1);
sumWeight是個變數。a自然就是個一維數組了。來,排個序。和偽代碼就一模一樣啊!
a = sort(a);
這麼丑的代碼都不好意思貼了。其實是為了做歸一化。
a(N + 1) = sumWeight;
for i = 1:N
particle(i).w = particle(i).w/sumWeight;
end
好吧,代碼寫成這樣,賴不得別人你的MatLab代碼效率低。在MatLab裡面,矩陣運算是很快的,可是跑for循環,tic toc下試試就知道差距了。
indexParticle = 1;
for i = 1:N
indexParticle(i)=1;
end
i = 1;
j = 1;
while (i &<=N) (j &<= N)
if (a(i) &< accSum(j))
indexParticle(i)=j;
i=i+1;
else
j=j+1;
end
end
temp = particle;
for i = 1:N
sub = indexParticle(i);
temp(i) = particle(sub);
end
for i = 1:N
particle(i) = temp(i);
end
說實話,能看懂偽代碼,基本就能寫出MatLab的代碼了,先不論美醜。對於一個機械系畢業的本科生來說,這樣的代碼我自己看的明白,寫起來不費勁。這是Particle filter中的resample部分。你說這需要有多高的編碼技巧?整個particle filter定位的演算法以我這樣寫,連演算法帶一個2D模擬一共300行,一個.m文件就完了。
再說個優點,Matlab的代碼基本找來就能執行,而C++的編譯環境對新手來說有點困難。拿到代碼半天跑不起來就醉了。不過現在很多MatLab擁躉已經轉移到Python的陣地了。
----------
接觸RatSLAM後,因為最早的代碼也是在MatLab裡面的,自然而然我們就繼續MatLab了。而RatSLAM的代碼寫的雖然清晰易懂,但是在效率上應該沒有仔細考慮。下面貼到的部分就是RatSLAM在做閉環時候的代碼。只需要看看數據的結構,不需要讀懂代碼。
exps(curr_exp_id).numlinks = exps(curr_exp_id).numlinks + 1;
exps(curr_exp_id).links(exps(curr_exp_id).numlinks).exp_id = new_exp_id;
exps(curr_exp_id).links(exps(curr_exp_id).numlinks).d = sqrt(accum_delta_x^2 + accum_delta_y^2);
exps(curr_exp_id).links(exps(curr_exp_id).numlinks).heading_rad = Get_Signed_Delta_Rad(exps(curr_exp_id).facing_rad, atan2(accum_delta_y, accum_delta_x));
exps(curr_exp_id).links(exps(curr_exp_id).numlinks).facing_rad = Get_Signed_Delta_Rad(exps(curr_exp_id).facing_rad, accum_delta_facing);
因為MatLab不需要定義結構體,所以對於內存大小是動態變化的結構體內部的元素訪問是非常慢的。為了改變這種寫法,我把以經驗點為主體的序列改成了點與點之間的鏈接作為序列。
link_id = numel(links);
links(link_id).spot_id = prev_spot_id;
links(link_id).target_spot_id = matched_spot_id;
links(link_id).d = sqrt(accum_delta_x^2 + accum_delta_y^2);
links(link_id).heading_rad = Clip_Rad_180(atan2(accum_delta_y,accum_delta_x)-spot_xyth(prev_spot_id,3));
links(link_id).facing_rad = Clip_Rad_180(accum_delta_facing - spot_xyth(prev_spot_id,3));
這種問題大概已經不是改成C++就能解決的問題,而是要從演算法和結構上重構下程序。我們看看OpenRatSLAM在ROS中運行的速度,和MatLab下是差不多的。當然代碼也基本感覺是直接翻譯過去,作者都是David Ball。不過C++對很多結構有嚴格規範,避免了很多問題。
RatSLAM雖然也是基於視覺的SLAM,但是算不上主流的方法,視覺部分做的比較簡單。我自然會想到能不能用BOW替換掉其Scanline Profile的方法。
有不少大學的cs課程都有詳細的vl_feat教程,往往還有優秀學生的作業代碼^_^,參考一下,我自己也寫了個簡單的基於Bag of word的演算法,用了vl_feat,在MatLab下運行也是挺快的~ 下面是類似RatSLAM的一個判斷新增關鍵幀還是閉環的簡單程序。大概是14年的代碼了。
[locations, SIFT_features] = vl_dsift(single(mono_image),"step",DSIFT_STEP,"size",DSIFT_SIZE,"fast");
num_of_feats = size(locations,2);
feature_DIST = vl_alldist2(vocab,single(SIFT_features));
[dist,cat] = min(feature_DIST);
% scene is represented by normalized bag of words
curr_scene_bow(1:vocab_size) = hist(cat,vocab_size)/num_of_feats;
scene_DIST = vl_alldist2(scene_template",curr_scene_bow");
[dist,min_scene_id] = min(scene_DIST);
if dist&> SCENE_MATCH_THRESHOLD min_scene_id~=(num_scenes-1)
%create a new scene
num_scenes = num_scenes + 1;
scene_repeat = 0;
scene_matched = 0;
scene_id = num_scenes;
scene_template(scene_id,1:vocab_size) = curr_scene_bow;
scene_num_spots(scene_id) = 0;
% Scene_spots is a cell array
scene_spots{scene_id} = [];
else
scene_id = min_scene_id;
if scene_id~=prev_scene_id
scene_repeat = 0;
scene_matched = scene_matched + 1;
else % loop closure
scene_repeat = scene_repeat + 1;
end
end
後來寫基於grid cell和place cell的SLAM,因為基於grid cell做的路徑積分的部分代碼就是在MatLab里的,只能繼續MatLab了。。沒有任何優化的時候,代碼慢到令人髮指。跑一次結果20多個小時,還讓不讓人調參數了?當然優化後也要差不多4個小時跑完。這種現階段只重視結果的代碼讓我重新寫成C++,就要老命了。
我們想測試下visual odometry,找到了MatLab下的libviso2,試試~
好了,現在你想跑orbSLAM,人家本來就基於ROS可以跑的好好的,而且還有《視覺SLAM漫談十四講》可以看。你要把每個部分都重新寫成MatLab的話,一定是在逗我~
最後再提一句,如果有的部分需要C++,有的部分需要MatLab,我自己喜好的做法是用tcp/ip來傳數據,而不是轉換代碼。MatLab下一直用pnet,C++裡面就Socket對接,還不錯。再者,在MatLab中做GUI也很方便,而且也能有回調函數,用起來不錯~
我就就幫到這兒了~因為之前在研究所工作,代碼不能開源。但不是說不能分享對吧:)
% PNET - IO-function for TCP and UDP comunation in matlab.
%
%
% This function can be called with different options/commands to operate on
% tcp/udp/ip connection in matlab. It supports data transfer with
% different data types and byte orders. The function is implemented as an
% MEX-file that needs to be
還是用c++,面試的slam相關的工作,你說你一直用matlab編程,人家懷疑瞬間心裡就感覺日了狗吧!
堅持吧~slam用到c++中難的語言特性還是比較少的,c++ primer足夠了
目前我正在做關於SLAM方面的開發,就我的經驗而言我總結如下:首先應該先明確自己的目的是什麼的,不能盲目進行選擇,因為編程能力和研究二者不是速成的,在某一段時間中偏重任何一項,另外一項都會進行緩慢。我建議,若是為了研究,發論文,研究演算法為主,編程次之,主要因為目前SLAM所需要的演算法多數都是開源的,只要知道怎麼去用就可以了,在找一個對應的突破口進行相應的研究,改進演算法,或者是提出自己的相應的演算法,可以使用matlab,python演算法庫等開源演算法庫,這樣是最快的,普通級別的論文非常好發~。若是為了做工程則是另外一套方法了,首先明確一點,工程和研究是不一樣的, 使用在現實場景遠遠比研究場景複雜,你的上司也會對你不斷的催促,因為論文出來了,源碼給了,實際卻是用不了?這個時候就該好好學習編程了,因為你不僅要去實現他原有的代碼(你自己的,了解思路,注意:實現和改是不一樣的), 然後會發現不同平台之間的差異性會給你造成大量的困難,這個時候就需要變成能力和編程經驗了,所以這個階段應該主要抓住編程能力,演算法次之。SLAM是個非常好的平台,建議使用編程語言是C++,也有好多人使用python,也挺好的,但是對於自身成長而言pyhton會減少很多細節的地方,所以強烈推薦C++。
上面高博已經說的很好了,但我還是想結合自己的一些學習聊聊這個話題:
首先放出觀點如下:
1.能用C++就用C++,別用其他語言
2.不要太糾結於語言細節,先用一本書能了解語言大體框架,之後再慢慢學習熟悉語言。
3.熟悉Ubuntu系統,不要用windows
4.多看開源代碼!多看開源代碼!多看開源代碼!
===============================迷之分割線==================================
做下自我介紹:研一某郵小碩,去年10月份差不多進入實驗室開始接觸SLAM演算法。由於實驗室以前沒有這塊方向,所以全是自己和實驗室另一個哥們摸索中學習,所以走了很多彎路,下面我將分別結合說說給出的上面三條理由。
剛開始接觸SLAM學習的是RGBDSLAM,一個經典的SLAM演算法。在網上下好源碼後,很快可以在電腦上跑出實時點雲圖。當時感覺SLAM不過如此。感覺美好的研究生生活即將展現在眼前。做了幾次實驗,和老闆開過幾次會後,老闆也提出一些意見,就準備開始修改代碼,接觸代碼整個人傻眼了。10個左右的源文件,每個源文件中至少500~600行的代碼。當時就不知道該怎麼辦了。這個時候才想到要好好學習C++。看了網上一些大神的意見:從《C++ Primer》開始看起(特地選的還是英文版)。看的很認真,並且基本上每道課後習題都在認真書寫和對照答案。到去年寒假差不多才看到第7章,開學來又學了幾周發現到第9周後前面幾章的有些知識記的不熟又要回頭再看,更要命的是,很多代碼該看不懂還是看不懂,比方說析構函數,列表構造函數等等都還是不知道什麼意思(知乎貼代碼太費勁了,就不上了)結果項目一拖再拖....。SLAM的學習等於說毫無進展,和別人說我是學SLAM的自己都不好意思。
後來,差不多4月中旬左右,開始調整策略,先找了一本C++簡要學習的書(《21天學通C++》感覺很不錯)。很快,大方向的C++具體知識很快就了解了。最起碼給我一份SLAM源碼,我大致知道每一步的操作是什麼。後面就可以再看到不懂得地方再進入《C++ primer》中尋找答案。同時又看了《CMakeLists實踐》大致知道一個項目框架該怎麼搭建起來,程序該如何運行。
再後面,就是下載ORB_SLAM源碼進行閱讀,本身作者給出了很多源碼解釋,但是表白paopaoSLAM做的中文解釋(在碼雲上可以下載,下載地址就不貼了)使SLAM代碼更好閱讀。
說這麼多,還是那句實踐出真知,只有不斷的用起來才知道自己到底缺什麼。第一次在知乎上答專業問題,可能有的說的很不規範,希望大家指正,輕噴。
如果你並不是在一流名校和著名研究機構,我相信你在搞SLAM的時候會碰到更多的工程問題(調攝像頭驅動雷達驅動運動結構驅動采數據等等)。 考慮到Matlab 臃腫的體積和授權還有移植問題,近幾年多數實驗室都不會用,自然開源項目也都是的C++。 結論,無論選擇哪種架構,研究SLAM對編程能力都有很高的要求,用Matlab要求甚至更高,因為你就得把MRPT ROS里那些matlab里沒有的東西重寫一遍,再開始研究具體演算法。等等,那這樣你是不是paper來不及發要延畢了?
整理了自己學習SLAM時用到的開發資源與方法發布在Github上:GeekLiB/Lee-SLAM-source
我覺得MATLAB前期了解演算法很重要,比如理解各種簡單的matrix運算,還有能看到圖片上面match的feature和最後生成的pointcloud,camera pose都能很容易畫出來,剛開始了解SLAM的各種基礎演算法很有幫助。
但是很多基礎演算法要自己寫,別人寫好給你的很少,Prinston有個中國教師有個education sfm那個package,拿來學習很好用。不過一個完整的pipeline,還是c++的implementation多
用c++的好處就是可以用別人寫的很多演算法,RANSAC,essential matrix,triangulation等等,很多都可以用他們寫好的,我就經常看ORB-SLAM的,feature matching上面很多細節也可以自己調節,feature也可以有很多,SIFT,ORB等,甚至可以用klt tracker(個人實驗,對於video很好用)。
c++對於SLAM來說,我覺得上手很難。我花了好幾個月debug各種程序問題。。。
Opencv:沒有用過的,不熟練的,要看別人寫的程序,否則很多matrix的operation搞不清楚,我一開始不在乎float和double,結果各種錯,其實我覺得opencv才是最難的地方,如果沒有怎麼用過,看看ORB-SLAM裡面怎麼調用的就可以了。新的opencv有一個sfm的library,建議不要用,它隱藏了很多重要的演算法,裡面的很多細節是要改的,不能無腦用。。。
Coding Structure: 我一開始用c++寫SLAM的時候,不在乎structure,亂寫,結果又複雜又不好debug,想加個程序,或者加個功能及其費勁。然後開始模仿ORB-SLAM的structure,程序就好多了。但是裡面的structure如果沒有自己寫過,出錯的經驗,剛開始看時不懂為什麼要寫這麼複雜的。。。我也是自己寫了3,4個不好的版本才發現ORB-SLAM的structure真的很好。。
visualization:這個問題就挺大的,我很多時候debug就要寫很複雜的visualization的程序,因為看不到3D的點,matrix的內容,match的準確性,所以debug的時候visualization很重要但是c++裡面很難寫,你可以抄ORB-SLAM裡面的pangolin或者直接用PCL。但是總是沒有matlab方便的。。
搞研究的話,用啥都無所謂,看你的時間和具體要證實的東西。
c++能提供完整的pipeline,而且非常詳細,不過細節過於繁瑣。
matlab的visualization很好,但是整體的pipeline要自己寫。
建議 C++.
另外推薦本周關於slam的免費線上講座,北大博士俞毓鋒為你分享 SLAM及在機器人領域中的應用~
線上分享|SLAM及在機器人領域中的應用
https://zhuanlan.zhihu.com/p/23659397
TLDR; 用c++,別用matlab。從整體方案入手。
具體來說, 這世界上沒有一個loop closure的演算法可以獨立於整個slam解決方案單獨存在的。loop closure的設計取決於整體slam的設計,基於feature還是direct,基於keyframe還是基於連續幀,是否基於graph,graph是否分層,map point是否做了索引,是否用了BOW還是直接用descriptor。還有其他茫茫多的細節。
建議選定一個解決方案,比如ORB SLAM2,在它上面只優化loop closure。
matlab和c++的問題,想都不要想,用c++。走出學校以後沒有哪家公司用matlab的。而且SLAM這麼複雜的系統,看matlab代碼要遠遠難於看c++。
退一萬步講,學c++是一輩子受益的事情,找工作,科研。而且學校里寫的c++演算法代碼可以終身跟著你走,成為你寶貴的財富。
推薦閱讀:
※學習SLAM需要哪些預備知識?
※螞蟻如何找到最短的回窩路徑?
TAG:機器人 | 同時定位和地圖構建SLAM |