【PCL滤波】统计滤波算法原理及源码详解
·
目录
1. 统计滤波原理
统计滤波假设所有点的 “k 近邻平均距离值”符合正态分布,通过判断某点的“k 近邻平均距离值”是否在设置区间内,以判别该点是否为离群点或噪点。
详细算法过程:
1)计算输入点云所有点的“k 近邻平均距离值” k-distances【符合正态分布】;
2)计算 k-distances 的平均值 mean 和标准差 σ;
3)计算统计距离区间,一般为[mean - k*σ,mean + k*σ],k为自定义系数,进行点云分类。
看PCL源码,步骤3是 d > mean + k*σ 即为噪点。这一块还要再核对下。
2. PCL统计滤波源码详解
PCL实现统计滤波算法的主要接口为 applyFilterIndices
源码路径:GitCode - 全球开发者的开源社区,开源代码托管平台
template <typename PointT> void
pcl::StatisticalOutlierRemoval<PointT>::applyFilterIndices(Indices& indices)
{
// Initialize the search class
// 初始化近邻搜寻对象,常用无序点云
if (!searcher_){
if (input_->isOrganized())
searcher_.reset(new pcl::search::OrganizedNeighbor<PointT>());
else
searcher_.reset(new pcl::search::KdTree<PointT>(false));
}
// 构建kdtree
if (!searcher_->setInputCloud (input_)){
PCL_ERROR ("[pcl::%s::applyFilter] Error when initializing search method!\n", getClassName ().c_str ());
indices.clear ();
removed_indices_->clear ();
return;
}
// The arrays to be used
const int searcher_k = mean_k_ + 1; // mean_k_值要+1,因为近邻搜寻结果包含query点
Indices nn_indices (searcher_k);
std::vector<float> nn_dists (searcher_k);
std::vector<float> distances (indices_->size ()); // 保存每个点对应的K近邻平均距离
indices.resize (indices_->size ());
removed_indices_->resize (indices_->size ());
int oii = 0, rii = 0; // oii = output indices iterator, rii = removed indices iterator
// First pass: Compute the mean distances for all points with respect to their k nearest neighbors
// 第一步:使用for循环【串行】计算每个点的K近邻平均距离,iii = input indices iterator
int valid_distances = 0;
for (int iii = 0; iii < static_cast<int> (indices_->size()); ++iii){
// 数据有效性判断
if (!std::isfinite((*input_)[(*indices_)[iii]].x) ||
!std::isfinite((*input_)[(*indices_)[iii]].y) ||
!std::isfinite((*input_)[(*indices_)[iii]].z)){
distances[iii] = 0.0;
continue;
}
// Perform the nearest k search
// k近邻搜寻
if (searcher_->nearestKSearch((*indices_)[iii], searcher_k, nn_indices, nn_dists) == 0){
distances[iii] = 0.0;
PCL_WARN ("[pcl::%s::applyFilter] Searching for the closest %d neighbors failed.\n", getClassName ().c_str (), mean_k_);
continue;
}
// Calculate the mean distance to its neighbors
// 计算当前点对应的K近邻平均距离;k = 0是当前点,不参与计算
double dist_sum = 0.0;
for (std::size_t k = 1; k < nn_dists.size(); ++k)
dist_sum += sqrt((nn_dists[k]);
distances[iii] = static_cast<float>(dist_sum / (nn_dists.size() - 1));
valid_distances++;
}
// Estimate the mean and the standard deviation of the distance vector
// 计算平均值和标准差
double sum = 0, sq_sum = 0;
for (const float& distance : distances){
sum += distance;
sq_sum += distance * distance;
}
// 平均值 和 方差
double mean = sum / static_cast<double>(valid_distances);
double variance = (sq_sum - sum * sum / static_cast<double>(valid_distances)) / (static_cast<double>(valid_distances) - 1);
double stddev = sqrt(variance);
//getMeanStd (distances, mean, stddev);
// 得到距离阈值
double distance_threshold = mean + std_mul_ * stddev;
// Second pass: Classify the points on the computed distance threshold
// 基于计算的距离阈值,将点云进行分类; // iii = input indices iterator
for (int iii = 0; iii < static_cast<int> (indices_->size()); ++iii) {
// Points having a too high average distance are outliers and are passed to removed indices
// Unless negative was set, then it's the opposite condition
// 大于距离阈值的点视为局外点,negative设置为TRUE,则情况相反
if ((!negative_ && distances[iii] > distance_threshold) || (negative_ && distances[iii] <= distance_threshold)){
if (extract_removed_indices_)
(*removed_indices_)[rii++] = (*indices_)[iii];
continue;
}
// Otherwise it was a normal point for output (inlier)
// 否则就是局内点
indices[oii++] = (*indices_)[iii];
}
// Resize the output arrays
indices.resize(oii);
removed_indices_->resize(rii);
}
更多推荐
所有评论(0)