computing/perception/detection/lidar_detector/packages/lidar_euclidean_cluster_detect

点云欧几里德聚类。包括cuda版本

cluster.cpp单个聚类的属性等

ToROSMessage(std_msgs::Header in_ros_header, autoware_msgs::CloudCluster &out_cluster_message)根据聚类的结果,生成autoware_msgs::cloudcluster消息

SetCloud(const pcl::PointCloud::Ptr in_origin_cloud_ptr, const std::vector& in_cluster_indices, std_msgs::Header in_ros_header, int in_id, int in_r,   int in_g, int in_b, std::string in_label, bool in_estimate_pose) 根据单个聚类包含的点云,设置此聚类的一系列属性,如边框,坐标,方向等。1. 通过找最小的点和最大的点,确定边框,bounding_box_。2. 将所有点云投影到xy平面,然后用andrew Monotone chain计算最小凸边形,将最小凸边性的点存储在polygon_中。如果is_estimate_pose=true,表示将需要用最小凸边形,校正bounding_box_。计算最小凸边性的水平旋转角,校正bounding_box_的朝向。

tf::Quaternion quat = tf::createQuaternionFromRPY(0.0, 0.0, rz);

  tf::quaternionTFToMsg(quat, bounding_box_.pose.orientation);

如果点云的数量大于3,则进行pca主成分析,计算特征向量和特征值,分别保存在eigen_vectors_ 和eigen_values中,点云保存在pointcloud_中。

GetFpfhDescriptor(const unsigned int& in_ompnum_threads,const double& in_normal_search_radius, const double& in_fpfh_search_radius) 获取快速点特征直方图描述子,即提取当前聚类点云的特征。首先用KDtree和normalestimationOPM计算点云中每个点的法向量,搜索点附近阈值范围内的点计算法向量。调用FPFHEstimaionOMP计算每个点的直方图,然后将每个点对应位置的直方图合并,每个直方图是一个33个值组成的向量,即将向量累加,并找出33个值的最大和最小。(貌似每一个点都要标准化一次,不知道时为啥,看不懂,留待以后解答)

lidar_euclidean_cluster_detect.cpp

findTransform()  查找对应的坐标变换,返回transform

transformPoint() 根据transform将点云点变换到对应坐标系下

checkPointInGrid(const grid_map::GridMap &in_grid_map, const cv::Mat &in_grid_image,const geometry_msgs::Point &in_point) 检查点是否在gridmap内部

publishDetectedObjects(const autoware_msgs::CloudClusterArray &in_clusters)发布聚类集合消息。每一聚类转换为一个autoware_msgs::DetectedObject,再统一放在autoware_msgs::DetectedObejctArray中,发布。

publishCloudClusters(const ros::Publisher *in_publisher, const autoware_msgs::CloudClusterArray &in_clusters,   const std::string &in_target_frame, const std_msgs::Header &in_header) 发布聚类目标物消息。末尾是调用publishDetectedObjects()发送消息,1. 如果目标做标系和当前坐标系不一致,则需要转换聚类的各项参数到目标坐标系下,如cloud,min_point,max_point,avg_point等。_transform_listener->lookupTransform(in_target_frame, _velodyne_header.frame_id, ros::Time(), *_transform);pcl_ros::transformPointCloud(in_target_frame, *_transform, i->cloud, cluster_transformed.cloud);需要先查找坐标变换再转换  2. 如果一致,则直接发送,无需转换

publishCentroids(const ros::Publisher *in_publisher, const autoware_msgs::Centroids &in_centroids,const std::string &in_target_frame, const std_msgs::Header &in_header) 发布中心点消息。1. 如果目标做标系和当前坐标系不一致,则需要转换聚类的各项参数到目标坐标系下。_transform_listener->transformPoint(in_target_frame, ros::Time(), centroid_in, in_header.frame_id, centroid_out);2. 如果一致,则直接发送,无需转换

publishcloud() 发布点云消息

publishColorCloud() 发布rgb点云

keepLanePoints(const pcl::PointCloud::Ptr in_cloud_ptr, pcl::PointCloud::Ptr out_cloud_ptr, float in_left_lane_threshold = 1.5, float in_right_lane_threshold = 1.5)  保留左右一定范围内的点,默认值为左右各1.5米内的点。先判断哪些点不符合要求,将其序号添加到 pcl::pointindices中,再利用pcl::ExtractIndices将序号内的点去掉,留下的是符合要求的点

clusterAndColorGpu 点云聚类和着色GPU版本,暂不分析,没看。

clusterAndColor ()  聚类和着色。将点云投影到xy平面。构建KDTree,tree的输入为投影到xy的点云。使用欧几里得聚类,搜索方法用kdtree。调用cluster的SetCloud计算每个聚类点云的若干属性,如边框,凸边形,最大,最小点等,并为每个聚类的点着色。将所有聚类保存在cluster的向量中。

checkClusterMerge(size_t in_cluster_id, std::vector &in_clusters, std::vector &in_out_visited_clusters, std::vector &out_merge_indices, double in_merge_threshold)  检查聚类结果之间是否可以互相融合。过程:轮询每个聚类,判断其他聚类与其中心点之间的距离是否小于阈值,如果小于阈值表示可以融合,将序号存储在out_merge_indices中,以当前聚类继续执行checkClusterMerge函数,直到找到所有可以聚类的目标,将可以聚类的目标标志位设置为1,轮询是跳过标志位为1的目标。

mergeClusters(const std::vector &in_clusters, std::vector &out_clusters, std::vector in_merge_indices, const size_t ¤t_index,std::vector &in_out_merged_clusters)  融合聚类,将可以融合的目标的点云存储再同一个pointcloud中,将可融合的目标标志位置1,便于最后区分已被融合的目标和独立目标。融合后重新调用SetCloud计算目标的边框,凸边形等属性,并着色。加入到out_cluster中。

checkAllForMerge()  调用checClusterMerge() 和 mergeClusters() ,将能够融合的目标融合。最后将融合后的目标和独立目标统一存入out_clusters。

segmentByDistance(const pcl::PointCloud::Ptr in_cloud_ptr, pcl::PointCloud::Ptr out_cloud_ptr,   autoware_msgs::Centroids &in_out_centroids,autoware_msgs::CloudClusterArray &in_out_clusters)  根据距离进行目标分割,其实就是调用欧几里得距离,clusterAndColor()。1. 判断是否使用多线程(use_multiple_thres),如果不用,则调用clusterAndColor 2. 如果用,则将点云根据距离分为5组,分别使用不同的阈值进行欧几里得聚类,调用clusterAndColor(),

// 0 => 0-15m d=0.5

  // 1 => 15-30 d=1

  // 2 => 30-45 d=1.6

  // 3 => 45-60 d=2.1

  // 4 => >60  d=2.6

聚类结果存储到all_clusters中,查看聚类中是否有可以聚合到一起的目标,如果有,则调用checkAllForMerge----> final_clusters。3.  是否使用地图向量,如果使用,则判断所需要的地图层是否存在,若存在建立类似apollo::roi的grid_map,将每个cluster的centroid转换到雷达坐标系下,判断final_clusters中的每个目标的中心点是否再grid_map中( checkPointInGrid()),如果不在则将cluster的valid_cluster_设置为flase。此处valid_cluster_再setCloud()中已经全部设置为true。将final_cluster中所有valid_cluster_=true的目标转化为autoware::cluster ,并存储在autoware::clustersarray中---->in_out_clusters

removeFloor()  调用pcl::SACSegmentation去除地面,将地面点存储在out_onlyfloor_cloud_ptr中,将非地面点存储在out_nofloor_cloud_ptr中。

downsampleCloud() 点云降采样,体素,leaf_size设置为0.2,实际要比这个大才可以,否则依然很密集。

clipCloud() 裁剪点云,上下高度阈值为-1.3~0.5,保留范围内的点。

differenceNormalsSegmentation(const pcl::PointCloud::Ptr in_cloud_ptr,                  pcl::PointCloud::Ptr out_cloud_ptr)  按照点的法向量进行分割。1. 调用pcl::NormalEstimationOMP 再一大一小两个范围内计算法向量,

0.5------->normals_small_scale                              2.0------->normals_large_scale 

接下来调用pcl::DifferenceOfNormalsEstimation简称DoN算法,计算点大范围和小范围法向量的差异。

1.点云的频率

  今天在阅读分割有关的文献时,惊喜的发现,点云和图像一样,有可能也存在频率的概念。但这个概念并未在文献中出现也未被使用,谨在本博文中滥用一下“高频”一词。点云表达的是三维空间中的一种信息,这种信息本身并没有一一对应的函数值。故点云本身并没有在讲诉一种变化的信号。但在抽象意义上,点云必然是在表达某种信号的,虽然没有明确的时间关系,但应该会存在某种空间关系(例如LiDar点云)。我们可以人为的指定点云空间中的一个点(例如Scan的重心或LiDar的“源”),基于此点来讨论点云在各个方向上所谓的频率。

  在传统的信号处理中,高频信号一般指信号变化快,低频信号一般指信号变化缓慢。在图像处理中,高低频的概念被引申至不同方向上图像灰度的变化,傅里叶变换可以用于提取图像的周期成分滤除布纹噪声。在点云处理中,定义:点云法线向量差为点云所表达的信号。换言之,如果某处点云曲率大,则点云表达的是一个变化的信号。如果点云曲率小,则其表达的是一个不变的信号。这和我们的直观感受也是相近的,地面曲率小,它表达的信息量也小;人的五官部分曲率大,其表达了整个Scan中最大的信息量。

2.基于点云频率的滤波方法

  虽然点云频率之前并没有被讨论,但使用频率信息的思想已经被广泛的应用在了各个方面,最著名的莫过于DoN算法。DoN算法被作者归类于点云分割算法中,但我认为并不准确,本质上DoN只是一种前处理,应该算是一种比较先进的点云滤波算法。分割本质上还是由欧式分割算法完成的。DoN 是 Difference of Normal 的简写。算法的目的是在去除点云低频滤波,低频信息(例如建筑物墙面,地面)往往会对分割产生干扰,高频信息(例如建筑物窗框,路面障碍锥)往往尺度上很小,直接采用 基于临近信息 的滤波器会将此类信息合并至墙面或路面中。所以DoN算法利用了多尺度空间的思想,算法如下:

在小尺度上计算点云法线1

在大尺度上计算点云法线2

法线1-法线2

滤去3中值较小的点

欧式分割

  显然,在小尺度上是可以对高频信息进行检测的,此算法可以很好的小尺度高频信息。其在大规模点云(如LiDar点云)中优势尤其明显

计算出法向量之差后,调用pcl::ConditionOr,创建一个比较器,如果法向量差大于阈值(0.5),则保留,否则去掉。 过滤后的点保存在out_cloud_ptr中。就像上面说的一样,这是一个预处理算法,处理掉高频和低频(不懂)信息。原论文 Yani Ioannou. Automatic Urban Modelling using Mobile Urban LIDAR Data. Thesis (Master, Computing), Queen's University, March, 2010.


PCL—低层次视觉—点云滤波(基于点云频率) - 相关文章



PCL—低层次视觉—点云滤波(基于点云频率)

removePointsUpTo() 去掉近距离的点

velodyne_callback() 接收点云的回调函数。

你可能感兴趣的:(computing/perception/detection/lidar_detector/packages/lidar_euclidean_cluster_detect)