2D曲线点云,含许多噪声,采用类似移动最小二乘的方法(MLS)分段拟合抛物线并投影至抛物线,进行点云平滑去噪。

更通俗的说法是让有一定宽度的曲线点云,变成一条细曲线上的点。

分两种情况进行讨论:

1)曲线前进方向与Y轴偏离较远;采用y=ax^{2}+bx+c

2)曲线前进方向与Y轴较近;采用x=ay^{2}+by+c

注意 这里并没有采取二阶多项式拟合的形式,ax^2+bxy+cy^2+dx+ey+f=0,因为这样可能导致过拟合,使用抛物线拟合可以让数据分布在曲线两侧,更符合曲线平滑的需求。

代码如下:

#pragma once
#include"common.h"
#include"CommonFunctions.h"#include <vector>
#include <cmath>
#include <algorithm>
#include <Eigen/Dense> // 需要Eigen库,用于矩阵运算class PointCloudSmoother {
public:static void smooth(std::vector<pcl2d::Point2d>& points, double radius, int iterations) {if (points.empty() || iterations <= 0) return;std::vector<pcl2d::Point2d> smoothed_points = points;for (int iter = 0; iter < iterations; ++iter) {//#pragma omp parallel forfor (size_t i = 0; i < points.size(); ++i) {// 1. 寻找邻域点std::vector<size_t> neighbors = findNeighbors(smoothed_points, i, radius);if (neighbors.size() < 5) continue; // 至少需要5个点才能拟合曲线// 2. 计算局部曲率double curvature = computeLocalCurvature(smoothed_points, neighbors);// 3. 曲率自适应MLS平滑smoothed_points[i] = mlsSmoothing(smoothed_points, i, neighbors, radius, curvature);}}points = smoothed_points;// 点云去重(基于距离阈值) filterPointsByRadius(points, 0.02);}// 计算局部曲率static double computeLocalCurvature(const std::vector<pcl2d::Point2d>& points, const std::vector<size_t>& neighbors) {if (neighbors.size() < 3) return 0.0;// 计算质心pcl2d::Point2d centroid(0, 0);for (size_t idx : neighbors) {centroid.x += points[idx].x;centroid.y += points[idx].y;}centroid.x /= neighbors.size();centroid.y /= neighbors.size();// PCA分析Eigen::Matrix2d cov = Eigen::Matrix2d::Zero();for (size_t idx : neighbors) {double dx = points[idx].x - centroid.x;double dy = points[idx].y - centroid.y;cov(0, 0) += dx * dx;cov(0, 1) += dx * dy;cov(1, 0) += dy * dx;cov(1, 1) += dy * dy;}// 计算特征值Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> solver(cov);Eigen::Vector2d eigenvalues = solver.eigenvalues();// 曲率估计 = 最小特征值 / (最大特征值 + 最小特征值)double min_eig = std::min(eigenvalues[0], eigenvalues[1]);double max_eig = std::max(eigenvalues[0], eigenvalues[1]);return min_eig / (max_eig + min_eig + 1e-6); // 避免除以零}private:// 寻找邻域点(实际应用中应使用空间索引加速)static std::vector<size_t> findNeighbors(const std::vector<pcl2d::Point2d>& points, size_t idx, double radius) {std::vector<size_t> neighbors;const pcl2d::Point2d& center = points[idx];for (size_t i = 0; i < points.size(); ++i) {double dx = points[i].x - center.x;double dy = points[i].y - center.y;double dist = std::sqrt(dx * dx + dy * dy);if (dist < radius) {neighbors.push_back(i);}}return neighbors;}// 移动最小二乘平滑static pcl2d::Point2d mlsSmoothing(const std::vector<pcl2d::Point2d>& points, size_t idx,const std::vector<size_t>& neighbors, double radius, double curvature) {const pcl2d::Point2d& center = points[idx];// 曲率自适应参数double sigma_s = radius * (1.0 - 0.5 * curvature); // 空间权重参数double sigma_r = 0.1 * radius * (1.0 + curvature); // 值域权重参数构建加权最小二乘问题//Eigen::MatrixXd A(neighbors.size(), 6);//Eigen::VectorXd b_x(neighbors.size());//Eigen::VectorXd b_y(neighbors.size());//Eigen::VectorXd weights(neighbors.size());std::vector<pcl2d::Point2d> neighbor_pos;for (size_t i = 0; i < neighbors.size(); ++i) {size_t n_idx = neighbors[i];const pcl2d::Point2d& p = points[n_idx];neighbor_pos.push_back(p);}double a = 0, b = 0, c = 0;auto type = fitParabola(neighbor_pos, a, b, c);return ((type == FUNC_TYPE_FX) ? projectToParabola_fx(points[idx], a, b, c) : projectToParabola_fy(points[idx], a, b, c));}// 判断点集拟合的直线是否接近 y 轴static bool isLineCloseToYAxis(const std::vector<pcl2d::Point2d>& points, double threshold = 10.0){if (points.size() < 2) return false; // 至少需要2个点// 1. 最小二乘法拟合直线 y = kx + bdouble sum_x = 0.0, sum_y = 0.0, sum_xy = 0.0, sum_xx = 0.0;for (const auto& p : points) {sum_x += p.x;sum_y += p.y;sum_xy += p.x * p.y;sum_xx += p.x * p.x;}double n = points.size();double k = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x);// 2. 判断斜率绝对值是否大于阈值return std::abs(k) > threshold;}enum FUNC_TYPE{FUNC_TYPE_FX, // y = ax² + bx + cFUNC_TYPE_FY  // x = ay² + by + c};// 拟合抛物线 static FUNC_TYPE fitParabola(const std::vector<pcl2d::Point2d>& points, double& a, double& b, double& c) {const int n = points.size();Eigen::MatrixXd A(n, 3);Eigen::VectorXd b_vec(n);FUNC_TYPE type = isLineCloseToYAxis(points)? FUNC_TYPE_FY : FUNC_TYPE_FX;// 构建最小二乘问题 Ax = bfor (int i = 0; i < n; ++i) {double x = points[i].x;b_vec[i] = points[i].y;if(type == FUNC_TYPE_FY){x = points[i].y;b_vec[i] = points[i].x;}A(i, 0) = x * x;A(i, 1) = x;A(i, 2) = 1.0;}// 求解最小二乘问题Eigen::Vector3d coeffs = A.colPivHouseholderQr().solve(b_vec);a = coeffs[0];b = coeffs[1];c = coeffs[2];return type;}// 计算点在抛物线上的投影 y = ax² + bx + cstatic pcl2d::Point2d projectToParabola_fx(const pcl2d::Point2d& point, double a, double b, double c) {double x = point.x;double y = a * x * x + b * x + c;return pcl2d::Point2d(x, y);}// 计算点在抛物线上的投影 x = ay² + by + cstatic pcl2d::Point2d projectToParabola_fy(const pcl2d::Point2d& point, double a, double b, double c) {double y = point.y;double x = a * y * y + b * y + c;return pcl2d::Point2d(x, y);}
};

可以优化的方向

拟合时考虑距离相关权重,考虑曲率值相关的权重。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/84659.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/84659.shtml
英文地址,请注明出处:http://en.pswp.cn/web/84659.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【平面波导外腔激光器专题系列】用于精密测量的平面波导外腔激光器特性

----翻译自Kenji Numata等人的文章 摘要 1542 nm平面波导外腔激光器PW-ECL具有足够低的噪声非常适合精密测量应用。与 0.1mHz至100kHz 之间&#xff0c;其频率和强度噪声与非平面环形振荡器 NPRO和光纤激光器相当或更好。通过将 PW-ECL 的频率稳定在乙炔&#xff08;13C2H2&a…

文件时间修改器

文件时间修改器是一款帮助用户修改文件创建时间的软件&#xff0c;支持毫秒级时间的修改&#xff0c;包括文件的创建时间、修改时间、访问时间等时间都支持修改&#xff0c;可以批量处理文件。 飞猫云下载 | 备用下载1 |备用下载2 基本简介 本软件主要为批量修改文件的创建时…

仓颉语言实战:MQTT物联网开发

目录 引言 mqtt4cj库的使用 申请仓颉编程语言内测 下载STDX 测试程序 结束语 引言 最近一直在学习仓颉语言&#xff0c;由于我对物联网比较感兴趣&#xff0c;自然想到写一个MQTT的程序&#xff0c;好在找到了mqtt4cj库&#xff0c;今天分享一下学习心得。 mqtt4cj库的…

OpenCV CUDA模块设备层-----用于在 CUDA 核函数中访问纹理数据的一个封装类TexturePtr()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 TexturePtr<T, R> 是 OpenCV 的 opencv_cudev 模块中用于在 CUDA 核函数中访问纹理数据的一个封装类。它主要用于将一个已创建好的 cudaTe…

Spring Boot的自动装配和自动配置

Spring Boot的自动装配&#xff08;Auto Wiring&#xff09;和自动配置&#xff08;Auto Configuration&#xff09;是两个不同的概念&#xff0c;它们在Spring框架中各自有不同的作用和用途。下面我将详细解释它们的区别和联系。 自动装配&#xff08;Auto Wiring&#xff09…

如何用 vue-office 快速搭建文档在线预览服务

1. 什么是 vue-office 1.1 vue-office 简介 vue-office 是一个基于 Vue 的组件库,用于在 Web 应用中快速集成 Office 文档的在线预览功能。它支持 Word、Excel 和 PowerPoint 等多种格式,并提供了简洁的 API 接口和丰富的自定义选项。 1.2 支持的文档类型与核心特性 支持的…

Python爬虫(六):Scrapy框架

"Scrapy到底该怎么学&#xff1f;"今天&#xff0c;我将用这篇万字长文&#xff0c;带你从零开始掌握Scrapy框架的核心用法&#xff0c;并分享我在实际项目中的实战经验&#xff01;建议收藏⭐&#xff01; 一、Scrapy简介&#xff1a;为什么选择它&#xff1f; 1.…

Linux中关闭swap分区

在 Linux 系统中关闭 swap 分区&#xff08;或交换文件&#xff09;的步骤如下&#xff0c;请务必在操作前保存所有数据&#xff0c;以免丢失&#xff1a; &#x1f4cc; 完整操作步骤&#xff1a; 1. 查看当前 swap 使用情况 free -h swapon --show # 查看活跃的 swap 设…

RPGMZ游戏引擎之如何设计每小时开启一次的副本

本文知识点 1. 获取时间 2. 时间格式要正确 3. 事件内如何设计 正文开始 1. 获取时间 首先获取当前时间 然后保存在 事件内的变量里面 后需要判断时间是否相等 function 获取当前日期(){const now new Date();return now.toISOString();}; 2. 时间格式要正确 now.toI…

学习路之uniapp--uniapp扩展uni-ui

这里写目录标题 一、新建项目二、下载导入插件三、直接创建uni-ui项目 一、新建项目 二、下载导入插件 三、直接创建uni-ui项目 创建uniapp项目时&#xff0c;直接创建uni-ui项目

Kotlin 2.6 猜数小游戏

本次实战通过开发猜数小游戏&#xff0c;深入学习了 Kotlin 编程的循环控制和条件判断。游戏要求计算机随机生成一个数字&#xff0c;用户通过输入猜测&#xff0c;程序根据猜测结果给出提示&#xff0c;直到猜中为止。通过实现这一过程&#xff0c;我们掌握了如何使用 while 循…

RNN工作原理和架构

## 1. 什么是 RNN&#xff1f; * **全称&#xff1a;** Recurrent Neural Network&#xff08;循环神经网络&#xff09; * **核心特点&#xff1a;** 它是一种专门设计用来处理**序列数据**的神经网络。 * **核心能力&#xff1a;** 拥有“记忆”能力&#xff0c;能够利用**…

智能计算模拟:第一性原理+分子动力学+机器学习

第一性原理分子动力学机器学习”三位一体的综合手段&#xff0c;已经成为模拟计算的一个前沿方向&#xff0c;为解决传统计算化学方法面临的挑战提供了新的解决方案。国内外已有科研团队在深化第一性原理与分子动力学的研究与应用拓展&#xff0c;利用机器学习优化大规模计算、…

基于Attention机制的模型。这使得它摆脱了RNN模型顺序读取序列的缺点,可以实现高度的并行化的理解

这句话的核心意思是:​​该模型完全基于注意力机制(Attention Mechanism),不再依赖传统的循环神经网络(RNN)结构,因此避免了 RNN 的顺序计算问题,能够实现高效的并行化计算​​。我们可以从以下几个方面深入理解: 1. ​​"仅基于 Attention 机制"​​ ​​传…

解决虚拟机 Kali 系统安装了VMware Tools 不能拖入文件问题

进入终端&#xff0c;这里我是root模式下&#xff0c;不是root模式在命令前加一个sudo即可&#xff0c;命令如下&#xff1a; apt install open-vm-tools open-vm-tools-desktop 执行成功后输入 reboot 重启后即可

GitHub OAuth 认证示例

GitHub链接&#xff1a;github_auth 流程图 功能特性 ✅ GitHub OAuth 认证✅ 获取用户基本信息✅ 显示用户的 GitHub 仓库列表✅ 安全的会话管理✅ 响应式用户界面 技术栈 后端 Flask - Python Web 框架Flask-CORS - 跨域资源共享Requests - HTTP 库Session - 会话管理 …

百度萝卜快跑携4颗禾赛激光雷达进军迪拜,千辆L4无人车开启全球化战略

3月28日,百度旗下自动驾驶出行服务平台“萝卜快跑”宣布在迪拜市区启动无人驾驶规模化测试及服务,计划部署超1000辆L4级全无人驾驶汽车。此次出海不仅是萝卜快跑首次在中国以外地区实现规模化落地,更以“单车搭载4颗禾赛激光雷达”的硬件配置引发行业关注,标志着中国自动驾…

湖北师范大学人工智能与计算机学院电子信息研究生课程《随机过程》第六次作业

一. 计算题&#xff08;共10题&#xff0c;100分&#xff09; 1. (计算题, 10分)随机信号 的实测样本函数如题图(a)与(b)所示&#xff0c; &#xff0c;期中X为随机变量&#xff0c; &#xff0c;试说明它们可能是均值各态历经的吗&#xff1f;&#xff08;写明道理&#xff…

解决Windows Server打开DNS提示“拒绝访问”和“RPC服务器不可用”

问题背景 在一个活动目录域xyzz.internal中&#xff0c;有两台域控制器&#xff08;Domain Controller&#xff09;&#xff0c;各位于一个站点。 问题 当我们在其中一台域控制器上的服务器管理器中打开DNS管理工具时&#xff0c;却看到类似如下错误&#xff0c;提示拒绝访问…

Python中字符串常用的操作方法

在Python中&#xff0c;字符串是不可变序列类型&#xff0c;提供了丰富的内置方法。以下是常用的字符串操作方法及示例&#xff1a; 1. 大小写转换 lower() 转小写 upper() 转大写 capitalize() 首字母大写 title() 每个单词首字母大写 swapcase() 大小写互换 print(&q…