在使用点云进行网络检测之前,其实用机器学习方法对点云进行一些预处理是很有必要的。点云在使用之前都应该进行校准操作,这里我们不展开来说,我们要说一下点云的地面滤除。

Ransac算法

用的比较多的算法就是随机采样一致性方法,该方法可以很好的检测平面。我们先来看一张原始的点云图片:

61c2f694-1493-4701-a440-999b72652a09-image.png

这个点云具有很多地面的噪点。直接用这样的点云会有很多噪声影响,尝试通过去掉地面,在采用聚类的方式来把障碍物检测出来也是一种常用的方法。
通过pcl中的ransac算法得到滤除地面之后的点云像这样:

b13f5558-5702-4dc9-bf03-83270f354bfb-image.png

可以看到,大部分的地面点被滤除掉了,但是仍然具有这么一些问题:

  1. 多车道,如果中间包含障碍,如栅栏等,另外一边由于点云稀疏比较难滤掉。
  2. 对于具有一定高度的非障碍物,如两边的栅栏等,很难滤除。

实现

这里贴出实现代码,核心就两部,一步ransac算法,另外一步是把地面点扣除掉。


void detectObjectsOnCloud(pcl::PointCloud<PointType>::Ptr &cloud,
                          pcl::PointCloud<PointType>::Ptr &cloud_filtered)
{
    if (cloud->size() > 0)
    {
        pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);
        pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
        pcl::SACSegmentation<PointType> seg;
        seg.setOptimizeCoefficients(true);
        seg.setModelType(pcl::SACMODEL_PLANE);
        seg.setMethodType(pcl::SAC_RANSAC);
        seg.setDistanceThreshold(0.15);
        seg.setInputCloud(cloud);
        seg.segment(*inliers, *coefficients);
        if (inliers->indices.size() == 0)
        {
            LOG(ERROR) << "Could not found any inliers.";
        }

        // extract ground
        pcl::ExtractIndices<PointType> extractor;
        extractor.setInputCloud(cloud);
        extractor.setIndices(inliers);
          extractor.setNegative(true);
        extractor.filter(*cloud_filtered);
        // vise-versa, remove the ground not just extract the ground
        // just setNegative to be true
        cout << "filter done.";
    }
    else
    {
        LOG(INFO) << "cloud has no data.";
    }
}