pcl::voxelGrid<PointT> 降采样后点云异常

代码示例
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,减少计算量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值