0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何將每個框架插入到SLAM框架中

新機器視覺 ? 來源:古月居 ? 2024-04-30 12:55 ? 次閱讀

0. 簡介

LinK3D、CSF、BALM這幾個都是非常方便去插入到激光SLAM框架的。這里我們會分別從多個角度來介紹如何將每個框架插入到SLAM框架中

1. LinK3D:三維LiDAR點云的

線性關(guān)鍵點表示

LinK3D的核心思想和基于我們的LinK3D的兩個LiDAR掃描的匹配結(jié)果。綠色線是有效匹配。當(dāng)前關(guān)鍵點(黑色,CK)的描述符用其相鄰關(guān)鍵點來表示。描述符的每個維度對應(yīng)于扇區(qū)區(qū)域。第一維度對應(yīng)于當(dāng)前關(guān)鍵點的最近關(guān)鍵點所在的扇區(qū)區(qū)域(藍(lán)色和紅色、CK的最近關(guān)鍵點),并且其他維度對應(yīng)于以逆時針順序布置的區(qū)域。如果在扇區(qū)區(qū)域中存在關(guān)鍵點,則搜索扇區(qū)區(qū)域中最近的關(guān)鍵點(紫色和橙色,扇區(qū)中CK的最近關(guān)鍵點)并將其用于表示描述符的對應(yīng)維度。

a735674c-063c-11ef-a297-92fbcf53809c.png

2. Link3D數(shù)據(jù)植入

這里的Link3D數(shù)據(jù)植入其實在外圍調(diào)用就這些內(nèi)容,當(dāng)中AggregationKeypoints_LinK3D存儲的是存當(dāng)前點云中的聚類后的關(guān)鍵點。而pCurrentFrame_LinK3D對應(yīng)的則是點云幀。該函數(shù)中利用LinK3D仿函數(shù)執(zhí)行了提取邊緣點,聚類,計算描述子的操作。其實主要實現(xiàn)的都是LinK3D提取器。

    //在這里植入LinK3D,把接收到的點云數(shù)據(jù)用LinK3D提取邊緣點和描述子,發(fā)布關(guān)鍵點數(shù)據(jù),打印輸出描述子
    //LinK3D提取器
    BoW3D::LinK3D_Extractor* pLinK3dExtractor(new BoW3D::LinK3D_Extractor(nScans, scanPeriod_LinK3D, minimumRange, distanceTh, matchTh)); 
    //創(chuàng)建點云幀,該函數(shù)中利用LinK3D仿函數(shù)執(zhí)行了提取邊緣點,聚類,計算描述子的操作
    Frame* pCurrentFrame_LinK3D(new Frame(pLinK3dExtractor, plaserCloudIn_LinK3D));
    //此時pCurrentFrame_LinK3D這個類指針中包含了邊緣點,聚類,描述子的信息
//測試 輸出關(guān)鍵點數(shù)量和第一個關(guān)鍵點信息 正常輸出 
// cout << "------------------------" << endl << "關(guān)鍵點數(shù)量:" << pCurrentFrame_LinK3D->mvAggregationKeypoints.size();
// cout << "第一個關(guān)鍵點信息x坐標(biāo)" << pCurrentFrame_LinK3D->mvAggregationKeypoints[0].x;
    //存當(dāng)前點云中的聚類后的關(guān)鍵點
    AggregationKeypoints_LinK3D->points.insert(AggregationKeypoints_LinK3D->points.end(), pCurrentFrame_LinK3D->mvAggregationKeypoints.begin(), pCurrentFrame_LinK3D->mvAggregationKeypoints.end());
//測試 輸出點云中信息 也能正常輸出
// cout << "------------------------" << endl << "關(guān)鍵點數(shù)量:" << AggregationKeypoints_LinK3D->points.size();
// cout << "第一個關(guān)鍵點信息x坐標(biāo)" << AggregationKeypoints_LinK3D->points[0].x;
    // 2.對描述子進行匹配 3.使用匹配對進行幀間icp配準(zhǔn) pPreviousFrame是上一個link3d Frame幀 pCurrentFrame_LinK3D是當(dāng)前l(fā)ink3d Frame幀
    // 獲取上一幀和當(dāng)前幀之間的匹配索引
     vector> vMatchedIndex; 
    pLinK3dExtractor->match(pCurrentFrame_LinK3D->mvAggregationKeypoints, pPreviousFrame->mvAggregationKeypoints, pCurrentFrame_LinK3D->mDescriptors, pPreviousFrame->mDescriptors, vMatchedIndex);
    //仿照BoW3D函數(shù)寫一個幀間ICP匹配函數(shù)求出R,t
    int returnValue = 0;
    // 進行幀間ICP匹配 求當(dāng)前幀到上一幀的位姿變換
    // 這里求的R t是當(dāng)前幀點云到上一幀點云的位姿變換
    returnValue = pose_estimation_3d3d(pCurrentFrame_LinK3D, pPreviousFrame, vMatchedIndex, RelativeR, Relativet, pLinK3dExtractor);
    //至此獲得了當(dāng)前幀點云到上一幀點云的位姿變換


    //當(dāng)前幀F(xiàn)rame用完以后,賦值給上一幀F(xiàn)rame,賦值前先把要丟掉的幀內(nèi)存釋放
    //這里Frame里有成員指針,析構(gòu)函數(shù)里delete成員指針
    delete pPreviousFrame;
    pPreviousFrame = pCurrentFrame_LinK3D;
    //LinK3D 植入結(jié)束

點云幀配置如下,其實可以看到這里面沒有太多的內(nèi)容,主要還是調(diào)用Link3D中的void LinK3D_Extractor::Ptr pLaserCloudIn, vector &keyPoints, cv::Mat &descriptors, ScanEdgePoints &validCluster)函數(shù)。并獲取關(guān)鍵點、描述子還有聚類信息。具體的實現(xiàn)與具體論文保持一致,可以看Github內(nèi)容

  //靜態(tài)(全局?)變量要在這里初始化
  long unsigned int Frame::nNextId = 0;


  Frame::Frame(LinK3D_Extractor* pLink3dExtractor, pcl::PointCloud::Ptr pLaserCloudIn):mpLink3dExtractor(pLink3dExtractor)
  {
    mnId = nNextId++; 


    (*mpLink3dExtractor)(pLaserCloudIn, mvAggregationKeypoints, mDescriptors, mClusterEdgeKeypoints);
  }

2. CSF“布料”濾波算法

然后下面就是CSF的處理,這里其實可以將內(nèi)容加在BALM當(dāng)中,Github。因為CSF其實作用是區(qū)分地面點的作用

a75834b6-063c-11ef-a297-92fbcf53809c.png

 // 
 CSF csf;
 csf.params.iterations = 600;
 csf.params.time_step = 0.95;
 csf.params.cloth_resolution = 3;
 csf.params.bSloopSmooth = false;


 csf.setPointCloud(*laserCloudSurfLast);
 // pcl::savePCDFileBinary(map_save_directory, *SurfFrame);


 std::vector groundIndexes, offGroundIndexes;
 // 輸出的是vector類型的地面點和非地面點索引
 pcl::PointCloud::Ptr groundFrame(new pcl::PointCloud);
 pcl::PointCloud::Ptr offGroundFrame(new pcl::PointCloud);
 csf.do_filtering(groundIndexes, offGroundIndexes);
 pcl::copyPointCloud(*laserCloudSurfLast, groundIndexes, *groundFrame);
 pcl::copyPointCloud(*laserCloudSurfLast, offGroundIndexes, *offGroundFrame);

實際用一句話:把點云翻過來,罩上一塊不同材質(zhì)的布料,就可以得到地面了。參考實際物理的布,布料上的點之間存在不同的作用力,詳細(xì)可以參考這篇文章:https://www.guyuehome.com/40977

3. BALM

對于BALM其實主要分為三塊,balm_front、scan2map、balm_back這三個流程。我們一開始使用的是ALOAM的前端來提取激光里程計信息,然后scan2map中加入CSF來進一步區(qū)分地面點。最后分成三類傳入到BA約束當(dāng)中https://blog.csdn.net/lovely_yoshino/article/details/133940976。

a7677ad4-063c-11ef-a297-92fbcf53809c.png

while(n.ok())
  {
    ros::spinOnce();
    if(corn_buf.empty() || ground_buf.empty() || odom_buf.empty() || offground_buf.empty())
    {
      continue;
    }


    mBuf.lock();
    uint64_t time_corn = corn_buf.front()->header.stamp.toNSec();
    uint64_t time_ground = ground_buf.front()->header.stamp.toNSec();
    uint64_t time_odom = odom_buf.front()->header.stamp.toNSec();
    uint64_t time_offground = offground_buf.front()->header.stamp.toNSec();
    if(time_odom != time_corn)
    {
      time_odom < time_corn ? odom_buf.pop() : corn_buf.pop();
 ? ? ? ? ? ?mBuf.unlock();
 ? ? ? ? ? ?continue;
 ? ? ? ?}


 ? ? ? ?if(time_odom != time_ground)
 ? ? ? ?{
 ? ? ? ? ? ?time_odom < time_ground ? odom_buf.pop() : ground_buf.pop();
 ? ? ? ? ? ?mBuf.unlock();
 ? ? ? ? ? ?continue;
 ? ? ? ?}


 ? ? ? ?if(time_odom != time_offground)
 ? ? ? ?{
 ? ? ? ? ? ?time_odom < time_ground ? odom_buf.pop() : ground_buf.pop();
 ? ? ? ? ? ?mBuf.unlock();
 ? ? ? ? ? ?continue;
 ? ? ? ?}


 ? ? ? ?ros::Time ct(ground_buf.front()->header.stamp);
    pcl::PointCloud::Ptr pl_ground_temp(new pcl::PointCloud);
    pcl::PointCloud::Ptr pl_edge_temp(new pcl::PointCloud);
    pcl::PointCloud::Ptr pl_offground_temp(new pcl::PointCloud);


    rosmsg2ptype(*ground_buf.front(), *pl_ground);
    rosmsg2ptype(*corn_buf.front(), *pl_corn);
    rosmsg2ptype(*offground_buf.front(), *pl_offground);


    //pcl::savePCDFileBinary("/home/wb/FALOAMBA_WS/wb/Map/map.pcd", *pl_ground);


    //pl_ground還有用,所以這里復(fù)制出一個新點云
    *pl_ground_temp = *pl_ground;
    *pl_edge_temp = *pl_corn;
    *pl_offground_temp = *pl_offground;
    corn_buf.pop(); ground_buf.pop(); offground_buf.pop();


    q_odom.w() = odom_buf.front()->pose.pose.orientation.w;
    q_odom.x() = odom_buf.front()->pose.pose.orientation.x;
    q_odom.y() = odom_buf.front()->pose.pose.orientation.y;
    q_odom.z() = odom_buf.front()->pose.pose.orientation.z;
    t_odom.x() = odom_buf.front()->pose.pose.position.x;
    t_odom.y() = odom_buf.front()->pose.pose.position.y;
    t_odom.z() = odom_buf.front()->pose.pose.position.z;
    odom_buf.pop();
    mBuf.unlock();


    // T_curr2last = T_curr2w * T_last2wˉ1
    Eigen::Vector3d delta_t(q_last.matrix().transpose()*(t_odom-t_last));
    Eigen::Quaterniond delta_q(q_last.matrix().transpose() * q_odom.matrix());
    q_last = q_odom;
    t_last = t_odom;


    // T_curr2last * I
    t_gather_pose = t_gather_pose + q_gather_pose * delta_t;
    q_gather_pose = q_gather_pose * delta_q;
    if(jump_flag < skip_num)
 ? ? ? ?{
 ? ? ? ? ? ?jump_flag++;
 ? ? ? ? ? ?continue;
 ? ? ? ?}
 ? ? ? ?jump_flag = 0;


 ? ? ? ?if(plcount == 0)// 第一幀
 ? ? ? ?{
 ? ? ? ? ? ?// 第一幀:T_curr2w = T_curr2last
 ? ? ? ? ? ?q_poses.push_back(q_gather_pose);
 ? ? ? ? ? ?t_poses.push_back(t_gather_pose);
 ? ? ? ?}
 ? ? ? ?else// 第二幀
 ? ? ? ?{
 ? ? ? ? ? ?// T_1_2_0 * T_2_2_1 = T_2_2_0
 ? ? ? ? ? ?// T_2_2_0 * T_3_2_2 = T_3_2_0
 ? ? ? ? ? ?q_poses.push_back(q_poses[plcount-1]*q_gather_pose);
 ? ? ? ? ? ?t_poses.push_back(t_poses[plcount-1] + q_poses[plcount-1] * t_gather_pose);
 ? ? ? ?}


 ? ? ? ?parray.header.stamp = ct;
 ? ? ? ?geometry_msgs::Pose apose;
 ? ? ? ?apose.orientation.w = q_poses[plcount].w();
 ? ? ? ?apose.orientation.x = q_poses[plcount].x();
 ? ? ? ?apose.orientation.y = q_poses[plcount].y();
 ? ? ? ?apose.orientation.z = q_poses[plcount].z();
 ? ? ? ?apose.position.x = t_poses[plcount].x();
 ? ? ? ?apose.position.y = t_poses[plcount].y();
 ? ? ? ?apose.position.z = t_poses[plcount].z();


 ? ? ? ?// ---------------------------- 當(dāng)前幀位姿(優(yōu)化前的)--------------------------------
 ? ? ? ?nav_msgs::Odometry laser_odom;
 ? ? ? ?laser_odom.header.frame_id = "camera_init";
 ? ? ? ?laser_odom.child_frame_id = "aft_BA";
 ? ? ? ?laser_odom.header.stamp = ct;
 ? ? ? ?laser_odom.pose.pose.orientation.x = apose.orientation.x;
 ? ? ? ?laser_odom.pose.pose.orientation.y = apose.orientation.y;
 ? ? ? ?laser_odom.pose.pose.orientation.z = apose.orientation.z;
 ? ? ? ?laser_odom.pose.pose.orientation.w = apose.orientation.w;
 ? ? ? ?laser_odom.pose.pose.position.x = apose.position.x;
 ? ? ? ?laser_odom.pose.pose.position.y = apose.position.y;
 ? ? ? ?laser_odom.pose.pose.position.z = apose.position.z;
 ? ? ? ?//發(fā)布優(yōu)化前的位姿
 ? ? ? ?pub_odom.publish(laser_odom);
 ? ? ? ?//發(fā)布坐標(biāo)關(guān)系
 ? ? ? ?static tf::TransformBroadcaster br;
 ? ? ? ?tf::Transform transform;
 ? ? ? ?tf::Quaternion q;
 ? ? ? ?transform.setOrigin(tf::Vector3(apose.position.x, apose.position.y, apose.position.z));
 ? ? ? ?q.setW(apose.orientation.w);
 ? ? ? ?q.setX(apose.orientation.x);
 ? ? ? ?q.setY(apose.orientation.y);
 ? ? ? ?q.setZ(apose.orientation.z);
 ? ? ? ?transform.setRotation(q);
 ? ? ? ?br.sendTransform(tf::StampedTransform(transform, laser_odom.header.stamp, "camera_init", "aft_BA"));
 ? ? ? ?parray.poses.push_back(apose);


 ? ? ? ?// 發(fā)布優(yōu)化前的位姿
 ? ? ? ?pub_pose.publish(parray);


 ? ? ? ?pl_ground_buf.push_back(pl_ground_temp);
 ? ? ? ?pl_edge_buf.push_back(pl_edge_temp);
 ? ? ? ?pl_offground_buf.push_back(pl_offground_temp);

審核編輯:黃飛

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • SLAM
    +關(guān)注

    關(guān)注

    23

    文章

    411

    瀏覽量

    31738
  • 濾波算法
    +關(guān)注

    關(guān)注

    2

    文章

    87

    瀏覽量

    13704

原文標(biāo)題:如何插入LinK3D、CSF、BALM來直接插入各個SLAM框架中

文章出處:【微信號:vision263com,微信公眾號:新機器視覺】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    GSLAM:一套通用的SLAM框架與基準(zhǔn)

    其中,SLAM算法插件提供了SLAM領(lǐng)域流行的優(yōu)秀算法,包括DSO,ORBSLAM,SVO和TheiaSFM等,這些插件可以直接集成自己的代碼,研究人員也可以基于這些插件進行進一步
    的頭像 發(fā)表于 03-07 09:42 ?8331次閱讀
    GSLAM:一套通用的<b class='flag-5'>SLAM</b><b class='flag-5'>框架</b>與基準(zhǔn)

    基于多模態(tài)語義SLAM框架

    本文提出了一個魯棒且快速的多模態(tài)語義 SLAM 框架,旨在解決復(fù)雜和動態(tài)環(huán)境SLAM 問題。具體來說,僅幾何聚類和視覺語義信息相結(jié)合
    的頭像 發(fā)表于 08-31 09:39 ?1622次閱讀

    Hadoop的整體框架組成

    。Hadoop旨在從單個服務(wù)器擴展數(shù)千個機器,每個都提供本地計算和存儲。Hadoop框架包括以下四個模塊:HadoopCommon: 這些是其他Hadoop模塊所需的Java庫和實用程序。這些庫提供文件系統(tǒng)
    發(fā)表于 05-11 16:00

    框架設(shè)計的常用模式有哪些

    1. 模板方法模式模板方法模式是框架中最常用的設(shè)計模式。其根本的思路是算法由框架固定,而將算法具體的操作交給二次開發(fā)者實現(xiàn)。例如一個設(shè)備初始化的邏輯,
    發(fā)表于 12-17 16:44

    什么是框架?為什么要有框架

    代碼結(jié)構(gòu)體邏輯是一樣的,同時有大量相似或者共同的地方。我們可以這些共同的地方抽出來形成一個固定的程序框架,那么我們再開發(fā)新的同一種類型的程序時就可以套用這套框架。這樣會大大提高我們的開發(fā)效率,同時由于這個
    發(fā)表于 11-09 07:38

    HOOFR-SLAM的系統(tǒng)框架及其特征提取

    Intelligent Vehicles Applications1. 介紹2. HOOFR-SLAM2.1 系統(tǒng)框架2.2 HOOFR特征提取2.3 映射線程2.3.1 特征匹配1. 介紹提出一種HOOFR-...
    發(fā)表于 12-21 06:35

    如何將CubeMX生成的程序框架與BSP驅(qū)動程序快速集成?

    一些經(jīng)驗如何將 CubeMX 生成的程序框架與 BSP 驅(qū)動程序快速集成。目標(biāo)是擁有無編譯/鏈接錯誤的應(yīng)用程序框架。x-nucleo 板的入門文檔側(cè)重于 HAL 和 BSP 層的一般概念。我正在尋找
    發(fā)表于 01-30 08:48

    ACE代碼框架總結(jié)

    .ACE_Engine框架模塊劃分對于類Web開發(fā)范式組件,根據(jù)組件從前端后端的過程,可以整個框架劃分為JsFrameWork,DomNode, ComPonent, Render
    發(fā)表于 03-22 09:11

    如何將應(yīng)用程序移植運行在基于Arm的設(shè)備上的Windows?

    本指南介紹如何將應(yīng)用程序移植運行在基于Arm的設(shè)備上的Windows。該指南首先回顧了一般指南,然后展示了不同框架的示例:Tweeten應(yīng)用程序的Electron移植、StaffPad應(yīng)用程序
    發(fā)表于 08-02 06:06

    spring mvc框架介紹

    。使用 Spring 可插入的 MVC 架構(gòu),可以選擇是使用內(nèi)置的 Spring Web 框架還是 Struts 這樣的 Web 框架。通過策略接口,Spring 框架是高度可配置的,
    發(fā)表于 11-17 16:28 ?2310次閱讀
    spring mvc<b class='flag-5'>框架</b>介紹

    從單片機基礎(chǔ)程序框架

    單片機應(yīng)用的核心技術(shù)是什么?是按鍵,數(shù)碼管,流水燈,串口。是它們的程序框架。按鍵和數(shù)碼管是 輸入是人機界面,把它們的程序框架研究透了,以后做彩屏或者更花銷的顯示界面,程序框架也可以通用。 流水
    發(fā)表于 09-07 14:45 ?9次下載

    LINS算法的框架與代碼分析

    , 由于網(wǎng)上已經(jīng)有些同學(xué)對算法做了介紹,一些基礎(chǔ)的知識本文不再贅述,本文詳細(xì)圍繞以下兩個問題介紹,希望對讀者理解算法有所幫助: 1、LINS 是如何將激光觀測融入濾波框架的? 2、濾波框架
    的頭像 發(fā)表于 10-09 14:57 ?3055次閱讀

    基于LeGo-LOAM框架的3D激光SLAM技術(shù)

    能力也過硬,一般企業(yè)年薪至少30W起步了。 學(xué)習(xí)SLAM主要需要攻克三大難關(guān): 扎實的數(shù)學(xué)基礎(chǔ) 對整個SLAM框架及細(xì)節(jié)部分理解一定深度 比較高度的編程能力 這三點都絕非易事,需要
    的頭像 發(fā)表于 06-29 15:28 ?582次閱讀
    基于LeGo-LOAM<b class='flag-5'>框架</b>的3D激光<b class='flag-5'>SLAM</b>技術(shù)

    視覺SLAM開源方案匯總 視覺SLAM設(shè)備選型

    SLAM至今已歷經(jīng)三十多年的研究,這里給出經(jīng)典視覺SLAM框架,這個框架本身及其包含的算法已經(jīng)基本定型,并且已經(jīng)在許多視覺程序庫和機器人程序庫中提供。
    發(fā)表于 08-10 14:15 ?915次閱讀
    視覺<b class='flag-5'>SLAM</b>開源方案匯總 視覺<b class='flag-5'>SLAM</b>設(shè)備選型

    視覺SLAM是什么?視覺SLAM的工作原理 視覺SLAM框架解讀

    近年來,SLAM技術(shù)取得了驚人的發(fā)展,領(lǐng)先一步的激光SLAM已成熟的應(yīng)用于各大場景,視覺SLAM雖在落地應(yīng)用上不及激光SLAM,但也是目前
    的頭像 發(fā)表于 09-05 09:31 ?3421次閱讀
    視覺<b class='flag-5'>SLAM</b>是什么?視覺<b class='flag-5'>SLAM</b>的工作原理 視覺<b class='flag-5'>SLAM</b><b class='flag-5'>框架</b>解讀