填写类的内容(3)

博客转载自:http://www.pclcn.org/study/shownews.php?lang=cn&id=262

bilateral.hpp

最后需要编写的是.hpp文件,完成对声明函数的具体实现,这里我们需要实现两个方法,就是applyFilter和computePointWeight。

template<typename PointT>double
 pcl::BilateralFilter<PointT>::computePointWeight (const int pid,const std::vector<int> &indices,const std::vector<float> &distances)
 {
double BF =0, W =0;
 
// For each neighbor
for (size_t n_id =0; n_id < indices.size (); ++n_id)
   {
double id = indices[n_id];
double dist = std::sqrt (distances[n_id]);
double intensity_dist = abs (input_->points[pid].intensity - input_->points[id].intensity);
 
double weight = kernel (dist, sigma_s_) * kernel (intensity_dist, sigma_r_);
 
     BF += weight * input_->points[id].intensity;
     W += weight;
   }
return (BF / W);
 }
 
template<typename PointT>void
 pcl::BilateralFilter<PointT>::applyFilter (PointCloud &output)
 {
   tree_->setInputCloud (input_);
 
   std::vector<int> k_indices;
   std::vector<float> k_distances;
 
output=*input_;
 
for (size_t point_id =0; point_id < input_->points.size (); ++point_id)
   {
     tree_->radiusSearch (point_id, sigma_s_ *2, k_indices, k_distances);
 
output.points[point_id].intensity = computePointWeight (point_id, k_indices, k_distances);
   }
 
 }

computePointWeight方法应该很简单因为它几乎和实例计算代码一样,通过传递一个要计算强度重量的point索引,索引所指示的点是由欧氏空间的邻域组成。在applyFilter中,我们首先利用输入数据构建Kd树,把所有输入数据拷贝到输出,然后开始计算新的点的强度,赋值于输出点云数据output。是时候为该类声明PCL_INSTANTIATE来实例化模板类了:

#ifndef PCL_FILTERS_BILATERAL_IMPL_H_
 #define PCL_FILTERS_BILATERAL_IMPL_H_
 #include <pcl/filters/bilateral.h>
 ...
 #define PCL_INSTANTIATE_BilateralFilter(T) template class PCL_EXPORTS pcl::BilateralFilter<T>;
 #endif // PCL_FILTERS_BILATERAL_H_

需要做的另一件事就是检查错误:

  ·是否给定了sigma_s_和sigma_r_两个参数;

  ·是否设置了搜索方法的对象(例如,tree_)。

对于前者,检查sigma_s_的值,它默认被设置成0,它对算法的行为有十分重要的意义(它实际上是定义了算法所支持滤波的范围大小),因此,如果代码执行的时候其值仍然是0,我们就用宏PCL_ERROR打印一个错误并返回。

就搜索方法来说,我们可以做同样的操作,或者为用户提供默认的选项,最好的默认选项是:

  ·如果点云是有序的,通过pcl::OrganizedDataIndex使用有序搜索方法;

  ·如果点云是无序的,通过pcl::KdTreeFLANN使用通用的Kd树。

#include <pcl/kdtree/kdtree_flann.h>
 #include <pcl/kdtree/organized_data.h>
 
...
template<typename PointT>void
pcl::BilateralFilter<PointT>::applyFilter(PointCloud &output)
{
if(sigma_s_==0)
{
PCL_ERROR("[pcl::BilateralFilter::applyFilter] Need a sigma_s value given before continuing.\n");
return;
}
if(!tree_)
{
if(input_->isOrganized())
tree_.reset(new pcl::OrganizedDataIndex<PointT>());
else
tree_.reset(new pcl::KdTreeFLANN<PointT>(false));
}
tree_->setInputCloud(input_);
...

这样该模板类完整的实现头文件见本章源码文件1.0文件夹下的bilateral.hpp。

利用PCL其他机制

点索引机制,向PCL算法传递点云数据的标准方法是通过访问setInputCloud()。另外,PCL也可通过setIndices()传递用户感兴趣区域或点云集,而不是整个点云。所有的类都从PCLBase继承了以下行为:如果用户没有给出一点的索引,类就会建立一个虚的索引并且在算法的整个运行期间使用。这意味着我们能够很容易地改变上面的实现代码来对<cloud, indices>元组进行操作。这样的好处,就是如果用户确实传递了点的索引,将会使用传递索引对应的点云,如果没有传递,将使用整个点云。

新的bilateral.hpp类就成为下面这样子:

#include <pcl/kdtree/kdtree_flann.h>
 #include <pcl/kdtree/organized_data.h>
 
 ...
template<typename PointT>void
 pcl::BilateralFilter<PointT>::applyFilter (PointCloud &output)
 {
if (sigma_s_ ==0)
   {
     PCL_ERROR ("[pcl::BilateralFilter::applyFilter] Need a sigma_s value given before continuing.\n");
return;
   }
if (!tree_)
   {
if (input_->isOrganized ())
       tree_.reset (new pcl::OrganizedDataIndex<PointT> ());
else
       tree_.reset (new pcl::KdTreeFLANN<PointT> (false));
   }
   tree_->setInputCloud (input_);
 ...

模板类实现头文件就编写如本章源码文件2.0文件夹下bilateral.hpp。

为了使indices_不用键入整个约束就能运行,我们需要给bilateral.h文件增加一行using语句来指示indices_的位置:

...
template<typename PointT>
class BilateralFilter:public Filter<PointT>
   {
using Filter<PointT>::input_;
using Filter<PointT>::indices_;
public:
       BilateralFilter () : sigma_s_ (0),
 ...

敬请关注PCL(Point Cloud Learning)中国更多的点云库PCL(Point Cloud Library)相关官方教程。

 

参考文献:

1.朱德海、郭浩、苏伟.点云库PCL学习教程(ISBN 978-7-5124-0954-5)北京航空航天出版社2012-10

posted @ 2018-03-18 17:40  采男孩的小蘑菇  阅读(498)  评论(0编辑  收藏  举报