一、点云滤波降噪算法
统计滤波:
概念:去除明显分布稀疏的离群点。根据给定的均值和方差去除方差之外的点。
步骤:对每个点都计算最近的K个点的距离,求个平均值。此时点云里每个点都有一个平均值。算所有的均值和方差,然后根据123方差阈值来滤除离群点。
当判断点的k近邻平均距高(mean distance)大于全局的1倍标准差+平均距离(global distances meanm and standard),则为离群点。
直通滤波:
根据点云的属性,设置一个范围,来进行滤除。比如常见的xyz范围。
半径滤波:
设定一个半径R,统计在其R内的点的个数,小于阈值则为离群点。
中值滤波:
用于去除图像或者信号中的噪声。具体实现是将像素值替换为滑动窗口里的中间值来实现滤波。
因为其选择中值作为替代,所以不受异常值影响。
均值滤波:
通过计算领域窗口内的平均值来替换像素值达到去噪的效果,但是会破坏图像细节,使得图像变得模糊。起到平滑图像和信号的效果。
高斯滤波:
用于平滑图像并减少图像中的噪声。首先确定高斯核的大小和标准差,标准差决定高斯核的形状以及平滑程度。根据这两个生成二维高斯权值矩阵,进行卷积。标准差越大,越模糊。高斯核越大越模糊。
二、点云降采样算法
1.随机降采样
2.体素降采样
分两种,将点云变为体素之后,可以在每个体素里随机选择一个点,这样快,也可以在体素里求一个平均值。
3.最远点降采样
每次选取一个点,下次找剩下的离他最远的那个点,不断迭代。容易受到噪声点影响,可以将一些密集的点去掉。
三、点云聚类算法
1.K-means聚类算法
K未知需要人为设置,可以使用手肘法,遍历K的大小取loss最低的。
对于初始点比较敏感,可以多选择几种初始化方法,最终选择loss最小的。
对于噪声点问题,可以选取类里到其他点距离最短的那个点作为中心点,而不是求均值。
算法流程:首先随机选取K个中心点,然后计算每个点距离哪个中心点最近,就属于哪一类。然后计算每个类的平均值,作为新的中心点,开始迭代。直到一定次数或者这个中心点变化很小。
算法复杂度为:t(迭代次数) * k(中心点个数)* N(点总数)* d(每个点的维度)。
2.Mean-shift聚类算法
随机选择一个点作为球心,半径为R,然后求半径内的点平均值,作为新的中心点,就这样不断迭代。直到中心点不再变化或变化很小。过程中的所有点都归为这一类。然后判断收敛的中心点与已经存在的中心点距离是否大于阈值,不是就合并。
因为meanshift每迭代一次都要计算这个中心点与其他所有点的距离,很耗时。而我们的思路是,所有点来找已经存在的中心点,这样耗时很少。
简化版本:遍历数据,计算数据与已经存在的中心点的距离,如果小于阈值就归为一类,然后更新该类新的中心值。
3.DBSCAN聚类算法
自带滤波的聚类算法。首先设置半径R,半径里面点数少于一定的为噪声点,其余为核心点,基于密度的聚类算法,核心点半径内的核心点为一类,然后迭代R内的其他核心点,也都为这一类。直到R内只有此核心点为止。从所有点里移除此类点,继续上面的迭代。
R选择技巧:一般先选一个点,计算它与其他所有点的距离,然后排序,找到前后变化很大的一处,然后R就选则突变点即可。这个选的太大,簇就少,选的太小,簇就多,可以适当调整
min_point一般这个值都偏小,可以多次尝试一下。文章来源:https://www.toymoban.com/news/detail-578857.html
四、点云分割算法
1.Ransac
是一种随机抽样算法,从样本里不断的随机采样,然后计算离群误差。只要属于采样方程里的内点数大于一定阈值就直接退出。文章来源地址https://www.toymoban.com/news/detail-578857.html
#include <iostream>
#include <vector>
#include <cmath>
#include <random>
struct Point {
double x;
double y;
};
// 计算两点之间的距离
double distance(const Point& p1, const Point& p2) {
return std::sqrt(std::pow(p2.x - p1.x, 2) + std::pow(p2.y - p1.y, 2));
}
// 使用 RANSAC 算法拟合直线
void ransacLineFitting(const std::vector<Point>& points,
int maxIterations,
double distanceThreshold,
double inlierRatioThreshold,
std::vector<Point>& inliers,
double& slope,
double& intercept) {
std::random_device rd;
std::mt19937 rng(rd());
std::uniform_int_distribution<int> uni(0, points.size() - 1);
int bestInlierCount = 0;
for (int iteration = 0; iteration < maxIterations; ++iteration) {
// 随机选择两个点
int index1 = uni(rng);
int index2 = uni(rng);
const Point& p1 = points[index1];
const Point& p2 = points[index2];
// 计算斜率和截距
slope = (p2.y - p1.y) / (p2.x - p1.x);
intercept = p1.y - slope * p1.x;
// 用于保存内点
std::vector<Point> currentInliers;
for (const Point& point : points) {
// 计算点到直线的距离
double d = std::abs(point.y - slope * point.x - intercept);
// 判断是否是内点
if (d < distanceThreshold) {
currentInliers.push_back(point);
}
}
// 更新最佳内点数和内点集合
if (currentInliers.size() > bestInlierCount) {
bestInlierCount = currentInliers.size();
inliers = std::move(currentInliers);
// 计算内点比例
double inlierRatio = static_cast<double>(bestInlierCount) / points.size();
// 如果内点比例达到阈值,提前退出循环
if (inlierRatio > inlierRatioThreshold) {
break;
}
}
}
}
int main() {
// 构造示例数据点云
std::vector<Point> points {
{0.0, 0.5},
{1.0, 2.0},
{2.0, 3.5},
{3.0, 4.5},
{4.0, 6.0},
{5.0, 7.5},
{6.0, 9.0},
{7.0, 10.5}
};
// RANSAC 参数
int maxIterations = 1000; // 最大迭代次数
double distanceThreshold = 0.5; // 内点阈值
double inlierRatioThreshold = 0.8; // 内点比例阈值
// 输出结果保存变量
std::vector<Point> inliers;
double slope, intercept;
// 使用 RANSAC 拟合直线
ransacLineFitting(points, maxIterations, distanceThreshold, inlierRatioThreshold,
inliers, slope, intercept);
// 输出拟合结果
std::cout << "拟合直线方程:y = " << slope << "x + " << intercept << std::endl;
std::cout << "内点数量:" << inliers.size() << std::endl;
return 0;
}
到了这里,关于点云滤波降采样聚类分割整理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!