一、算法原理
基于点云法线的双边滤波,实现对点云的平滑处理。
1、主要函数
头文件
#include <CGAL/bilateral_smooth_point_set.h>
函数
double CGAL::bilateral_smooth_point_set ( PointRange & points,
unsigned int k,
const NamedParameters & np = parameters::default_values()
)
该函数通过迭代地将每个点投影到最近邻拟合的隐式曲面上,来平滑输入点集。双侧投影根据法线(梯度)信息保留尖锐特征。点位和法线都会被修改。函数返回值为平均点移动误差。这是算法的收敛准则。这个值可以帮助用户决定多少次迭代是足够的。
points
:包含法向量信息的点云k
: 隐式曲面拟合的邻域点数。值越大,结果越平滑。np
:下面列出的命名参数中的一个可选序列。
2、参考文献
H. Huang, S. Wu, M. Gong, D. Cohen-Or, U. Ascher, and H. Zhang. Edge-aware point set resampling. ACM Transactions on Graphics, 32:9:1–9:12, 2013.
二、代码实现
#include <utility> // std::pair
#include <fstream>
#include <CGAL/tags.h>
#include <CGAL/property_map.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/IO/read_points.h> // 读取点云
#include <CGAL/IO/write_points.h> // 保存点云
#include <CGAL/bilateral_smooth_point_set.h> // 双边滤波
// Types
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;
// 定义一个pair容器用来存储点坐标和法向量
typedef std::pair<Point, Vector> PointVectorPair;
int main(int argc, char* argv[])
{
// 设置文件读取路径和保存路径
const std::string input_filename = CGAL::data_file_path("cgal//fin90_with_PCA_normals.xyz");
const char* output_filename = "cgal//fin90_with_PCA_normals_bilateral_smoothed.xyz";
// ------------------------------加载含有法线的点云-----------------------------------
std::vector<PointVectorPair> points;
if (!CGAL::IO::read_points(input_filename, std::back_inserter(points),
CGAL::parameters::point_map(CGAL::First_of_pair_property_map<PointVectorPair>())
.normal_map(CGAL::Second_of_pair_property_map<PointVectorPair>())))
{
std::cerr << "点云读取失败" << input_filename << std::endl;
return -1;
}
// -----------------------------------参数设置----------------------------------------
int k = 120; // 邻域点的个数,点数越多越平滑
double sharpness_angle = 25; // 控制结果的平滑度,值越大越平滑
int iter_number = 3; // 应用投影的次数
// ------------------------------基于法线的双边滤波----------------------------------
for (int i = 0; i < iter_number; ++i)
{
CGAL::bilateral_smooth_point_set <CGAL::Parallel_if_available_tag>(
points,
k,
CGAL::parameters::point_map(CGAL::First_of_pair_property_map<PointVectorPair>())
.normal_map(CGAL::Second_of_pair_property_map<PointVectorPair>())
.sharpness_angle(sharpness_angle));
}
// ------------------------------------结果保存--------------------------------------
if (!CGAL::IO::write_XYZ(output_filename, points,
CGAL::parameters::point_map(CGAL::First_of_pair_property_map<PointVectorPair>())
.normal_map(CGAL::Second_of_pair_property_map<PointVectorPair>())
.stream_precision(17)))
return -1;
return 0;
}
三、结果展示
白色为原始点云,红色为平滑之后的点云。