一、主要函数
头文件
#include <CGAL/remove_outliers.h>
函数
PointRange::iterator CGAL::remove_outliers ( PointRange & points,
unsigned int k,
const NamedParameters & np = parameters::default_values()
)
计算到最近邻居的平均平方距离,并使用平均距离的阈值或选择具有最高平均距离的点的固定百分比来划分点。该方法修改输入点的顺序,以便首先打包所有剩余的点,并在第一个点上返回要删除的迭代器。由于这个原因,它不应该在已排序的容器上调用。
可以使用两个阈值:threshold_percent
和threshold_distance
。这个函数返回最小数量的异常值,以便至少满足这些阈值中的一个。这意味着如果threshold_percent=100
,则只考虑threshold_distance
;如果threshold_distance=0
,则只考虑threshold_percent
。
二、代码实现
#include <vector>
#include <iostream>
#include <CGAL/property_map.h>
#include <CGAL/compute_average_spacing.h>
#include <CGAL/IO/read_points.h>
#include <CGAL/IO/write_points.h>
#include <CGAL/remove_outliers.h> // 点云去噪
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
int main(int argc, char* argv[])
{
const std::string fname = CGAL::data_file_path("cgal//oni.pwn");
// ------------------------------加载点云----------------------------------
std::vector<Kernel::Point_3> points;
if (!CGAL::IO::read_points(fname, std::back_inserter(points),
CGAL::parameters::point_map(CGAL::Identity_property_map<Kernel::Point_3>())))
{
std::cerr << "点云读取失败" << fname << std::endl;
return -1;
}
// Removes outliers using erase-remove idiom.
// The Identity_property_map property map can be omitted here as it is the default value.
const int nb_neighbors = 24; // 邻域点个数
// 计算平均密度
const double average_spacing = CGAL::compute_average_spacing<CGAL::Sequential_tag>(points, nb_neighbors);
std::vector<Kernel::Point_3>outLier;
bool outPercent = true; // 离群点百分比是否已知
if (outPercent == false)
{
// -------------------------离群点所占百分比未知---------------------------
std::vector<Kernel::Point_3>::iterator first_to_remove = CGAL::remove_outliers<CGAL::Parallel_if_available_tag>
(points, nb_neighbors,
CGAL::parameters::threshold_percent(100.). // 百分比为100,则只考虑距离
threshold_distance(2. * average_spacing)); // 距离设置为平均密度的2倍
std::cerr << (100. * std::distance(first_to_remove, points.end()) / static_cast<double>(points.size()))
<< "% of the points are considered outliers when using a distance threshold of "
<< 2. * average_spacing << std::endl;
outLier.swap(points);
}
else
{
// --------------------------知道离群点所占百分比----------------------------
const double removed_percentage = 5.0; // 百分之五的离群点需要移除
points.erase(CGAL::remove_outliers<CGAL::Parallel_if_available_tag>
(points,
nb_neighbors,
CGAL::parameters::threshold_percent(removed_percentage). // 按最小百分比剔除异常值
threshold_distance(0.)), // 距离阈值设置为0
points.end());
// Optional: after erase(), use Scott Meyer's "swap trick" to trim excess capacity
outLier.swap(points);
}
// -------------------------------------保存结果----------------------------------
if (!CGAL::IO::write_points("cgal//oni_outlier.xyz", outLier,
CGAL::parameters::point_map(CGAL::Identity_property_map<Kernel::Point_3>())
.stream_precision(10)))
{
std::cerr << "保存失败!!!" << std::endl;
return -1;
}
return 0;
}
三、结果展示
1、滤波前
2、滤波后