2D曲線點云平滑去噪

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 = ax2 + bx + cFUNC_TYPE_FY  // x = ay2 + 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 = ax2 + 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 = ay2 + 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…