热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

LIOSLAM代码详细注释二featureExtraction.cpp

featureExtraction.cpp#includeutility.h#includelio_samcloud_info.hstructsmoothness_t{

featureExtraction.cpp

#include "utility.h"
#include "lio_sam/cloud_info.h"struct smoothness_t{ float value; //曲率size_t ind; //序号
};struct by_value{ //曲率值对比bool operator()(smoothness_t const &left, smoothness_t const &right) { return left.value < right.value;}
};class FeatureExtraction : public ParamServer
{public:ros::Subscriber subLaserCloudInfo;ros::Publisher pubLaserCloudInfo;ros::Publisher pubCornerPoints;//发布角点特征ros::Publisher pubSurfacePoints;//发布面特征
//pcl点云指针&#xff0c;提取、角点、面pcl::PointCloud<PointType>::Ptr extractedCloud;//有效点pcl::PointCloud<PointType>::Ptr cornerCloud; //存角点pcl::PointCloud<PointType>::Ptr surfaceCloud; //存面pcl::VoxelGrid<PointType> downSizeFilter;lio_sam::cloud_info cloudInfo;std_msgs::Header cloudHeader; //发布topic的时间戳std::vector<smoothness_t> cloudSmoothness; //存储每个点的曲率和索引号float *cloudCurvature; //存储每个点的曲率int *cloudNeighborPicked; //不进行特征提取的索引int *cloudLabel; //标记面的索引FeatureExtraction(){su&#96;bLaserCloudInfo &#61; nh.subscribe<lio_sam::cloud_info>("lio_sam/deskew/cloud_info", 1,&FeatureExtraction::laserCloudInfoHandler, this, ros::TransportHints().tcpNoDelay());pubLaserCloudInfo &#61; nh.advertise<lio_sam::cloud_info> ("lio_sam/feature/cloud_info", 1);pubCornerPoints &#61; nh.advertise<sensor_msgs::PointCloud2>("lio_sam/feature/cloud_corner", 1);pubSurfacePoints &#61; nh.advertise<sensor_msgs::PointCloud2>("lio_sam/feature/cloud_surface", 1);initializationValue();}void initializationValue(){cloudSmoothness.resize(N_SCAN*Horizon_SCAN);//降采样参数0.2downSizeFilter.setLeafSize(odometrySurfLeafSize, odometrySurfLeafSize, odometrySurfLeafSize);extractedCloud.reset(new pcl::PointCloud<PointType>());cornerCloud.reset(new pcl::PointCloud<PointType>());surfaceCloud.reset(new pcl::PointCloud<PointType>());cloudCurvature &#61; new float[N_SCAN*Horizon_SCAN];cloudNeighborPicked &#61; new int[N_SCAN*Horizon_SCAN];cloudLabel &#61; new int[N_SCAN*Horizon_SCAN];}
//将订阅的点云信息传到cloudInfo void laserCloudInfoHandler(const lio_sam::cloud_infoConstPtr& msgIn){cloudInfo &#61; *msgIn; // new cloud infocloudHeader &#61; msgIn->header; // new cloud headerpcl::fromROSMsg(msgIn->cloud_deskewed, *extractedCloud); // new cloud for extraction&#xff0c;转成ros信息点云//计算曲率calculateSmoothness();//标记遮挡和平行点markOccludedPoints();//提取角点和面特帧extractFeatures();//发布特征点云publishFeatureCloud();}
//计算曲率 10个点void calculateSmoothness(){int cloudSize &#61; extractedCloud->points.size();//序号从第五个开始&#xff0c;前后五个&#xff0c;共10个for (int i &#61; 5; i < cloudSize - 5; i&#43;&#43;){ //但前点与附近10点的距离差和float diffRange &#61; cloudInfo.pointRange[i-5] &#43; cloudInfo.pointRange[i-4]&#43; cloudInfo.pointRange[i-3] &#43; cloudInfo.pointRange[i-2]&#43; cloudInfo.pointRange[i-1] - cloudInfo.pointRange[i] * 10&#43; cloudInfo.pointRange[i&#43;1] &#43; cloudInfo.pointRange[i&#43;2]&#43; cloudInfo.pointRange[i&#43;3] &#43; cloudInfo.pointRange[i&#43;4]&#43; cloudInfo.pointRange[i&#43;5]; cloudCurvature[i] &#61; diffRange*diffRange;//diffX * diffX &#43; diffY * diffY &#43; diffZ * diffZ;cloudNeighborPicked[i] &#61; 0;cloudLabel[i] &#61; 0;// cloudSmoothness for sortingcloudSmoothness[i].value &#61; cloudCurvature[i];cloudSmoothness[i].ind &#61; i;}}
//标记不提取的点云特征&#xff0c;遮挡平行点void markOccludedPoints(){int cloudSize &#61; extractedCloud->points.size();// mark occluded points and parallel beam pointsfor (int i &#61; 5; i < cloudSize - 6; &#43;&#43;i)//与后一个点插值&#xff0c;所以减去6{// occluded pointsfloat depth1 &#61; cloudInfo.pointRange[i];float depth2 &#61; cloudInfo.pointRange[i&#43;1];//列索引间的距离int columnDiff &#61; std::abs(int(cloudInfo.pointColInd[i&#43;1] - cloudInfo.pointColInd[i]));if (columnDiff < 10){// 10 pixel diff in range image范围图像中的像素差异 //对相邻两帧进行测距&#xff0c;附近前后五帧的也受当前评测影响//在一定范围内 &#xff0c;设为1,不再考虑成为特征点if (depth1 - depth2 > 0.3){cloudNeighborPicked[i - 5] &#61; 1;cloudNeighborPicked[i - 4] &#61; 1;cloudNeighborPicked[i - 3] &#61; 1;cloudNeighborPicked[i - 2] &#61; 1;cloudNeighborPicked[i - 1] &#61; 1;cloudNeighborPicked[i] &#61; 1;}else if (depth2 - depth1 > 0.3){cloudNeighborPicked[i &#43; 1] &#61; 1;cloudNeighborPicked[i &#43; 2] &#61; 1;cloudNeighborPicked[i &#43; 3] &#61; 1;cloudNeighborPicked[i &#43; 4] &#61; 1;cloudNeighborPicked[i &#43; 5] &#61; 1;cloudNeighborPicked[i &#43; 6] &#61; 1;}}// parallel beam平行线的 情况&#xff0c;左右两点与该点的深度差&#xff0c;确定该点是否会被选择成为特征点float diff1 &#61; std::abs(float(cloudInfo.pointRange[i-1] - cloudInfo.pointRange[i]));float diff2 &#61; std::abs(float(cloudInfo.pointRange[i&#43;1] - cloudInfo.pointRange[i]));//与前后点的距离大于深度的百分之2,视为远离群点、斜坡点、凹凸面点和空旷区域点&#xff0c;设置为筛选过、弃用//因为噪声点会影响与该障碍物平面的匹配if (diff1 > 0.02 * cloudInfo.pointRange[i] && diff2 > 0.02 * cloudInfo.pointRange[i])cloudNeighborPicked[i] &#61; 1;}}
//进行角点与面点的提取&#xff0c;角点直接保存&#xff0c;面需要经过降采样之后保存void extractFeatures(){cornerCloud->clear();surfaceCloud->clear();pcl::PointCloud<PointType>::Ptr surfaceCloudScan(new pcl::PointCloud<PointType>());pcl::PointCloud<PointType>::Ptr surfaceCloudScanDS(new pcl::PointCloud<PointType>());for (int i &#61; 0; i < N_SCAN; i&#43;&#43;){surfaceCloudScan->clear();//六次循环&#xff0c;每次都要找2个角点&#xff08;平滑差&#xff09;和四个面&#xff08;平滑好&#xff09;for (int j &#61; 0; j < 6; j&#43;&#43;){//startRingIndex从4到20 共16次//假如起始0,终点是360度&#xff0c;将一帧云平均分乘6份&#xff0c;每一份60度//ep是end_index sp 是start_index 如&#xff1a;startRingIndex[i] &#61;1 endRingIndex[i]&#61;60//sp1 : 1 sp2 : 11 sp3 : 21 sp6 : 51//ep1 : 10 ep2 : 20 ep3 : 30........ep6 : 60//最后的点的曲率最大&#xff0c;如果满足条件就是角点 &#xff08;6-j&#xff09;/6 j/6int sp &#61; (cloudInfo.startRingIndex[i] * (6 - j) &#43; cloudInfo.endRingIndex[i] * j) / 6;/// (5 - j)/6 &#xff08;j &#43; 1)/6 -1int ep &#61; (cloudInfo.startRingIndex[i] * (5 - j) &#43; cloudInfo.endRingIndex[i] * (j &#43; 1)) / 6 - 1;if (sp >&#61; ep)continue;//cloudSmoothness.包括曲率和序号&#xff0c;将曲率从小到达排序std::sort(cloudSmoothness.begin()&#43;sp, cloudSmoothness.begin()&#43;ep, by_value());int largestPickedNum &#61; 0;//从后往前读取&#xff0c;越前面曲率越低越不满足边缘要求//进行角点提取for (int k &#61; ep; k >&#61; sp; k--){int ind &#61; cloudSmoothness[k].ind; // edgeThreshold: 1.0// surfThreshold: 0.1// 可提取特帧 曲率 if (cloudNeighborPicked[ind] &#61;&#61; 0 && cloudCurvature[ind] > edgeThreshold)//边缘{largestPickedNum&#43;&#43;;//每一段最多选取20个点if (largestPickedNum <&#61; 20){cloudLabel[ind] &#61; 1;//因为是角点所以不是面 &#xff0c;标记为1指的角点&#xff0c;-1指的是面cornerCloud->push_back(extractedCloud->points[ind]);} else {break;}//已经标记了角点&#xff0c;就不再重复标记cloudNeighborPicked[ind] &#61; 1;//同时避免了特征点聚集&#xff0c;所以对前后的五个角点不再提取特征for (int l &#61; 1; l <&#61; 5; l&#43;&#43;)//前5{ //一帧云与光心距离int columnDiff &#61; std::abs(int(cloudInfo.pointColInd[ind &#43; l] - cloudInfo.pointColInd[ind &#43; l - 1]));if (columnDiff > 10)break;cloudNeighborPicked[ind &#43; l] &#61; 1;}for (int l &#61; -1; l >&#61; -5; l--)//后5{int columnDiff &#61; std::abs(int(cloudInfo.pointColInd[ind &#43; l] - cloudInfo.pointColInd[ind &#43; l &#43; 1]));if (columnDiff > 10)break;cloudNeighborPicked[ind &#43; l] &#61; 1;}}}//进行面提取for (int k &#61; sp; k <&#61; ep; k&#43;&#43;){int ind &#61; cloudSmoothness[k].ind;if (cloudNeighborPicked[ind] &#61;&#61; 0 && cloudCurvature[ind] < surfThreshold){cloudLabel[ind] &#61; -1; //标记面特征cloudNeighborPicked[ind] &#61; 1; //不再重复提取特征for (int l &#61; 1; l <&#61; 5; l&#43;&#43;) {int columnDiff &#61; std::abs(int(cloudInfo.pointColInd[ind &#43; l] - cloudInfo.pointColInd[ind &#43; l - 1]));if (columnDiff > 10)break;cloudNeighborPicked[ind &#43; l] &#61; 1;}for (int l &#61; -1; l >&#61; -5; l--) {int columnDiff &#61; std::abs(int(cloudInfo.pointColInd[ind &#43; l] - cloudInfo.pointColInd[ind &#43; l &#43; 1]));if (columnDiff > 10)break;cloudNeighborPicked[ind &#43; l] &#61; 1;}}}//对面进行保存for (int k &#61; sp; k <&#61; ep; k&#43;&#43;){if (cloudLabel[k] <&#61; 0){surfaceCloudScan->push_back(extractedCloud->points[k]);}}}//对面进行pcl库降采样&#xff0c;临时保存在surfaceCloudScanDSsurfaceCloudScanDS->clear();downSizeFilter.setInputCloud(surfaceCloudScan);downSizeFilter.filter(*surfaceCloudScanDS);//保存临时值*surfaceCloud &#43;&#61; *surfaceCloudScanDS;}}void freeCloudInfoMemory(){cloudInfo.startRingIndex.clear();cloudInfo.endRingIndex.clear();cloudInfo.pointColInd.clear();cloudInfo.pointRange.clear();}void publishFeatureCloud(){// free cloud info memoryfreeCloudInfoMemory();// save newly extracted featurescloudInfo.cloud_corner &#61; publishCloud(&pubCornerPoints, cornerCloud, cloudHeader.stamp, lidarFrame);cloudInfo.cloud_surface &#61; publishCloud(&pubSurfacePoints, surfaceCloud, cloudHeader.stamp, lidarFrame);// publish to mapOptimizationpubLaserCloudInfo.publish(cloudInfo);}
};int main(int argc, char** argv)
{ros::init(argc, argv, "lio_sam");FeatureExtraction FE;ROS_INFO("\033[1;32m----> Feature Extraction Started.\033[0m");ros::spin();return 0;
}

参考博文&#xff1a;
https://bbs.csdn.net/topics/398260808
https://zhuanlan.zhihu.com/p/182408931
https://zhuanlan.zhihu.com/p/57351961
https://zhuanlan.zhihu.com/p/111388877


推荐阅读
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 本文介绍了Codeforces Round #321 (Div. 2)比赛中的问题Kefa and Dishes,通过状压和spfa算法解决了这个问题。给定一个有向图,求在不超过m步的情况下,能获得的最大权值和。点不能重复走。文章详细介绍了问题的题意、解题思路和代码实现。 ... [详细]
  • 实现一个通讯录系统,可添加、删除、修改、查找、显示、清空、排序通讯录信息
    本文介绍了如何实现一个通讯录系统,该系统可以实现添加、删除、修改、查找、显示、清空、排序通讯录信息的功能。通过定义结构体LINK和PEOPLE来存储通讯录信息,使用相关函数来实现各项功能。详细介绍了每个功能的实现方法。 ... [详细]
  • 阿里Treebased Deep Match(TDM) 学习笔记及技术发展回顾
    本文介绍了阿里Treebased Deep Match(TDM)的学习笔记,同时回顾了工业界技术发展的几代演进。从基于统计的启发式规则方法到基于内积模型的向量检索方法,再到引入复杂深度学习模型的下一代匹配技术。文章详细解释了基于统计的启发式规则方法和基于内积模型的向量检索方法的原理和应用,并介绍了TDM的背景和优势。最后,文章提到了向量距离和基于向量聚类的索引结构对于加速匹配效率的作用。本文对于理解TDM的学习过程和了解匹配技术的发展具有重要意义。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • Html5-Canvas实现简易的抽奖转盘效果
    本文介绍了如何使用Html5和Canvas标签来实现简易的抽奖转盘效果,同时使用了jQueryRotate.js旋转插件。文章中给出了主要的html和css代码,并展示了实现的基本效果。 ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
  • 本文讨论了如何在codeigniter中识别来自angularjs的请求,并提供了两种方法的代码示例。作者尝试了$this->input->is_ajax_request()和自定义函数is_ajax(),但都没有成功。最后,作者展示了一个ajax请求的示例代码。 ... [详细]
  • 如何在跨函数中使用内存?
    本文介绍了在跨函数中使用内存的方法,包括使用指针变量、动态分配内存和静态分配内存的区别。通过示例代码说明了如何正确地在不同函数中使用内存,并提醒程序员在使用动态分配内存时要手动释放内存,以防止内存泄漏。 ... [详细]
  • 如何使用Python从工程图图像中提取底部的方法?
    本文介绍了使用Python从工程图图像中提取底部的方法。首先将输入图片转换为灰度图像,并进行高斯模糊和阈值处理。然后通过填充潜在的轮廓以及使用轮廓逼近和矩形核进行过滤,去除非矩形轮廓。最后通过查找轮廓并使用轮廓近似、宽高比和轮廓区域进行过滤,隔离所需的底部轮廓,并使用Numpy切片提取底部模板部分。 ... [详细]
author-avatar
鸵鸟家的大pp
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有