【点云surface】 修剪B样条曲线拟合

1 介绍

Fitting trimmed B-splines(修剪B样条曲线拟合)是一种用于对给定的点云数据进行曲线拟合的算法。该算法使用B样条曲线模型来逼近给定的点云数据,并通过对模型进行修剪来提高拟合的精度和准确性。

B样条曲线是一种常用的曲线表示方法,它通过一组控制点和节点向量来定义曲线的形状。B样条曲线具有局部控制性和平滑性,因此在曲线拟合问题中被广泛应用。

修剪B样条曲线拟合算法的基本步骤如下:

  1. 初始化:定义一个B样条曲线模型,并设置模型的阶数、节点向量和控制点。

  2. 迭代优化:通过迭代优化的方法,不断调整模型的控制点,使得模型更好地逼近给定的点云数据。在每次迭代中,根据给定的拟合参数和优化目标函数,计算出新的控制点位置。

  3. 修剪:根据给定的修剪参数,对拟合的B样条曲线进行修剪。修剪可以通过删除不需要的曲线段或调整曲线段的权重来实现。修剪的目的是提高拟合的准确性和精度。

  4. 终止条件:根据设定的终止条件,判断是否终止迭代优化过程。终止条件可以是达到最大迭代次数、拟合精度满足要求或其他自定义条件。

  5. 输出结果:输出最终的修剪B样条曲线拟合结果。结果可以是修剪后的B样条曲线模型,也可以是曲线的控制点和节点向量等表示。

2 效果

3 说明

在进行B样条曲面拟合时,通常需要先对曲面进行拟合,然后再对曲面上的曲线进行拟合。这是因为曲面上的曲线通常是曲面的边界或者用于修剪曲面的曲线,它们与曲面的形状紧密相关,因此需要单独进行拟合和调整。

首先,进行B样条曲面拟合时,目标是通过一组控制点和节点向量来逼近给定的点云数据,以生成一个平滑的曲面模型。这个曲面模型可以用来表示曲面的整体形状。

然后,在曲面拟合的基础上,进行B样条曲线拟合。曲线拟合通常是对曲面的边界曲线或者修剪曲线进行拟合。这些曲线与曲面的形状紧密相关,因此需要单独进行拟合和调整。通过对曲线进行拟合,可以更好地捕捉曲面的边界形状或者修剪曲线的形状,从而提高拟合的精度和准确性。

总结起来,进行B样条曲面拟合后,还需要对曲面上的曲线进行拟合的原因是曲线与曲面的形状紧密相关,需要单独进行拟合和调整以提高拟合的精度和准确性。通过分别拟合曲面和曲线,可以更好地捕捉曲面的整体形状和边界形状,从而得到更好的拟合结果。

曲面拟合时的参数

  • order:曲面的阶数。该参数定义了B样条曲面的阶数,即每个控制点的影响范围。较高的阶数可以提供更大的自由度,但也会增加计算时间和内存消耗。

  • refinement:细化次数。该参数定义了在拟合过程中进行的细化次数。通过细化,可以在拟合过程中增加新的控制点,以提高拟合的精度和准确性。

  • iterations:迭代次数。该参数定义了拟合过程中的迭代次数。增加迭代次数可以提高拟合的精度,但也会增加计算时间和内存消耗。

  • mesh_resolution:网格分辨率。该参数定义了生成曲面网格的分辨率。较高的分辨率会导致更细致的曲面表示,但也会增加计算时间和内存消耗。

  • params.interior_smoothness:内部平滑度。该参数用于调整曲面内部的平滑度。较大的值会使曲面更平滑。

  • params.interior_weight:内部权重。该参数用于调整曲面内部点对拟合结果的权重。较大的权重会使内部点对拟合结果的影响更大。

  • params.boundary_smoothness:边界平滑度。该参数用于调整曲面边界的平滑度。较大的值会使曲面边界更平滑。

  • params.boundary_weight:边界权重。该参数用于调整曲面边界点对拟合结果的权重。较大的权重会使边界点对拟合结果的影响更大。

曲线拟合的参数

  • curve_params.addCPsAccuracy:添加控制点的精度。控制点是用于定义B样条曲线形状的关键点。该参数指定了在拟合过程中添加新的控制点的精度。较小的值会导致更精确的拟合结果,但可能会增加计算时间和内存消耗。

  • curve_params.addCPsIteration:添加控制点的迭代次数。在拟合过程中,可以通过迭代的方式不断添加新的控制点来改进拟合结果。该参数指定了添加控制点的迭代次数。增加迭代次数可以提高拟合的精度,但也会增加计算时间和内存消耗。

  • curve_params.maxCPs:最大控制点数。该参数限制了拟合过程中允许的最大控制点数。超过这个数目的控制点将被丢弃。通过调整这个参数,可以控制拟合结果的复杂度和平滑度。

  • curve_params.accuracy:拟合的精度。该参数指定了拟合结果与原始数据之间的误差阈值。较小的值会导致更精确的拟合结果,但可能会增加计算时间和内存消耗。

  • curve_params.iterations:迭代次数。该参数指定了拟合过程中的迭代次数。增加迭代次数可以提高拟合的精度,但也会增加计算时间和内存消耗。

  • curve_params.param.closest_point_resolution:最近点的分辨率。该参数用于计算曲线上最近点的分辨率。较小的值会导致更精确的最近点计算,但可能会增加计算时间和内存消耗。

  • curve_params.param.closest_point_weight:最近点的权重。该参数用于计算曲线上最近点的权重。较大的权重会使最近点对拟合结果的影响更大。

  • curve_params.param.closest_point_sigma2:最近点的方差。该参数用于计算曲线上最近点的方差。较小的方差会使最近点对拟合结果的影响更大。

  • curve_params.param.interior_sigma2:内部点的方差。该参数用于计算曲线上内部点的方差。较小的方差会使内部点对拟合结果的影响更大。

  • curve_params.param.smooth_concavity:平滑凹度。该参数用于调整曲线的平滑凹度。较大的值会使曲线更平滑。

  • curve_params.param.smoothness:平滑度。该参数用于调整曲线的平滑度。较大的值会使曲线更平滑。

4 代码

#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/surface/on_nurbs/fitting_surface_tdm.h>
#include <pcl/surface/on_nurbs/fitting_curve_2d_asdm.h>
#include <pcl/surface/on_nurbs/triangulation.h>typedef pcl::PointXYZ Point;
std::ostringstream os;// 将点云数据中的有效点(即非NaN值)提取出来,并以Eigen::Vector3d类型的形式保存起来
void PointCloud2Vector3d(pcl::PointCloud<Point>::Ptr cloud, pcl::on_nurbs::vector_vec3d & data)
{for (unsigned i = 0; i< cloud->size(); i++){Point &p = cloud->at(i);if(!std::isnan(p.x) && !std::isnan(p.z) && !std::isnan(p.z))data.push_back(Eigen::Vector3d(p.x, p.y, p.z));}
}// 将ON_NurbsCurve和ON_NurbsSurface的曲线和控制点可视化显示在PCLVisualizer中,方便用户观察和分析曲线的形状和控制点的位置。
void visualizeCurve (ON_NurbsCurve &curve,ON_NurbsSurface &surface,pcl::visualization::PCLVisualizer &viewer)
{// 将曲线转换为点云数据pcl::PointCloud<pcl::PointXYZRGB>::Ptr curve_cloud(new pcl::PointCloud<pcl::PointXYZRGB>);pcl::on_nurbs::Triangulation::convertCurve2PointCloud (curve, surface, curve_cloud, 4);//该函数会将曲线上的点均匀地采样,并将采样点作为点云数据的点。// 可视化for(std::size_t i=0; i< curve_cloud->size() - 1; i++){pcl::PointXYZRGB &p1 = curve_cloud->at(i);pcl::PointXYZRGB &p2 = curve_cloud->at(i+1);os << "line" << i;viewer.removeShape(os.str());viewer.addLine<pcl::PointXYZRGB>(p1, p2, 1.0, 0.0, 0.0, os.str());}//pcl::PointCloud<pcl::PointXYZRGB>::Ptr curve_cps (new pcl::PointCloud<pcl::PointXYZRGB>);for(int i=0; i< curve.CVCount(); i++){ON_3dPoint p1;curve.GetCV(i, p1); // 曲线的一个控制点double pnt[3];surface.Evaluate(p1.x ,p1.y, 0, 3, pnt); // 加usn曲面上对应的点的坐标pcl::PointXYZRGB p2;p2.x = float (pnt[0]);p2.y = float (pnt[1]);p2.z = float (pnt[2]);p2.r = 255;p2.g = 0;p2.b = 0;curve_cps->push_back (p2);}viewer.removePointCloud ("cloud_cps");viewer.addPointCloud (curve_cps, "cloud_cps");
}int main()
{pcl::visualization::PCLVisualizer viewer("B-spline surface fitting");viewer.setSize(800, 600);pcl::PCLPointCloud2 cloud2;pcl::PointCloud<Point>::Ptr cloud(new pcl::PointCloud<Point>);if(pcl::io::loadPCDFile("/home/lrj/work/pointCloudData/bun0.pcd", cloud2) == -1)throw std::runtime_error("    PCD file not found.");pcl::fromPCLPointCloud2(cloud2, *cloud);pcl::on_nurbs::NurbsDataSurface data;PointCloud2Vector3d(cloud, data.interior);pcl::visualization::PointCloudColorHandlerCustom<Point> handler(cloud, 0, 255, 0);viewer.addPointCloud<Point>(cloud, handler, "cloud_cylinder");std::printf("     %lu points in data set\n", cloud->size());// ############################################################################// fit B-spline surface/** 整个过程的目的是通过ON-Nurbs算法对给定的点云数据进行曲面拟合,并将拟合结果以三角网格的形式可视化显示出来。* 通过多次细化和迭代,逐步优化曲面拟合结果,使其更加接近原始点云数据。*/// parametersunsigned order(3); // 曲面的阶数unsigned refinement(5); // 细化次数unsigned iterations(10); // 迭代次数unsigned mesh_resolution(256); // 网格分辨率pcl::on_nurbs::FittingSurface::Parameter params;params.interior_smoothness = 0.2; // 内部平滑度params.interior_weight = 1.0; // 内部权重params.boundary_smoothness = 0.2; // 边界平滑度params.boundary_weight = 0.0; // 边界权重// 生成初始的曲面拟合结果printf("   surface fitting ...\n");ON_NurbsSurface nurbs = pcl::on_nurbs::FittingSurface::initNurbsPCABoundingBox(order, &data);pcl::on_nurbs::FittingSurface fit(&data, nurbs);//  fit.setQuiet (false); // enable/disable debug output// 将拟合结果转为三角网格,并将其添加到可视化窗口进行现实pcl::PolygonMesh mesh;pcl::PointCloud<pcl::PointXYZ>::Ptr mesh_cloud(new pcl::PointCloud<pcl::PointXYZ>);std::vector<pcl::Vertices> mesh_vertices;std::string mesh_id = "mesh_nurbs";pcl::on_nurbs::Triangulation::convertSurface2PolygonMesh(fit.m_nurbs, mesh, mesh_resolution);viewer.addPolygonMesh(mesh, mesh_id);// 进行多次曲面细化和求解for (unsigned i=0; i< refinement; i++){fit.refine(0);fit.refine(1);fit.assemble(params);fit.solve();pcl::on_nurbs::Triangulation::convertSurface2Vertices (fit.m_nurbs, mesh_cloud, mesh_vertices, mesh_resolution); // 将曲面转为顶点数据viewer.updatePolygonMesh<pcl::PointXYZ> (mesh_cloud, mesh_vertices, mesh_id); // 视窗刷新,以便观察到曲面拟合的过程viewer.spinOnce ();}// 进行一定次数的曲面拟合迭代for (unsigned i = 0; i < iterations; i++){fit.assemble (params);fit.solve ();pcl::on_nurbs::Triangulation::convertSurface2Vertices (fit.m_nurbs, mesh_cloud, mesh_vertices, mesh_resolution);viewer.updatePolygonMesh<pcl::PointXYZ> (mesh_cloud, mesh_vertices, mesh_id);viewer.spinOnce();}// ############################################################################// fit B-spline curve/** 整个曲线拟合的过程的目的是使用ON-Nurbs算法对给定的点云数据进行曲线拟合,并将拟合结果可视化显示出来。* 通过调整拟合参数,可以控制拟合的精度和平滑度,以得到最优的拟合结果。*/// parameterspcl::on_nurbs::FittingCurve2dAPDM::FitParameter curve_params;curve_params.addCPsAccuracy = 5e-2; // 添加控制点的精度curve_params.addCPsIteration = 3; // 添加控制点的迭代次数curve_params.maxCPs = 200; // 最大控制点数curve_params.accuracy = 1e-3; // 拟合的精度curve_params.iterations = 100; // 迭代次数curve_params.param.closest_point_resolution = 0; // 最近点的分辨率curve_params.param.closest_point_weight = 1.0; // 最近点的权重curve_params.param.closest_point_sigma2 = 0.1; // 最近点的方差curve_params.param.interior_sigma2 = 0.00001; // 内部点的方差curve_params.param.smooth_concavity = 1.0; // 平滑凹度curve_params.param.smoothness = 1.0; // 平滑度// initialisation (circular)printf ("  curve fitting ...\n");pcl::on_nurbs::NurbsDataCurve2d curve_data;curve_data.interior = data.interior_param;curve_data.interior_weight_function.push_back (true);ON_NurbsCurve curve_nurbs = pcl::on_nurbs::FittingCurve2dAPDM::initNurbsCurve2D (order, curve_data.interior);// curve fittingpcl::on_nurbs::FittingCurve2dASDM curve_fit (&curve_data, curve_nurbs);// curve_fit.setQuiet (false); // enable/disable debug outputcurve_fit.fitting (curve_params);visualizeCurve (curve_fit.m_nurbs, fit.m_nurbs, viewer);// ############################################################################// triangulation of trimmed surfaceprintf ("  triangulate trimmed surface ...\n");viewer.removePolygonMesh (mesh_id);pcl::on_nurbs::Triangulation::convertTrimmedSurface2PolygonMesh (fit.m_nurbs, curve_fit.m_nurbs, mesh,mesh_resolution); // 将拟合的曲面、曲线转为三角网格viewer.addPolygonMesh (mesh, mesh_id);// save trimmed B-spline surfaceif ( fit.m_nurbs.IsValid() ){ONX_Model model;ONX_Model_Object& surf = model.m_object_table.AppendNew();surf.m_object = new ON_NurbsSurface(fit.m_nurbs);surf.m_bDeleteObject = true;surf.m_attributes.m_layer_index = 1;surf.m_attributes.m_name = "surface";ONX_Model_Object& curv = model.m_object_table.AppendNew();curv.m_object = new ON_NurbsCurve(curve_fit.m_nurbs);curv.m_bDeleteObject = true;curv.m_attributes.m_layer_index = 2;curv.m_attributes.m_name = "trimming curve";//        model.Write(file_3dm.c_str());
//        printf("  model saved: %s\n", file_3dm.c_str());}printf ("  ... done.\n");viewer.spin();return 0;
}

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

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

相关文章

【element优化经验】el-dialog修改title样式

目录 前言 解决之路 1.把默认的这个图标隐藏&#xff0c;官方的api有这个属性&#xff1a;showClose值设置false. 2.title插槽定制&#xff1a;左边定制标题&#xff0c;右边定制按钮区域。 3.背景颜色修改&#xff1a;默认title是有padding的需要把它重写调&#xff0c;然…

基于 STM32Cube.AI 的嵌入式人脸识别算法实现

本文介绍了如何使用 STM32Cube.AI 工具开发嵌入式人脸识别算法。首先&#xff0c;我们将简要介绍 STM32Cube.AI 工具和 STM32F系列单片机的特点。接下来&#xff0c;我们将详细讨论如何使用 STM32Cube.AI 工具链和相关库来进行人脸识别算法的开发和优化。最后&#xff0c;我们提…

Netty实现websocket且实现url传参的两种方式(源码分析)

1、先构建基本的netty框架 再下面的代码中我构建了一个最基本的netty实现websocket的框架&#xff0c;其他个性化部分再自行添加。 Slf4j public class TeacherServer {public void teacherStart(int port) throws InterruptedException {NioEventLoopGroup boss new NioEve…

Day40力扣打卡

打卡记录 包子凑数&#xff08;裴蜀定理 DP&#xff09; 根据裴蜀定理&#xff0c;存在 c gcd(a, b) 使不定方程ax by c满足条件&#xff0c;如果gcd(a, b) 1即a与b互素的情况下&#xff0c;就会 ax by 1&#xff0c;由于为1可以构造后面的无穷数字&#xff0c;故得到结…

Centos7 离线安装 CDH7.1.7

1. 安装CDH的准备工作&#xff08;所有节点都要执行&#xff09; 1.1 准备环境 角色 IP k8s-master 192.168.181.129 k8s-node1 192.168.181.130 k8s-node2 192.168.181.131 1.2 安装JDK # https://www.oracle.com/java/technologies/downloads/#java11 wget rpm -ivh…

亚马逊Listing怎么写!亲身经验分享

亚马逊运营的重要环节之一&#xff0c;listing的攥写&#xff0c;可以决定了产品的搜索排名&#xff0c;用户的点击率和转化率&#xff0c;那么如果你的产品排名或者转化不理想的情况&#xff0c;可以考虑对listing进行优化&#xff0c;在关键词过多和语句流程通顺的情况下&…

js获取时间日期

目录 Date 对象 1. 获取当前时间 2. 获取特定日期时间 Date 对象的方法 1. 获取各种日期时间组件 2. 获取星期几 3. 获取时间戳 格式化日期时间 1. 使用 toLocaleString() 方法 2. 使用第三方库 UNIX 时间戳 内部表示 时区 Date 对象 JavaScript中内置的 Date 对象…

数据挖掘之PCA-主成分分析

PCA的用处&#xff1a;找出反应数据中最大变差的投影&#xff08;就是拉的最开&#xff09;。 在减少需要分析的指标同时&#xff0c;尽量减少原指标包含信息的损失&#xff0c;以达到对所收集数据进行全面分析的目的 但是什么时候信息保留的最多呢&#xff1f;具体一点&#…

​飞凌嵌入式FCU2601网关,为工商业储能EMS注入智慧的力量

一、火热的储能行业&#xff0c;寻求新的市场机会 最近一段时间以来&#xff0c;世界储能大会、上海储能展、能源电子产业发展大会等多个储能相关论坛和展览密集登场&#xff0c;即使“内卷”已成为了业内讨论的热词&#xff0c;但寻求新的市场机会仍然是行业共识&#xff0c;…

Qt C++中调用python,并将软件打包发布,python含第三方依赖

工作中遇到qt c调用我的python 代码&#xff0c;并且想要一键打包&#xff0c;这里我根据参考的以及个人实践的结果来简单实现一下。 环境&#xff1a;windows系统&#xff0c;QT Creater 4.5&#xff0c; python 3.8&#xff08;anaconda虚拟环境&#xff09; 1. 简单QT调用…

electron windows robotjs 安装教程

Robotjs 安装 前言第一步 : 安装python第二步 : 安装Visual Studio 2022第三步 : 安装robotjs 前言 robotjs可以控制鼠标键盘&#xff0c;获取屏幕内容&#xff0c;配合electron可做很多自动化操作。windows下配置环境有很多坑&#xff0c;很多文章都太旧了。试了很多次发现了…

ky10 server x86 auditd安装(日志审计系统)

概述 Auditd工具可以帮助运维人员审计Linux&#xff0c;分析发生在系统中的发生的事情。Linux 内核有用日志记录事件的能力&#xff0c;包括记录系统调用和文件访问。管理员可以检查这些日志&#xff0c;确定是否存在安全漏洞&#xff08;如多次失败的登录尝试&#xff0c;或者…

golang学习笔记——接口和继承比较2

接口和继承 现在有一个需要要求大学生和足球运动员掌握英语技能&#xff0c;请问怎么实现? 给运动员和学生结构体添加studyEnglish方法显示是可以的&#xff0c;但是篮球动员和中学生也学习了英语&#xff0c;显示不行。这时&#xff0c;我们可以直接给足球运动员和大学生添加…

跳转应用市场详情页market

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、商业变现、人工智能等&#xff0c;希望大家多多支持。 未经允许不得转载 目录 一、导读二、概览三、跳转到各大厂商应…

播放器开发(四):多线程解复用与解码模块实现

学习课题&#xff1a;逐步构建开发播放器【QT5 FFmpeg6 SDL2】 前言 根据第一章内容&#xff0c;我们首先可以先把解复用和解码模块完成&#xff0c;其中需要使用到多线程以及队列&#xff0c;还需要使用FFmpeg进行解复用和解码动作的实现。 创建BaseQueue基类 BaseQueue.h…

亚马逊两步验证有哪些验证方法?

亚马逊通常提供多种两步验证的方式&#xff0c;包括短信&#xff08;通过手机接收验证码&#xff09;和认证器应用程序&#xff08;如Google Authenticator、Authy等&#xff09;。选择你偏好的方式。 短信验证&#xff1a; 如果选择短信验证&#xff0c;需要将你的手机号码关联…

YOLOv8改进 | 2023 | LSKAttention大核注意力机制助力极限涨点

论文地址&#xff1a;官方论文地址 代码地址&#xff1a;官方代码地址 一、本文介绍 在这篇文章中&#xff0c;我们将讲解如何将LSKAttention大核注意力机制应用于YOLOv8&#xff0c;以实现显著的性能提升。首先&#xff0c;我们介绍LSKAttention机制的基本原理&#xff0c;…

定制手机套餐---python序列

if __name__ __main__:print("定制手机套餐")print("")#定义电话时长&#xff1a;字典callTimeOptions{1:0分钟,2:50分钟,3:100分钟,4:300分钟,5:不限量}keyinput("请输入电话时长的选择编号&#xff1a;")valuecallTimeOptions.get(key)if val…

代码随想录算法训练营第五十四天|392.判断子序列 115.不同的子序列

文档讲解&#xff1a;代码随想录 视频讲解&#xff1a;代码随想录B站账号 状态&#xff1a;看了视频题解和文章解析后做出来了 392.判断子序列 class Solution:def isSubsequence(self, s: str, t: str) -> bool:dp [[0] * (len(t)1) for _ in range(len(s)1)]for i in ra…

RabbitMq使用与整合

MQ基本概念 MQ概述 MQ全称 Message Queue&#xff08;[kjuː]&#xff09;&#xff08;消息队列&#xff09;&#xff0c;是在消息的传输过程中保存消息的容器。多用于分布式系统之间进行通信。 &#xff08;队列是一种容器&#xff0c;用于存放数据的都是容器&#xff0c;存…