研究SLAM,對編程的要求有多高?
點擊上方“小白學視覺”,選擇加"星標"或“置頂”
重磅干貨,第一時間送達
本文來自知乎上的同名問題,已經(jīng)征得了部分答主的授權(quán),對幾個優(yōu)秀回答進行了整理,如下
題主說MATLAB,主要原因是大多數(shù)人本科階段接觸的都是MATLAB,所以希望之后研究SLAM也用它。
MATLAB確實有很多優(yōu)點:語法簡單,開發(fā)速度快,調(diào)試方便,功能豐富。然而,在SLAM領(lǐng)域,MATLAB缺點也很明顯,主要是這兩個:
需要正版軟件(你不能實機上也裝個盜版MATLAB吧);
運行效率不高;
需要一個巨大的安裝包;
而相對的,C++的優(yōu)勢在于直接使用,有很高的運行效率,不過開發(fā)速度和調(diào)試方面慢于MATLAB。不過光運行效率這一條,就夠許多SLAM方案選擇C++作為開發(fā)語言了,因為運行效率真的很重要。同一個算法,拿MATLAB寫出來實現(xiàn)不能實時,拿C++寫的能實時,你說用哪個?
當然MATLAB也有一些用武之地。我見過一些SLAM相關(guān)的公開課程,讓學生用MATLAB做仿真,交作業(yè),這沒有問題,比如SLAM toolbox 。同樣的,比較類似于MATLAB的Python(以及octave)亦常被用于此道。它們在開發(fā)上的快捷帶來了很多便利,當你想要驗證一些數(shù)學理論、思想時,這些都是不錯的工具。所謂技多不壓身,題主掌握MATLAB和Python當然是很棒的。
但是一牽涉到實用,你會發(fā)現(xiàn)幾乎所有的方案都在用C++。因為運行效率實在是太重要了。
那既然有心思學MATLAB,為什么不學好C++呢?
接下來說說C++大概要學到什么程度。用程序員的話說,C++語言比較特殊,你可以說自己精通了Java,但千萬不要說自己精通了C++。C++非常之博大精深,有數(shù)不清的特性,而且隨著時間還會不斷變化更新。不過,大多數(shù)人都用不著學會所有的C++特性,因為許多東西一輩子都用不到。
作為SLAM研究人員,我們面對的主要是算法層面的開發(fā),所以更關(guān)心如何有效地實現(xiàn)各種相關(guān)的算法。而相對的,那些復雜的軟件架構(gòu),設(shè)計模式,我個人認為在SLAM中倒是占次要地位的。畢竟您用SLAM的目的是計算一個位置以及建個地圖,并不是要去寫一套能夠自動更新的、多人網(wǎng)上對戰(zhàn)功能的機器人大戰(zhàn)平臺。您的主要精力可能會花在矩陣運算、分塊、非線性優(yōu)化的實現(xiàn)、圖像處理上面;您可能對并發(fā)、指令集加速、GPU加速等話題感興趣,也可以花點時間學習;你還可能想用模板來拓展你的算法,也不妨一試。相應的,很多功能性的東西,比如說UI、網(wǎng)絡(luò)通信等等,當你用到的時候不妨接觸一下,但專注于SLAM上時就不必專門去學習了。
話雖如此,SLAM所需的C++水平,大抵要高于你在書本上看到的那些個示例代碼。因為那些代碼是作者用來向初學者介紹語法的,所以會盡量簡單。而實際見到的代碼往往結(jié)合了各種奇特的技巧,乍看起來會顯得高深莫測。比方說你在教科書里看的大概是這樣:
int main ( int argc, char** argv )
{
vector<string> vec;
vec.push_back("abc");
for ( int i=0; i<vec.size(); i++ )
{
// ...
}
return 0;
}
你看了C++ Primer Plus,覺得C++也不過如此,并沒有啥特別難以理解的地方。然而實際代碼大概是這樣的:
嵌套的模板類(來自g2o的塊求解器):
g2o::BlockSolver< g2o::BlockSolverTraits<3,1> >::LinearSolverType* linearSolver = new g2o::LinearSolverDense<g2o::BlockSolver< g2o::BlockSolverTraits<3,1> >::PoseMatrixType>();
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 );
模板元(來自ceres的自動求導):
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<CostFunctor, double,
N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>::Differentiate(
*functor_,
parameters,
SizedCostFunction<kNumResiduals,
N0, N1, N2, N3, N4,
N5, N6, N7, N8, N9>::num_residuals(),
residuals,
jacobians);
}
C11新特性(來自SVO特征提取部分)
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;
std::for_each(fts_.begin(), fts_.end(), [&](Feature* ftr){ if(ftr->point != NULL) checkKeyPoints(ftr); });
}
謎之運算(來自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> nd(seed->mu, norm_scale);
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;
}
我不知道你們看到這些代碼是什么心情,總之我當時內(nèi)心的感受是:臥槽這怎么和教科書里的完全不一樣?。《已芯苛税胩彀l(fā)現(xiàn)人家居然是對的?。?/span>
[我不是很擅長貼表情圖總之你們腦補一下就好]
總而言之,對C++的水平要求應該是在教科書之上的。而且這個水平的提高,多數(shù)時候建立在你不斷地看別人代碼、碼自己代碼的過程之上。它是反復練習出來的,并不是僅僅通過看書就能領(lǐng)會的。特別是對于視覺SLAM問題,很多時候你沒法照著論文把一套方案實現(xiàn)出來,這很大程度上取決于你的理論和代碼功底。
所以,請盡早開始學習C++,盡早開始使用C++,才是研究SLAM的正確之道。不要長期彷徨在自己的舒適區(qū)里猶豫不決,這樣是沒有進步的。(同樣的道理亦適用于想研究SLAM但不愿意學習Linux的朋友們)
我覺得對編程要求還是挺高的,先從后端說起吧
g2o, gtsam,ceres知道是肯定需要知道的,三者其實學習曲線都挺難的,你覺得你會用了是一回事,然后用好是一回事,自己寫vertex, edge, factor, cost function又是另外一回事,如果你會寫g2o里面的solver應該又是一個級別了吧。但是這三個在網(wǎng)上的資源而論g2o > ceres > gtsam。再者,你會調(diào)用api就代表你懂優(yōu)化了嗎,自己動手matlab寫一下gauss-newton應該也可以試一試吧。當然,遠古一點了levmar也很不錯哦。直到這里,你確定你明白各種算法底層suitesparse里面的效率問題嗎,如果挖掘到了這一層,還有各種線性代數(shù)庫的比較哦,肯定是又快有慢。所以說,想要學會一到兩個優(yōu)化器不難,學會自定義有一點難,考慮到后端的效率自己寫solver更難,深入到線性代數(shù)庫的最底層,考慮問題結(jié)構(gòu),提升效率就更難了
前端,其實僅僅考慮點特征,也就那么多東西,V-SLAM用OPENCV也就夠用了,而且opencv我覺得到API調(diào)用那一層也就足夠了。如果考慮上RGBD,再加上一個PCL。理論知識方面基本的Multiview geometry其實也就足夠了。但是前端的問題在于很多都是經(jīng)驗的東西,參數(shù)的選擇,循環(huán)的次數(shù)等等。說白了我個人覺得視覺部分調(diào)參的問題更多,理論倒是不容易出問題。
前后段一起的話,什么線程管理就不用說了,該用的庫都得上,例如boost啥的。有時候做visualization可能還需要一些別的庫。
說完好像要求也就那樣,反正我又不是CS出身活得還好好的
要搞SLAM,編程能力非常非常重要。編程能力就像運動員的力量和體能,是一切技巧和戰(zhàn)術(shù)的基礎(chǔ)。雖然研究的是算法,但良好的編程能力能夠使你節(jié)省大量的時間,并且達到更好的效果。
根據(jù)我的經(jīng)驗,算法搞得特別好的人很少有編程不行的,因為編程好可以使你能夠迅速驗證想法。見過不少學生因為編程基礎(chǔ)不好,在實現(xiàn)和debug上浪費大把大把的時間。這樣的人當然很難把算法搞好。
這里編程能力有很多方面,以下簡單說幾個。贊多了再補( ̄▽ ̄)/
1. 閱讀代碼的能力
未說寫,先說讀。搞科研和搞工程都大忌閉門造車,除了paper外,開源代碼是最有效的學習途徑。一般而言,paper中只是著重描述比較創(chuàng)新的部分,80%以上的實現(xiàn)細節(jié)(甚至很多很關(guān)鍵的東西)需要從代碼中了解。編程不好的人,往往也不太會讀代碼。
2. 架構(gòu)軟件,管理復雜項目的能力
一個SLAM方案通常由很多模塊組成。我見過不少實驗室的內(nèi)部代碼,一鍋粥,學生們各種胡亂修補。這樣必然導致效率低下。如果能做到模塊化、低耦合,可以使開發(fā)事半功倍。
3. 高效實現(xiàn)的能力
過去八年間,我最少的一年也碼了兩萬多行。。。根據(jù)我的體會,同樣的算法,好的實現(xiàn)可以比不好的實現(xiàn)快2-10倍。復雜度越高越如是,例如3D SLAM。要擁有高效實現(xiàn)的能力,必須熟悉常用的數(shù)據(jù)結(jié)構(gòu),對復雜度分析形成很好的直覺。
4. 管理多線程、異步程序的能力
SLAM往往涉及到多線程和異步程序,例如用于后端優(yōu)化等。玩兒不轉(zhuǎn)這個就會出現(xiàn)程序不穩(wěn)定,或效率低。
Matlab不能滿足需要。Matlab對數(shù)據(jù)結(jié)構(gòu)的支持太差,而且速度慢。即使不考慮產(chǎn)品,只是做算法,也很不適合。自己做算法驗證基本上就是C++或python,如果你因為不熟悉這些而選其他語言,會因為參考少、輪子少的原因效率很低。強烈建議題主學習C++。
好消息,小白學視覺團隊的知識星球開通啦,為了感謝大家的支持與厚愛,團隊決定將價值149元的知識星球現(xiàn)時免費加入。各位小伙伴們要抓住機會哦!

交流群
歡迎加入公眾號讀者群一起和同行交流,目前有SLAM、三維視覺、傳感器、自動駕駛、計算攝影、檢測、分割、識別、醫(yī)學影像、GAN、算法競賽等微信群(以后會逐漸細分),請掃描下面微信號加群,備注:”昵稱+學校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺SLAM“。請按照格式備注,否則不予通過。添加成功后會根據(jù)研究方向邀請進入相關(guān)微信群。請勿在群內(nèi)發(fā)送廣告,否則會請出群,謝謝理解~

