博客转载自: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. "); 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. "); 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