在使用点云进行网络检测之前,其实用机器学习方法对点云进行一些预处理是很有必要的。点云在使用之前都应该进行校准操作,这里我们不展开来说,我们要说一下点云的地面滤除。
Ransac算法
用的比较多的算法就是随机采样一致性方法,该方法可以很好的检测平面。我们先来看一张原始的点云图片:
这个点云具有很多地面的噪点。直接用这样的点云会有很多噪声影响,尝试通过去掉地面,在采用聚类的方式来把障碍物检测出来也是一种常用的方法。
通过pcl中的ransac算法得到滤除地面之后的点云像这样:
可以看到,大部分的地面点被滤除掉了,但是仍然具有这么一些问题:
- 多车道,如果中间包含障碍,如栅栏等,另外一边由于点云稀疏比较难滤掉。
- 对于具有一定高度的非障碍物,如两边的栅栏等,很难滤除。
实现
这里贴出实现代码,核心就两部,一步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.";
}
}