插值與擬合(3):B樣條曲線

在路徑規劃問題中,通常會用到B樣條來平滑路徑,本文實現并封裝了三次準均勻開放B樣條曲線,供大學學習使用。作者提供了三套代碼方案。可以用于不同平臺:方案1:MATLAB;方案2:標準C++;方案3:在ROS-noetic平臺中基于C++實現,并基于Rviz實現可視化。

本文的代碼有如下優勢:1、即拿即用。程序員僅僅需要提供控制點(control_node)、曲線節點數量(也就是很多博客中提到的u的尺寸),通過兩三行代碼即可實現B樣條;2、可以適用于二維、三維環境。

注意:本文側重于代碼分享,因此對于B樣條曲線的原理不做闡述。(網上有很多講的非常好的博客,作者理論闡述能力有限,故不再班門弄斧)。

提示:關于“三次”“準均勻”“開放(open)”三個前綴,大家可以搜一搜了解即可。大多數場景下我們說的B樣條就是“三次”“準均勻”“開放(open)”B樣條曲線。(這句話不一定嚴謹,個人想法)

下面開始代碼分享:

1?基于MATLAB實現B樣條曲線

如下圖所示,程序員需要修改的主要是:第4行control_node以及第12行path_node_num的值。

clc, clear, close allcontrol_node = [0 0; 1 -2; 2 2; 3 -1; 4 1; 5 0]; % 二維坐標
% control_node = [0 0 0; 
%                 1 -2 -2; 
%                 2 2 3; 
%                 3 -1 4; 
%                 4 1 5; 
%                 5 0 5];path_node_num = 200;n = size(control_node,1)-1; % n+1個控制點
degree = 3; % 最高次冪3
order = 4;  % 階數4; order = degree + 1;u = linspace(0, 1-0.0005, path_node_num);  % !!!注意:如果u的范圍是[0, 1],下面節點向量的范圍也要是0到1
path = zeros(length(u), size(control_node, 2));%% 生成節點向量kontsVector
m = n+1 + degree ;
knotsVector = zeros(n+1+degree+1, 1);
for i= 1:m+1if i <= degree + 1knotsVector(i) = 0;endif i>degree+1 && i<=m-degreeknotsVector(i) = knotsVector(i-1)+1;endif i > m-degreeknotsVector(i) = knotsVector(m-degree)+1;end
end
knotsVector = knotsVector / knotsVector(m+1);%% 獲取準均勻B樣條曲線
for idx = 1 : length(u)for i = 1 : size(control_node, 1)Bik = BaseFunction(i, order-1 , u(idx), knotsVector);path(idx,:) = path(idx,:) + Bik*control_node(i,:);end
endplot(path(:,1), path(:,2),'g--','LineWidth',5);hold on
scatter(control_node(:,1), control_node(:,2),500, '.');function Bik_u = BaseFunction(i, k , u, NodeVector)if k == 0       % 0次B樣條if u >= NodeVector(i) && u < NodeVector(i+1)Bik_u = 1;elseBik_u = 0;end
elseLength1 = NodeVector(i+k) - NodeVector(i);Length2 = NodeVector(i+k+1) - NodeVector(i+1);      % 支撐區間的長度if Length1 == 0       % 規定0/0 = 0Length1 = 1;endif Length2 == 0Length2 = 1;endBik_u = (u - NodeVector(i)) / Length1 * BaseFunction(i, k-1, u, NodeVector) ...+ (NodeVector(i+k+1) - u) / Length2 * BaseFunction(i+1, k-1, u, NodeVector);
end
end

下面兩張圖分別是二維和三維環境下的效果:

2 基于標準C++實現B樣條曲線

主要包括bspline.h、bspline.cpp以及main.cpp三個代碼文件。主要需要在main.cpp中進行三處修改:

第7行:Eigen::MatrixXd control_node(6, 2);其中6表示控制點數量,2表示維度,這兩個參數供程序員修改;

第8行:程序員提供控制點

第14行:提供path_node_num,即路徑節點數量。

2.1 首先是bspline.h

#ifndef __BSPLINE_H__
#define __BSPLINE_H__#include <iostream>
#include <eigen3/Eigen/Eigen>
#include <vector>class Bspline
{
public:Bspline(){};~Bspline(){};/* 啟動B樣條 */void Bspline_start();/* 獲取控制點、最高次冪、離散點的數量*/Bspline(Eigen::MatrixXd control_node, int degree, int num);/* 生成節點向量 */void get_konts();/* 獲取準均勻B樣條 */void get_bspline_curve();/* 基函數 */double BaseFunction(int i, int k, double u, std::vector<double> konts_vector);
private:Eigen::MatrixXd m_control_node;Eigen::MatrixXd m_path;// double int m_degree, m_order, m_num, m;std::vector<double> konts_vector;std::vector<double> u;
};#endif

2.2 之后是bspline.cpp

#include "bspline.h"Bspline::Bspline(Eigen::MatrixXd control_node, int degree, int num)
{this->m_control_node = control_node;        // 獲取控制點this->m_degree = degree;                    // B樣條的次數this->m_order = this->m_degree + 1;         // B樣條的階數this->m_num = num;                          // 路徑點的數量int n = this->m_control_node.rows() - 1;    // n+1個控制點this->m = n + 1 + this->m_degree;           // m + 1 = n + 1 + degree + 1// 確定uthis->u.resize(this->m_num);for(int i=0; i<m_num; i++){u[i] = 0 + (1.0-0.005)/(m_num-1) * i;}this->m_path.setZero(this->m_num, this->m_control_node.cols());// 初始化路徑
}void Bspline::Bspline_start()
{this->get_konts();this->get_bspline_curve();
}void Bspline::get_konts()
{this->konts_vector.resize(this->m + 1);for(int i = 0; i<=m; i++){if(i <= this->m_degree){this->konts_vector[i] = 0;}if(i > this->m_degree && i< (this->m - this->m_degree)) {this->konts_vector[i] = this->konts_vector[i-1]+1;}if(i >= (this->m - this->m_degree)){this->konts_vector[i] = this->konts_vector[this->m - this->m_degree -1] + 1;}}for(int i=0; i<=m; i++){this->konts_vector[i] = this->konts_vector[i] / this->konts_vector[m];}
}void Bspline::get_bspline_curve()
{double Bik;for(int idx = 0; idx<this->u.size(); idx++){for(int i=0; i<this->m_control_node.rows(); i++){Bik = BaseFunction(i, this->m_degree, this->u[idx], this->konts_vector);for(int j=0; j<this->m_control_node.cols(); j++){this->m_path(idx,j) = this->m_path(idx,j) + Bik*this->m_control_node(i,j);}}}// std::cout << this->m_path ;
}double Bspline::BaseFunction(int i, int k, double u, std::vector<double> konts_vector)
{double Bik_u;if(k==0){if(u>=konts_vector[i] && u<konts_vector[i+1])return Bik_u = 1.0;elsereturn Bik_u = 0.0;}else{double length1 = konts_vector[i+k] - konts_vector[i];double length2 = konts_vector[i+k+1] - konts_vector[i+1];if(length1==0){length1=1;}if(length2==0){length2=1;}return Bik_u = (u - konts_vector[i])/length1 * BaseFunction(i,k-1,u,konts_vector) + (konts_vector[i+k+1]-u) / length2 * BaseFunction(i+1,k-1,u,konts_vector);}
}

2.3 最后是main.cpp

#include <iostream>
#include "bspline.h"
#include <eigen3/Eigen/Eigen>int main()
{Eigen::MatrixXd control_node(6, 2);control_node << 0, -2,10, -2,25, -2,25, 0,40, 0,50, 0;int path_node_num = 200;Bspline bspline(control_node, 3, path_node_num);bspline.Bspline_start();return 0;
}

3?ROS-noetic+Rviz+C++實現B樣條曲線

這一部分主要包括bspline.h、bspline.cpp以及main.cpp三個代碼文件。其中,bspline.h、bspline.cpp跟標準C++代碼完全一致,讀者復制粘貼即可,因此只提供main.cpp文件,內容如下。可供修改的地方主要是三點:

第16行:Eigen::MatrixXd control_node(6, 2);其中6表示控制點數量,2表示維度,這兩個參數供程序員修改;注意如果是二維,要把第29行 cloud.points[i].z 設置為0.0。

第17行:程序員提供控制點

第29行:提供path_node_num,即路徑節點數量。

注意:這段代碼需要讀者有基本的ROS和Rviz知識。

#include <ros/ros.h>
#include <sensor_msgs/PointCloud2.h>
#include <pcl/point_cloud.h>
#include <pcl_conversions/pcl_conversions.h>
#include <eigen3/Eigen/Eigen>
#include "bspline.h"
#include <vector>int main(int argc, char *argv[])
{ros::init(argc, argv, "main_node");ros::NodeHandle nh;ros::Publisher pcl_pub = nh.advertise<sensor_msgs::PointCloud2>("path", 10);/* 將路徑節點傳給cloud */Eigen::MatrixXd control_node(6, 3);control_node << 0, -2, -2,1, -2, 4,2.5, -2, 1,2.5, 0, 0,4.0, 0, 2,5.0, 0, 0;   // 3-dim 地圖// control_node << 0, 0,//                 1, 4,//                 2, 2,//                 3, 3,//                 4.0, 1,//                 5.0, 5;   // 2-dim 地圖int path_node_num = 200;     // 散點數量Bspline bspline(control_node, 3, 200);Eigen::MatrixXd path = bspline.Bspline_start();pcl::PointCloud<pcl::PointXYZ> cloud;cloud.points.resize(path.rows());for(size_t i=0; i<cloud.points.size(); i++){cloud.points[i].x = path(i,0);cloud.points[i].y = path(i,1);cloud.points[i].z = path(i,2);}sensor_msgs::PointCloud2 output;pcl::toROSMsg(cloud, output);output.header.frame_id = "map";output.header.stamp = ros::Time::now();while(ros::ok()){   ROS_INFO("path pub...");pcl_pub.publish(output);ros::spinOnce();}return 0;
}

既然涉及到ROS,還需要配置一下CMakeLists文件,配置如下:

cmake_minimum_required(VERSION 3.0.2)
project(pcl_pkg)find_package(catkin REQUIRED COMPONENTSpcl_rosroscpprospysensor_msgsstd_msgs
)include_directories(
# include${catkin_INCLUDE_DIRS}${CMAKE_CURRENT_SOURCE_DIR}/include
)add_executable(main_node src/main.cpp src/bspline.cpp) 
target_link_libraries(main_node ${catkin_LIBRARIES} )

下面兩張圖分別是Rviz中二維和三維環境下的效果:

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/88032.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/88032.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/88032.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[免費]基于Python豆瓣電影數據分析及可視化系統(Flask+echarts+pandas)【論文+源碼+SQL腳本】

大家好&#xff0c;我是java1234_小鋒老師&#xff0c;看到一個不錯的于Python豆瓣電影數據分析及可視化系統(Flaskechartpandas)【論文源碼SQL腳本】&#xff0c;分享下哈。項目介紹隨著如今電影越來越多&#xff0c;各種各樣的爛片和撈錢的商業片也層出不窮&#xff0c;而有意…

SQL127 月總刷題數和日均刷題數

SQL127 月總刷題數和日均刷題數 withtemp as (selectDATE_FORMAT(submit_time, "%Y%m") as submit_month,count(question_id) as month_q_cnt,round(count(question_id) / day(last_day(max(submit_time))),3) as avg_day_q_cntfrompractice_recordwhereyear(submit…

unity luban接入

1.找到luban官網并下載他的例子和.net8.0的sdk安裝 官網地址如下 快速上手 | Luban 參考大佬教程如下 Luban新版本接入教程_嗶哩嗶哩_bilibili 2.找到他的luban_examples-main示例下的兩個文件MiniTemplate和tool 3.MiniTemplate這個文件復制一份到項目工程下&#xff0c;自…

Django服務開發鏡像構建

最后完整的項目目錄結構1、安裝依賴pip install django django-tables2 django-filter2、創建項目和主應用django-admin startproject configcd configpython manage.py startapp dynamic_models3、配置settings.py將項目模塊dynamic_models加入進來&#xff0c;django_tables2…

20250706-3-Docker 快速入門(上)-常用鏡像管理命令_筆記

一、配置加速器&#xfeff;1. Docker Hub簡介與地址&#xfeff;公共鏡像倉庫: 由Docker公司維護的公共鏡像倉庫&#xff0c;包含大量容器鏡像默認下載源: Docker工具默認從這個公共鏡像庫下載鏡像訪問地址: https://hub.docker.com鏡像搜索功能: 可通過瀏覽器訪問圖形化管理系…

【unity游戲開發——優化篇】使用Occlusion Culling遮擋剔除,只渲染相機視野內的游戲物體提升游戲性能

注意&#xff1a;考慮到優化的內容比較多&#xff0c;我將該內容分開&#xff0c;并全部整合放在【unity游戲開發——優化篇】專欄里&#xff0c;感興趣的小伙伴可以前往逐一查看學習。 文章目錄 前言實戰1、確保所有靜止的3D物體都標記為Occluder Static靜態遮擋體和Occludee …

通用業務編號生成工具類(MyBatis-Plus + Spring Boot)詳解 + 3種調用方式

在企業應用開發中&#xff0c;我們經常需要生成類似 BZ -240704-0001 這種“業務編號”&#xff0c;它通常具有以下特點&#xff1a;前綴&#xff1a;代表業務類型&#xff0c;如 BZ 表示包裝日期&#xff1a;年月日格式&#xff0c;通常為 yyMMdd序列號&#xff1a;當天內遞增…

前端相關性能優化筆記

1.打開速度怎么變快 - 首屏加載優化2.再次打開速度怎么變快 - 緩存優化了3.操作怎么才順滑 - 渲染優化4.動畫怎么保證流暢 - 長任務拆分2.1 首屏加載指標細化:1.FP(First Paint 首次繪制) 2.FCP(First contentful Paint 首次內容繪制)&#xff0c;FP 到 FCP 中間其實主要是 SPA…

7.7晚自習作業

實操作業02&#xff1a;Spark核心開發 作業說明 請嚴格按照步驟操作&#xff0c;并將最終結果文件&#xff08;命名為&#xff1a;sparkcore_result.txt&#xff09;于20點前上傳。結果文件需包含每一步的關鍵命令執行結果文本輸出。 一、數據讀取與轉換操作 上傳賬戶數據$…

手機FunASR識別SIM卡通話占用內存和運行性能分析

手機FunASR識別SIM卡通話占用內存和運行性能分析 --本地AI電話機器人 上一篇&#xff1a;手機無網離線使用FunASR識別SIM卡語音通話內容 下一篇&#xff1a;手機通話語音離線ASR識別商用和優化方向 一、前言 書接上一文《阿里FunASR本地斷網離線識別模型簡析》&#xff0c;…

虛幻引擎Unreal Engine5恐怖游戲設計制作教程,從入門到精通從零開始完整項目開發實戰詳細講解中英字幕

和大家分享一個以前收集的UE5虛幻引擎恐怖游戲開發教程&#xff0c;這是國外一個大神制作的視頻教程&#xff0c;教程從零開始到制作出一款完整的游戲。內容講解全面&#xff0c;如藍圖基礎知識講解、角色控制、高級交互系統、高級庫存系統、物品檢查、恐怖環境氛圍設計、過場動…

多人協同開發時Git使用命令

拉取倉庫代碼 # 拉取遠程倉庫至本地tar_dir路徑 git clone gitgithub.com:your-repo.git target_dir # 默認是拉取遠程master分支&#xff0c;下面拉取并切換到自己需要開發的分支上 # 假設自己需要開發的分支是/feature/my_branch分支 git checkout -b feature/my_branch orig…

線性表——雙向鏈表

線性表——雙向鏈表1. 雙向鏈表的實現1.1 簡單圖例1.2 結點的定義1.3 新結點的創建1.4 鏈表的初始化1.5 結點的插入1.5.1 頭部插入&#xff08;頭插&#xff09;1.5.2 尾部插入&#xff08;尾插&#xff09;1.5.3 任意位置&#xff08;前&#xff09;插入1.6 結點的刪除1.6.1 頭…

Java后端技術博客匯總文檔

文章目錄 前言Java后端匯總鏈接Java基礎知識點數據結構算法&#xff08;Java實現&#xff09;算法知識點合集算法刷題算法競賽AcWing課程藍橋杯AB組輔導課合集&#xff08;更新中…&#xff09; 源碼分析redission 數據庫SQL ServerMySQLRedis -Canal JUC并發編程JVMNetty日志框…

QT 菜單欄設計使用方法

目錄 常用設置函數 多個QAction的單選設置 ???????菜單相關類 ??????? 系統菜單的生成和響應 使用代碼添加系統菜單 使用UI設計器設計系統菜單 使用Qt設計及界面時&#xff0c;常用的兩種方式添加菜單&#xff0c;第一使用UI界面添加&#xff0c;第二種 在…

AIGC領域AI藝術,打造個性化藝術作品

AIGC領域AI藝術,打造個性化藝術作品 關鍵詞:AIGC、AI藝術、生成對抗網絡、個性化創作、深度學習、藝術風格遷移、創意計算 摘要:本文深入探討了AIGC(人工智能生成內容)在藝術創作領域的應用,重點分析了如何利用AI技術打造個性化藝術作品。文章從技術原理出發,詳細解析了生…

基于Flask+Jinja2的快捷教務系統(后端鏈接到新版正方教務系統)

快捷教務系統&#xff08;Easy Educational Administration Management System, EasyEAMS&#xff09; 項目簡介 EasyEAMS 是一個基于 Flask Jinja2 的現代化教務系統 Web 應用。學生可通過網頁端登錄&#xff0c;在線查詢個人信息、成績、課表、學業生涯、通知、選課等。系…

EDM自動化與出海獨立開發實用教程

隨著互聯網全球化發展&#xff0c;越來越多的獨立開發者&#xff08;Indie Developer&#xff09;選擇將自己的產品推向海外市場。如何高效地獲客、激活用戶、提升轉化率&#xff0c;成為出海過程中必須解決的問題。EDM&#xff08;電子郵件營銷&#xff09;自動化&#xff0c;…

「日拱一碼」017 深度學習常用庫——TensorFlow

目錄 基礎操作 張量操作&#xff1a; tf.constant 用于創建常量張量 tf.Variable 用于創建可訓練的變量張量 tf.reshape 可改變張量的形狀 tf.concat 可將多個張量沿指定維度拼接 tf.split 則可將張量沿指定維度分割 數學運算&#xff1a; tf.add 張量的加運算 tf.su…

ARM DStream仿真器腳本常用命令

以下是ARM DStream仿真器腳本中常用的命令及其功能分類&#xff0c;結合調試流程和典型應用場景整理&#xff1a; ?? 一、連接與初始化命令 connect 建立與目標設備的連接&#xff0c;需指定接口類型&#xff08;如JTAG/SWD&#xff09;和處理器核心。 示例&#xff1a;conne…