1. 程式人生 > >從零開始一起學習SLAM | 點雲平滑法線估計

從零開始一起學習SLAM | 點雲平滑法線估計

參考 需要 後臺 不常用 為什麽 分表 覆蓋 了吧 完全

點擊公眾號“計算機視覺life”關註,置頂星標更快接收消息!
本文編程練習框架及數據獲取方法見文末獲取方式
菜單欄點擊“知識星球”查看「從零開始學習SLAM」一起學習交流

點雲濾波後為什麽還需要平滑?

小白:師兄,師兄,上次你說的點雲濾波我學會啦,下一步怎麽把點雲變成網格啊?
師兄:濾波只是第一步,在網格化前我們還需要對濾波後的點雲進行平滑(smoothing)
小白:不是已經濾波了嗎?怎麽還要平滑啊?濾波和平滑不一樣嗎?
師兄:確實不太一樣。我們用RGB-D,激光掃描儀等設備掃描物體,尤其是比較小的物體時,往往會有測量誤差。這些誤差所造成的不規則數據如果直接拿來曲面重建的話,會使得重建的曲面不光滑或者有漏洞,而且這種不規則數據很難用前面我們提到過的統計分析等濾波方法消除,所以為了建立光滑完整的模型必須對物體表面進行平滑處理和漏洞修復。
你看下面左邊就是原始的掃描數據,右邊就是用最小二乘法進行表面平滑後的結果
技術分享圖片

小白:從圖上看,平滑確實效果很明顯啊,左邊杯子上黑色的是噪聲吧,右邊的結果來看經過平滑都消失了
師兄:對,除了上面說到的設備測量誤差外,還有一種情況也需要對點雲進行平滑。就是後處理過程中,比如我們對同一個物體從不同方向進行了多次掃描,然後把掃描結果進行配準,最後得到一個完整的模型,但是你配準的結果不一定準啊,比如下圖中左側就是配準後未經過處理的結果,同一面墻壁由於配準誤差變成了“兩面墻”,並不能完全重疊,你覺得這個數據可以直接用來進行表面重建嗎?
技術分享圖片
小白:好坑啊,肯定不行,這樣重建出的結果也是兩面墻了吧
師兄:對,所以我們需要想辦法把“兩面墻”變成“一面墻”,如果這時候,我們沒有條件重新掃描出更精確的結果,或者配準精度也無法提升,可以通過重采樣的方法來實現點雲的平滑,從而避免出現這樣的問題。
小白:原來這個平滑這麽重要啊!怎麽用重采樣來平滑呢?感覺迫不及待想要學習啦!
師兄:(既然胃口已經被吊起來了)那我們趕快開始切入正題吧

如何通過重采樣實現點雲平滑?

師兄:點雲重采樣,我們實際上是通過一種叫做“移動最小二乘”(MLS, Moving Least Squares )法來實現的,對應的類名叫做:pcl::MovingLeastSquares,你知道怎麽用嗎?
小白:不知道,不過我還記得我們上次師兄給我說的方法,在PCL API documentation http://docs.pointclouds.org/trunk/ 上查詢類名稱,就能看到類的定義和用法啦
師兄:活學活用啊,哈哈,那我們現在去查一下看看吧
小白:嗯,我查到了,這個MLS類的定義在這裏:
http://docs.pointclouds.org/trunk/classpcl_1_1_moving_least_squares.html#a379330b0b1dacaa668d165f94930749c
成員函數好多啊
師兄:對,看著是很多,但是很多我們不常用的,比如我們常用的一個用於重采樣的示例代碼如下,每行代碼都給你註釋好了,結合上面網址看很容易理解

// 對點雲重采樣  
pcl::search::KdTree<PointT>::Ptr treeSampling (new pcl::search::KdTree<PointT>); // 創建用於最近鄰搜索的KD-Tree
pcl::PointCloud<PointT> mls_points;   //輸出MLS
pcl::MovingLeastSquares<PointT, PointT> mls;  // 定義最小二乘實現的對象mls
mls.setComputeNormals (false);  //設置在最小二乘計算中是否需要存儲計算的法線
mls.setInputCloud (cloud_filtered);     //設置待處理點雲
mls.setPolynomialOrder(2);          // 擬合2階多項式擬合
mls.setPolynomialFit (false);  // 設置為false可以 加速 smooth
mls.setSearchMethod (treeSampling); // 設置KD-Tree作為搜索方法
mls.setSearchRadius (0.05); // 單位m.設置用於擬合的K近鄰半徑
mls.process (mls_points);       //輸出

小白:師兄,這個代碼裏的KD-Tree是幹嘛的?
師兄:Kd-Tree是一種數據結構,是空間二分樹的一種特殊情況,可以很方便的用於進行範圍搜索。在這裏用KD-Tree就是為了便於管理、搜索點雲,這種結構來可以很方便的找到最近鄰點。
小白:原來如此,那上面mls.setSearchRadius (0.05) 的意思是不是就是搜索當前點以5cm為半徑的空間中所有的點?
師兄:對的,然後把這些點用2階多項式擬合~
技術分享圖片
小白:所以表面就變平滑啦!

如何估計點雲的表面法線?

小白:師兄,現在可以網格化了嗎?
師兄:還不行。。。別急,網格化前我們還需要估計一下點雲的表面法線(normal)
小白:啊,怎麽又冒出來一個法線。。。
師兄:法線好像是中學就學過了,應該還記得平面的法線的定義吧,平面的法線是垂直於該平面的向量,如下圖所示
技術分享圖片

你看上面右邊那個圖,對於曲面來說,曲面在某點P處的法線為垂直於該點切平面(tangent plane)的向量
小白:記得呢,不過這個法線有什麽用?怎麽就突然冒出來了
師兄:法線很有用的,尤其是在三維建模中應用非常廣泛,比如在計算機圖形學(computer graphics)領域裏,法線決定著曲面與光源(light source)的強弱處理(Flat Shading),對於每個點光源位置,其亮度取決於曲面法線的方向。
小白:原來如此。不過好像平面或曲面的法線比較容易計算,方程 ax + by + cz = d 表示的平面,向量(a, b, c)
就是其法線。而我們這裏是點雲呢!怎麽算呢?
師兄:確實如此。點雲的法線計算是稍微麻煩點,一般有兩種方法:
1、使用曲面重建方法,從點雲數據中得到采樣點對應的曲面,然後再用曲面模型計算其表面的法線
2、直接使用近似值直接從點雲數據集推斷出曲面法線
這裏主要用第2種方法來近似估計點雲中每個點的表面法線。
具體來說,就是把估計某個點的表面法線問題簡化為:從該點最近鄰計算的協方差矩陣的特征向量和特征值的分析,這裏就不多做介紹了。PCL已經幫我們封裝好了函數啦
我們計算出來點雲的法線大概是這樣的
技術分享圖片
小白:那個箭頭就代表法線吧?
師兄:對的,我們前面提到了,需要從該點的周圍點鄰域(也稱為k鄰域)估計一點處的表面法線 ,所以這個K鄰域的選取也很關鍵
小白:這個K鄰域選取會有什麽影響嗎?
師兄:有的,而且影響挺大的,K近鄰的取值可以通過選擇k個最近點,或者確定一個以r為半徑的圓內的點集來確定,你看下面這個圖是對同一個點雲用不同尺度因子(k和r)進行法線估計的結果。左邊部分表示比例因子選擇的比較合適,估計的表面法線近似垂直於這兩個平面,即使在互相垂直的邊緣部分,也能明顯看到邊沿。而右邊的尺度因子就選的有點大了,這樣臨近點集更大範圍的覆蓋臨近表面的點,兩個平面邊沿處估計的法線就不準了,不能表達真實的情況。
技術分享圖片

小白:確實是這樣啊,看來編程的時候要格外註意了。
師兄:法線估計的示例如下,我也給你註釋好啦

// 法線估計
pcl::NormalEstimation<PointT, pcl::Normal> normalEstimation;                    //創建法線估計的對象
normalEstimation.setInputCloud(cloud_smoothed);                                 //輸入點雲
pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>);         // 創建用於最近鄰搜索的KD-Tree
normalEstimation.setSearchMethod(tree);
pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>);   // 定義輸出的點雲法線
// K近鄰確定方法,使用k個最近點,或者確定一個以r為半徑的圓內的點集來確定都可以,兩者選1即可
normalEstimation.setKSearch(10);                    // 使用當前點周圍最近的10個點
//normalEstimation.setRadiusSearch(0.03);           //對於每一個點都用半徑為3cm的近鄰搜索方式
normalEstimation.compute(*normals);                 //計算法線

本文參考:PCL官網

編程練習

前面我們已經介紹過點雲濾波,這次練習主要是後續的平滑和法線估計,為後面網格化做鋪墊。
題目:給定一個融合後的點雲,已經對其進行下采樣和濾波(代碼已給)。請對其進行平滑(輸出結果),然後計算法線,並講法線顯示在平滑後的點雲上。
代碼框架及待處理數據已經 為你準備好了,公眾號「計算機視覺life」後臺回復:平滑,即可獲得。
如果一切順利,你將得到如下結果。你可以通過調整法線的稠密,放大查看法線計算的是否符合預期。
技術分享圖片

歡迎留言討論,更多學習視頻、文檔資料、參考答案等關註計算機視覺life公眾號,,菜單欄點擊“知識星球”查看「從零開始學習SLAM」星球介紹,快來和其他小夥伴一起學習交流~

推薦閱讀

從零開始一起學習SLAM | 為什麽要學SLAM?
從零開始一起學習SLAM | 學習SLAM到底需要學什麽?
從零開始一起學習SLAM | SLAM有什麽用?
從零開始一起學習SLAM | C++新特性要不要學?
從零開始一起學習SLAM | 為什麽要用齊次坐標?
從零開始一起學習SLAM | 三維空間剛體的旋轉
從零開始一起學習SLAM | 為啥需要李群與李代數?
從零開始一起學習SLAM | 相機成像模型
從零開始一起學習SLAM | 不推公式,如何真正理解對極約束?
從零開始一起學習SLAM | 神奇的單應矩陣
從零開始一起學習SLAM | 你好,點雲
從零開始一起學習SLAM | 給點雲加個濾網
零基礎小白,如何入門計算機視覺?

從零開始一起學習SLAM | 點雲平滑法線估計