<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          研究SLAM,對編程的要求有多高?

          共 9499字,需瀏覽 19分鐘

           ·

          2021-09-18 02:17

          來源 | 小白學(xué)視覺
          研究SLAM的同學(xué)平時(shí)除了要看很多頭疼的公式原理外,對編程也是有不少要求的。在學(xué)生階段,很多同學(xué)都是用MATLAB作為主要編程語言,容易上手又簡單。但是去看SLAM的開源代碼,發(fā)現(xiàn)基本清一色都是C++,而且有不少開源代碼使用C++到了出神入化的地步了。那么問題來了,學(xué)習(xí)SLAM是否可以不拘泥于編程語言的選擇?到底對編程的要求有多高?

          本文來自知乎上的同名問題,已經(jīng)征得了部分答主的授權(quán),對幾個(gè)優(yōu)秀回答進(jìn)行了整理,如下

          高翔

          關(guān)于MATLAB

          題主說MATLAB,主要原因是大多數(shù)人本科階段接觸的都是MATLAB,所以希望之后研究SLAM也用它。

          MATLAB確實(shí)有很多優(yōu)點(diǎn):語法簡單,開發(fā)速度快,調(diào)試方便,功能豐富。然而,在SLAM領(lǐng)域,MATLAB缺點(diǎn)也很明顯,主要是這兩個(gè):

          • 需要正版軟件(你不能實(shí)機(jī)上也裝個(gè)盜版MATLAB吧);

          • 運(yùn)行效率不高;

          • 需要一個(gè)巨大的安裝包;

          而相對的,C++的優(yōu)勢在于直接使用,有很高的運(yùn)行效率,不過開發(fā)速度和調(diào)試方面慢于MATLAB。不過光運(yùn)行效率這一條,就夠許多SLAM方案選擇C++作為開發(fā)語言了,因?yàn)檫\(yùn)行效率真的很重要。同一個(gè)算法,拿MATLAB寫出來實(shí)現(xiàn)不能實(shí)時(shí),拿C++寫的能實(shí)時(shí),你說用哪個(gè)?

          當(dāng)然MATLAB也有一些用武之地。我見過一些SLAM相關(guān)的公開課程,讓學(xué)生用MATLAB做仿真,交作業(yè),這沒有問題,比如SLAM toolbox 。同樣的,比較類似于MATLAB的Python(以及octave)亦常被用于此道。它們在開發(fā)上的快捷帶來了很多便利,當(dāng)你想要驗(yàn)證一些數(shù)學(xué)理論、思想時(shí),這些都是不錯的工具。所謂技多不壓身,題主掌握MATLAB和Python當(dāng)然是很棒的。

          但是一牽涉到實(shí)用,你會發(fā)現(xiàn)幾乎所有的方案都在用C++。因?yàn)檫\(yùn)行效率實(shí)在是太重要了。

          那既然有心思學(xué)MATLAB,為什么不學(xué)好C++呢?

          C++需要掌握到什么程度?

          接下來說說C++大概要學(xué)到什么程度。用程序員的話說,C++語言比較特殊,你可以說自己精通了Java,但千萬不要說自己精通了C++。C++非常之博大精深,有數(shù)不清的特性,而且隨著時(shí)間還會不斷變化更新。不過,大多數(shù)人都用不著學(xué)會所有的C++特性,因?yàn)樵S多東西一輩子都用不到。

          作為SLAM研究人員,我們面對的主要是算法層面的開發(fā),所以更關(guān)心如何有效地實(shí)現(xiàn)各種相關(guān)的算法。而相對的,那些復(fù)雜的軟件架構(gòu),設(shè)計(jì)模式,我個(gè)人認(rèn)為在SLAM中倒是占次要地位的。畢竟您用SLAM的目的是計(jì)算一個(gè)位置以及建個(gè)地圖,并不是要去寫一套能夠自動更新的、多人網(wǎng)上對戰(zhàn)功能的機(jī)器人大戰(zhàn)平臺。您的主要精力可能會花在矩陣運(yùn)算、分塊、非線性優(yōu)化的實(shí)現(xiàn)、圖像處理上面;您可能對并發(fā)、指令集加速、GPU加速等話題感興趣,也可以花點(diǎn)時(shí)間學(xué)習(xí);你還可能想用模板來拓展你的算法,也不妨一試。相應(yīng)的,很多功能性的東西,比如說UI、網(wǎng)絡(luò)通信等等,當(dāng)你用到的時(shí)候不妨接觸一下,但專注于SLAM上時(shí)就不必專門去學(xué)習(xí)了。

          話雖如此,SLAM所需的C++水平,大抵要高于你在書本上看到的那些個(gè)示例代碼。因?yàn)槟切┐a是作者用來向初學(xué)者介紹語法的,所以會盡量簡單。而實(shí)際見到的代碼往往結(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++也不過如此,并沒有啥特別難以理解的地方。然而實(shí)際代碼大概是這樣的:

          嵌套的模板類(來自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的自動求導(dǎo)):

          virtual bool Evaluate(double constconst* 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); });
          }

          謎之運(yùn)算(來自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;
          }

          我不知道你們看到這些代碼是什么心情,總之我當(dāng)時(shí)內(nèi)心的感受是:臥槽這怎么和教科書里的完全不一樣??!而且研究了半天發(fā)現(xiàn)人家居然是對的??!

          [我不是很擅長貼表情圖總之你們腦補(bǔ)一下就好]

          總而言之,對C++的水平要求應(yīng)該是在教科書之上的。而且這個(gè)水平的提高,多數(shù)時(shí)候建立在你不斷地看別人代碼、碼自己代碼的過程之上。它是反復(fù)練習(xí)出來的,并不是僅僅通過看書就能領(lǐng)會的。特別是對于視覺SLAM問題,很多時(shí)候你沒法照著論文把一套方案實(shí)現(xiàn)出來,這很大程度上取決于你的理論和代碼功底。

          所以,請盡早開始學(xué)習(xí)C++,盡早開始使用C++,才是研究SLAM的正確之道。不要長期彷徨在自己的舒適區(qū)里猶豫不決,這樣是沒有進(jìn)步的。(同樣的道理亦適用于想研究SLAM但不愿意學(xué)習(xí)Linux的朋友們)

          Kache

          我覺得對編程要求還是挺高的,先從后端說起吧
          g2o, gtsam,ceres知道是肯定需要知道的,三者其實(shí)學(xué)習(xí)曲線都挺難的,你覺得你會用了是一回事,然后用好是一回事,自己寫vertex, edge, factor, cost function又是另外一回事,如果你會寫g2o里面的solver應(yīng)該又是一個(gè)級別了吧。但是這三個(gè)在網(wǎng)上的資源而論g2o > ceres > gtsam。再者,你會調(diào)用api就代表你懂優(yōu)化了嗎,自己動手matlab寫一下gauss-newton應(yīng)該也可以試一試吧。當(dāng)然,遠(yuǎn)古一點(diǎn)了levmar也很不錯哦。直到這里,你確定你明白各種算法底層suitesparse里面的效率問題嗎,如果挖掘到了這一層,還有各種線性代數(shù)庫的比較哦,肯定是又快有慢。所以說,想要學(xué)會一到兩個(gè)優(yōu)化器不難,學(xué)會自定義有一點(diǎn)難,考慮到后端的效率自己寫solver更難,深入到線性代數(shù)庫的最底層,考慮問題結(jié)構(gòu),提升效率就更難了

          前端,其實(shí)僅僅考慮點(diǎn)特征,也就那么多東西,V-SLAM用OPENCV也就夠用了,而且opencv我覺得到API調(diào)用那一層也就足夠了。如果考慮上RGBD,再加上一個(gè)PCL。理論知識方面基本的Multiview geometry其實(shí)也就足夠了。但是前端的問題在于很多都是經(jīng)驗(yàn)的東西,參數(shù)的選擇,循環(huán)的次數(shù)等等。說白了我個(gè)人覺得視覺部分調(diào)參的問題更多,理論倒是不容易出問題。

          前后段一起的話,什么線程管理就不用說了,該用的庫都得上,例如boost啥的。有時(shí)候做visualization可能還需要一些別的庫。

          說完好像要求也就那樣,反正我又不是CS出身活得還好好的

          邵天蘭

          要搞SLAM,編程能力非常非常重要。編程能力就像運(yùn)動員的力量和體能,是一切技巧和戰(zhàn)術(shù)的基礎(chǔ)。雖然研究的是算法,但良好的編程能力能夠使你節(jié)省大量的時(shí)間,并且達(dá)到更好的效果。

          根據(jù)我的經(jīng)驗(yàn),算法搞得特別好的人很少有編程不行的,因?yàn)榫幊毯每梢允鼓隳軌蜓杆衮?yàn)證想法。見過不少學(xué)生因?yàn)榫幊袒A(chǔ)不好,在實(shí)現(xiàn)和debug上浪費(fèi)大把大把的時(shí)間。這樣的人當(dāng)然很難把算法搞好。

          這里編程能力有很多方面,以下簡單說幾個(gè)。贊多了再補(bǔ)( ̄▽ ̄)/

          1. 閱讀代碼的能力
          未說寫,先說讀。搞科研和搞工程都大忌閉門造車,除了paper外,開源代碼是最有效的學(xué)習(xí)途徑。一般而言,paper中只是著重描述比較創(chuàng)新的部分,80%以上的實(shí)現(xiàn)細(xì)節(jié)(甚至很多很關(guān)鍵的東西)需要從代碼中了解。編程不好的人,往往也不太會讀代碼。

          2. 架構(gòu)軟件,管理復(fù)雜項(xiàng)目的能力
          一個(gè)SLAM方案通常由很多模塊組成。我見過不少實(shí)驗(yàn)室的內(nèi)部代碼,一鍋粥,學(xué)生們各種胡亂修補(bǔ)。這樣必然導(dǎo)致效率低下。如果能做到模塊化、低耦合,可以使開發(fā)事半功倍。

          3. 高效實(shí)現(xiàn)的能力
          過去八年間,我最少的一年也碼了兩萬多行。。。根據(jù)我的體會,同樣的算法,好的實(shí)現(xiàn)可以比不好的實(shí)現(xiàn)快2-10倍。復(fù)雜度越高越如是,例如3D  SLAM。要擁有高效實(shí)現(xiàn)的能力,必須熟悉常用的數(shù)據(jù)結(jié)構(gòu),對復(fù)雜度分析形成很好的直覺。

          4. 管理多線程、異步程序的能力
          SLAM往往涉及到多線程和異步程序,例如用于后端優(yōu)化等。玩兒不轉(zhuǎn)這個(gè)就會出現(xiàn)程序不穩(wěn)定,或效率低。

          Matlab不能滿足需要。Matlab對數(shù)據(jù)結(jié)構(gòu)的支持太差,而且速度慢。即使不考慮產(chǎn)品,只是做算法,也很不適合。自己做算法驗(yàn)證基本上就是C++或python,如果你因?yàn)椴皇煜み@些而選其他語言,會因?yàn)閰⒖忌?、輪子少的原因效率很低。?qiáng)烈建議題主學(xué)習(xí)C++。

          —版權(quán)聲明—

          僅用于學(xué)術(shù)分享,版權(quán)屬于原作者。

          若有侵權(quán),請聯(lián)系微信號:yiyang-sy 刪除或修改!


          —THE END—
          瀏覽 37
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  夜噜噜在线 | 婷中文字幕9 | 三级片网站av | 日本有码第1页 | 国产精品熟妇一区二区三区四区 |