最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

總結(jié)!一文詳解lio-livox中的特征提取

2023-09-12 11:09 作者:3D視覺工坊  | 我要投稿

lio-livox是livox官方在2021年開源的一款Lidar+IMU算法,可以用于livox mid360, horizon, HAP等不同型號(hào)的激光雷達(dá)運(yùn)行LIO算法。然而,筆者并沒有在網(wǎng)上找到詳細(xì)的原理說明文檔,因此嘗試通過代碼分析算法原理。本文首先介紹特征提取的部分,由于能力有限,難免解讀出現(xiàn)錯(cuò)誤,請(qǐng)讀者即使批評(píng)指正。

作者:小L | 來源:3DCV

在公眾號(hào)「3DCV」后臺(tái),回復(fù)「原論文」即可獲取論文pdf和代碼。

添加微信:dddvisiona,備注:SLAM,拉你入群。文末附行業(yè)細(xì)分群。

開源代碼:https://github.com/livox-SDK/LIO-Livox

1. 程序整體運(yùn)行

首先放上正常運(yùn)行時(shí)的rqt_graph,可以看出,lio-livox主要有兩個(gè)節(jié)點(diǎn):ScanRegistrationPoseEstimation。顯然,第一個(gè)時(shí)特征提取部分,后面的是位姿軌跡部分。但有趣的是,前者發(fā)布了完整點(diǎn)云livox_full_cloud、不那么sharp和flat的點(diǎn)云、以及非特征點(diǎn),但并沒有被后面節(jié)點(diǎn)接收。所以說,這個(gè)livox_full_cloud 就包含了特征點(diǎn)的信息。

2. 參數(shù)配置

ScanRegistration.cpp中的main函數(shù)中,主要載入了相關(guān)的配置文件,和收發(fā)數(shù)據(jù)的節(jié)點(diǎn)。因此,首先了解下配置文件中有哪些基本配置。

首先在運(yùn)行代碼時(shí),會(huì)運(yùn)行:

roslaunch?lio-livox?mid.launch

所以查看這個(gè)launch文件,文件截圖如下:

首先載入了mid360的配置文件,"mid360_config.yaml",然后設(shè)置了msg_type為0,和其他參數(shù)。msg_type為激光雷達(dá)發(fā)出的數(shù)據(jù)格式,有l(wèi)ivox自定義數(shù)據(jù)類型格式CustomMsg和ros標(biāo)準(zhǔn)的PointCloud2格式,因此首先需要確定激光雷達(dá)端配置的是哪種格式。可以從激光雷達(dá)的ros驅(qū)動(dòng)中看到驅(qū)動(dòng)端有三種格式可以選,驅(qū)動(dòng)端的數(shù)字2對(duì)應(yīng)lio-livox中的1,驅(qū)動(dòng)端的0對(duì)應(yīng)lio-livox的格式0。

接著在"mid360_config.yaml"文件中定義了一些配置,如下:

其中,

  • lidar_type表示采用horizon還是mid360激光雷達(dá)。查了一下horizon的雷達(dá)掃描,雖然是固態(tài)的激光雷達(dá),但是掃描是水平的,因此我推測(cè)應(yīng)該和mid360這種水平掃描的數(shù)據(jù)在特征提取這些方法上是類似的,因此這一個(gè)配置文件可以同時(shí)支持horizon和mid360兩種型號(hào)。

  • Used_Line為采用的線束,mid360數(shù)據(jù)格式具有l(wèi)ine字段,可以輸出以下這個(gè)值是0~3,因此推測(cè)mid360的線束就是4,因此這里采用4條線進(jìn)行處理。

  • Feature_Mode的參數(shù)值可選0或1,但代碼中并沒有用到這個(gè)變量,我推測(cè)可能是之前或之后版本想實(shí)現(xiàn)基于特征的配準(zhǔn)或直接不用特征的配準(zhǔn)吧。

  • Use_Seg是是否啟用動(dòng)態(tài)物體分割,如果啟用,則特征提取前先經(jīng)過動(dòng)態(tài)物體濾波。

再往后的一些參數(shù)從名字可以看出含義,不多做解釋。

if?(Lidar_Type?==?0)??{????customCloud?=?nodeHandler.subscribe<livox_ros_driver::CustomMsg>("/livox/lidar",?100,?&lidarCallBackHorizon);??}??else?if?(Lidar_Type?==?1)??{????customCloud?=?nodeHandler.subscribe<livox_ros_driver::CustomMsg>("/livox/lidar",?100,?&lidarCallBackHAP);??}??else?if(Lidar_Type==2){??????if?(msg_type==0)??????????customCloud?=?nodeHandler.subscribe<livox_ros_driver::CustomMsg>("/livox/lidar",?100,?&lidarCallBackHorizon);??????else?if(msg_type==1)??????????pc2Cloud=nodeHandler.subscribe<sensor_msgs::PointCloud2>("/livox/lidar",?100,?&lidarCallBackPc2);??}

在接下來的main函數(shù)中,可以看出,如果選用的是mid360,采用的默認(rèn)livox的數(shù)據(jù)格式,則進(jìn)入的是Horizon回調(diào)函數(shù)進(jìn)行數(shù)據(jù)處理lidarCallBackHorizon

3. 特征提取

下面正式進(jìn)入特征提取。不展開介紹動(dòng)態(tài)物體分割部分的代碼,直接看特征提取??梢钥吹?,在Horizon回調(diào)中,最核心的函數(shù)就是FeatureExtract。特征提取后,得到帶有特征標(biāo)記的完整點(diǎn)云,和角點(diǎn)、平面點(diǎn)點(diǎn)云(但這兩個(gè)沒有用到)。

回調(diào)函數(shù)為lidarCallBackHorizon,如果不需要濾除動(dòng)態(tài)物體,則調(diào)用FeatureExtract,否則調(diào)用FeatureExtract_with_segment

void?lidarCallBackHorizon(const?livox_ros_driver::CustomMsgConstPtr?&msg)?{??sensor_msgs::PointCloud2?msg2;??if(Use_seg){????lidarFeatureExtractor->FeatureExtract_with_segment(msg,?laserCloud,?laserConerCloud,?laserSurfCloud,?laserNonFeatureCloud,?msg2,N_SCANS);??}??else{????lidarFeatureExtractor->FeatureExtract(msg,?laserCloud,?laserConerCloud,?laserSurfCloud,N_SCANS,Lidar_Type);??}???//?省略后續(xù)格式轉(zhuǎn)化}

FeatureExtract函數(shù)在LidarFeatureExtractor.cpp中,代碼核心部分如下:

void?LidarFeatureExtractor::FeatureExtract(){??//?省略一些預(yù)處理?...??//?多線程特征提取??std::thread?threads[N_SCANS];??for(int?i=0;?i<N_SCANS;?++i){????threads[i]?=?std::thread(&LidarFeatureExtractor::detectFeaturePoint,?this,?std::ref(vlines[i]),?std::ref(vcorner[i]),?std::ref(vsurf[i]));??}??for(int?i=0;?i<N_SCANS;?++i){????//?線程合并????threads[i].join();??}??for(int?i=0;?i<N_SCANS;?++i){????for(int?j=0;?j<vcorner[i].size();?++j){??????laserCloud->points[_float_as_int(vlines[i]->points[vcorner[i][j]].normal_z)].normal_z?=?1.0;????}????for(int?j=0;?j<vsurf[i].size();?++j){??????laserCloud->points[_float_as_int(vlines[i]->points[vsurf[i][j]].normal_z)].normal_z?=?2.0;????}??}??//~?省略后續(xù)處理}

可以看出,對(duì)于每條掃描的線束,開了N_SCANS個(gè)線程(這里是4)分別提取每線束的特征,然后再做合并。每條線束的特征提取函數(shù)為detectFeaturePoint,輸入為這條線束的點(diǎn),輸出為corner點(diǎn)和surf點(diǎn)。比較有趣的是后面幾行,lio-livox代碼中點(diǎn)采用PointXYZINormal格式,法向量normal的z值為特征的類型:1為角點(diǎn)特征,2為平面特征,3為非特征點(diǎn)(mid360的代碼運(yùn)行時(shí)沒有用到非特征點(diǎn))。

具體地,下面這一行的含義為:對(duì)于第i條線束,將被判定為corner點(diǎn)的所有的點(diǎn)的法向量的z值設(shè)定為1。其中,vlines[i]的每個(gè)點(diǎn)的normal_z為這個(gè)點(diǎn)再laserCloud->points中的索引值,vcorner[i][j]為第i線束的第j個(gè)角點(diǎn)的索引。不得不說一下這一行代碼為了省變量,信息量是真的大。

laserCloud->points[_float_as_int(vlines[i]->points[vcorner[i][j]].normal_z)].normal_z?=?1.0;

接下來進(jìn)入detectFeaturePoint函數(shù)看具體如何尋找的corner和surf兩種點(diǎn)。在這個(gè)函數(shù)中,首先提取了三類點(diǎn):平面點(diǎn)(surf/flat),兩平面相交的線(line feature),和break point。

一般我們比較熟悉平面點(diǎn)和角點(diǎn),對(duì)這個(gè)break point不太了解。我個(gè)人認(rèn)為,代碼對(duì)角點(diǎn)中進(jìn)一步細(xì)分為了line feature和break point,前者的基本判定是左右的一些點(diǎn)構(gòu)成有一定夾角的兩個(gè)平面,后者判定為左右的點(diǎn)是"斷開的",物理空間上沒有連接,所以需要引入一些距離的判定。

每種點(diǎn)提取的時(shí)候,先初步提取,再做篩選。通過CloudFeatureFlag這個(gè)變量的數(shù)值表示這些點(diǎn)分別是什么類型。

展開介紹CloudFeatureFlag的一些值:

  • 0,這個(gè)點(diǎn)暫不是任何特征類型,需要執(zhí)行相應(yīng)計(jì)算與判斷。

  • 1,平面點(diǎn)附近的點(diǎn)被標(biāo)記為1,不作為任何特征,只是在判斷點(diǎn)是否為0時(shí)用于跳過這個(gè)點(diǎn),加快計(jì)算速度

  • 2,對(duì)初次標(biāo)記為平面點(diǎn)的再一次篩選,滿足一定準(zhǔn)則的設(shè)定為2

  • 3,根據(jù)平面曲率初次提取的平面點(diǎn),嚴(yán)格符合條件的會(huì)被標(biāo)記為3

  • 100:初次提取的break point

  • 101:對(duì)標(biāo)記為100的點(diǎn)做篩選,不符合嚴(yán)格的break point的設(shè)定為101

  • 150:兩個(gè)平面相交線的點(diǎn)

  • 300:基于反射率和距離等判定得到的一些點(diǎn),后續(xù)并沒有用到

具體一些,在平面點(diǎn)提取階段,通過每個(gè)點(diǎn)和前后點(diǎn)的夾角等,CloudFeatureFlag會(huì)賦值1,2,3,300;在相交線特征點(diǎn)提取過程中,會(huì)根據(jù)左右的點(diǎn)是否能構(gòu)成平面,給CloudFeatureFlag賦值150;在break point提取過程中,CloudFeatureFlag會(huì)出現(xiàn)100和101。由于這部分代碼較為冗雜,不展開介紹。理解了這些數(shù)字的基本含義可以去探究具體的判定準(zhǔn)則是什么。

在得到這些用數(shù)值表示的特征后,將標(biāo)記為100和150的點(diǎn)作為角點(diǎn),將標(biāo)記為2的點(diǎn)標(biāo)記為平面點(diǎn)。代碼如下:

if(CloudFeatureFlag[i]?==?2){????pointsLessFlat.push_back(i);????num_surf++;????continue;??}if(CloudFeatureFlag[i]?==?100?||?CloudFeatureFlag[i]?==?150){?//??pointsLessSharp_ori.push_back(i);??laserCloudCorner->push_back(_laserCloud->points[i]);}

至此,完成了特征提取的所有部分的代碼解釋。

提取完角點(diǎn)/平面特征后,要干什么用呢?這就是后續(xù)的配準(zhǔn)和優(yōu)化部分。在Estimator.cpp中,可以看到,對(duì)于角點(diǎn)執(zhí)行的是點(diǎn)-線icp,平面點(diǎn)執(zhí)行的是點(diǎn)-面icp:

threads[0]?=?std::thread(&Estimator::processPointToLine,?this,?????????????????????????std::ref(edgesLine[f]),?????????????????????????std::ref(vLineFeatures[f]),?????????????????????????std::ref(laserCloudCornerStack[f]),?????????????????????????std::ref(laserCloudCornerFromLocal),?????????????????????????std::ref(kdtreeCornerFromLocal),?????????????????????????std::ref(exTlb),?????????????????????????std::ref(transformTobeMapped));threads[1]?=?std::thread(&Estimator::processPointToPlanVec,?this,?????????????????????????std::ref(edgesPlan[f]),?????????????????????????std::ref(vPlanFeatures[f]),?????????????????????????std::ref(laserCloudSurfStack[f]),?????????????????????????std::ref(laserCloudSurfFromLocal),?????????????????????????std::ref(kdtreeSurfFromLocal),?????????????????????????std::ref(exTlb),?????????????????????????std::ref(transformTobeMapped));

后續(xù)內(nèi)容本文暫不做介紹。

總結(jié)!一文詳解lio-livox中的特征提取的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
克山县| 德令哈市| 集贤县| 遂平县| 曲麻莱县| 额敏县| 天气| 建昌县| 同德县| 黄大仙区| 黔西县| 东阿县| 手机| 阳城县| 德清县| 定结县| 金华市| 荔波县| 宽城| 乳山市| 阿坝| 二连浩特市| 陵川县| 乐昌市| 台湾省| 修水县| 彭泽县| 西丰县| 天峨县| 长丰县| 新干县| 泾阳县| 治多县| 印江| 合水县| 梁平县| 冷水江市| 道孚县| 合川市| 门源| 体育|