代码示例
void downSample(CloudT::Ptr cloud, const double& leaf_size)
{
CloudT::Ptr filtered(new CloudT);
pcl::VoxelGrid<PointT> downer;
downer.setInputCloud(cloud);
downer.setLeafSize(leaf_size, leaf_size, leaf_size);
downer.filter(*filtered);
cloud->clear();
*cloud = std::move(*filtered);
}
结果:
原始点云 | 滤波后点云 |
---|---|
![]() |
![]() |
原因:点云中含有无效值
方法一
利用pcl的接口去除无效值:
pcl::removeNaNFromPointCloud (const pcl::PointCloud< PointT > &cloud_in, pcl::PointCloud< PointT > &cloud_out, std::vector< int > &index)
结果并没有得到明显改善,查阅该接口的主要实现如下:
pcl::removeNaNFromPointCloud (const pcl::PointCloud<PointT> &cloud_in,
pcl::PointCloud<PointT> &cloud_out,
std::vector<int> &index)
{
// If the clouds are not the same, prepare the output
if (&cloud_in != &cloud_out)
{
cloud_out.header = cloud_in.header;
cloud_out.points.resize (cloud_in.points.size ());
cloud_out.sensor_origin_ = cloud_in.sensor_origin_;
cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_;
}
// Reserve enough space for the indices
index.resize (cloud_in.points.size ());
// If the data is dense, we don't need to check for NaN
if (cloud_in.is_dense)
{
// Simply copy the data
cloud_out = cloud_in;
for (std::size_t j = 0; j < cloud_out.points.size (); ++j)
index[j] = static_cast<int>(j);
}
else
{
std::size_t j = 0;
for (std::size_t i = 0; i < cloud_in.points.size (); ++i)
{
if (!std::isfinite (cloud_in.points[i].x) ||
!std::isfinite (cloud_in.points[i].y) ||
!std::isfinite (cloud_in.points[i].z))
continue;
cloud_out.points[j] = cloud_in.points[i];
index[j] = static_cast<int>(i);
j++;
}
if (j != cloud_in.points.size ())
{
// Resize to the correct size
cloud_out.points.resize (j);
index.resize (j);
}
cloud_out.height = 1;
cloud_out.width = static_cast<std::uint32_t>(j);
// Removing bad points => dense (note: 'dense' doesn't mean 'organized')
cloud_out.is_dense = true;
}
}
从实现可以看出该接口是能有效的去除nan值和inf值,但如果cloud_in.is_dense是正确的,则直接返回.问题就出现在这,pcl::PointCloud对象构造时,默认都是将is_dense成员置为true,如果后面向pointcloud对象输入nan值时,is_dense成员始终都是true,也就出现了用removeNaNFromPointCloud接口无法去除无效值的情况.
修改代码如下:
void downSample(CloudT::Ptr cloud, const double& leaf_size)
{
//filter out invalid point
CloudT::Ptr no_nan_cloud(new CloudT);
std::vector<int> out_inliers;
cloud->is_dense = false;
pcl::removeNaNFromPointCloud(*cloud, *no_nan_cloud, out_inliers);
//voxel filter
CloudT::Ptr filtered(new CloudT);
pcl::VoxelGrid<PointT> downer;
downer.setInputCloud(no_nan_cloud);
downer.setLeafSize(leaf_size, leaf_size, leaf_size);
downer.filter(*filtered);
cloud->clear();
*cloud = std::move(*filtered);
}
得到如下滤波后结果,达到了降采样的目的.
原始点云 | 滤波后点云 |
---|---|
![]() |
![]() |
说明:pointcloud的is_dense含义是什么???下面是官方解释:
True if no points are invalid (e.g., have NaN or Inf values in any of their floating point fields).
就是指明这个点云是否包含无效值.由于在构造点云对象时,默认是将is_dense置为true,所以在无法保证所构建的点云是否包含无效值时,建议手动将is_dense置为false,否则会造成pcl的很多点云处理算法出现异常.(个人感觉:这个成员变量的目的是为了对点云只做一次有效性判断,由于后面对点云的处理的算法可能有多个,这样就不需要在算法中重复判断每个点的有效性,节省处理时间)
方法二
pcl点云处理算法的实现中一般都会判断点云的有效性,从而保证算法的准确性.但判断与否是取决于上述is_dense成员,如果将该成员设为false,算法会自动进行点云的有效性判断,剔除掉无效点云.所以还可通过下面的代码直接进行降采样:
void downSample(CloudT::Ptr cloud, const double& leaf_size)
{
cloud->is_dense = false;
CloudT::Ptr filtered(new CloudT);
pcl::VoxelGrid<PointT> downer;
downer.setInputCloud(cloud);
downer.setLeafSize(leaf_size, leaf_size, leaf_size);
downer.filter(*filtered);
cloud->clear();
*cloud = std::move(*filtered);
}
也可得到方法一的效果.
建议
如果点云对象只是经过一个算法处理,则在处理前直接将is_dense对象置为false.
如果点云对象经过多个算法处理,则在处理前先判断点云的有效性,生成不含无效点的点云,并将is_dense置为true,减少计算量
版权声明:本文为weixin_37835423原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。