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

news2024/12/23 12:43:11

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算法对给定的点云数据进行曲面拟合,并将拟合结果以三角网格的形式可视化显示出来。
     * 通过多次细化和迭代,逐步优化曲面拟合结果,使其更加接近原始点云数据。
    */

    // parameters
    unsigned 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算法对给定的点云数据进行曲线拟合,并将拟合结果可视化显示出来。
     * 通过调整拟合参数,可以控制拟合的精度和平滑度,以得到最优的拟合结果。
    */

    // parameters
    pcl::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 fitting
    pcl::on_nurbs::FittingCurve2dASDM curve_fit (&curve_data, curve_nurbs);
    // curve_fit.setQuiet (false); // enable/disable debug output
    curve_fit.fitting (curve_params);
    visualizeCurve (curve_fit.m_nurbs, fit.m_nurbs, viewer);

    // ############################################################################
    // triangulation of trimmed surface

    printf ("  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 surface
    if ( 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.coloradmin.cn/o/1249885.html

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

相关文章

深度学习之基于Tensorflow银行卡号码识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介银行卡号码识别的步骤TensorFlow的优势 二、功能三、系统四. 总结 一项目简介 # 深度学习基于TensorFlow的银行卡号码识别介绍 深度学习在图像识别领域取得…

浏览器缓存、本地存储、Cookie、Session、Token

目录 前端通信&#xff08;渲染、http、缓存、异步、跨域&#xff09; HTTP与HTTPS&#xff0c;HTTP版本、状态码 请求头&#xff0c;响应头 缓存 强制缓存&#xff1a;Cache-Control:max-age&#xff08;HTTP1.1&#xff09;>Expires&#xff08;1.0&#xff09; js、…

python pdf转txt文本、pdf转json

文章目录 一、前言二、实现方法1. 目录结构2. 代码 一、前言 此方法只能转文本格式的pdf&#xff0c;如果是图片格式的pdf需要用到ocr包&#xff0c;以后如果有这方面需求再加这个方法 二、实现方法 1. 目录结构 2. 代码 pdf2txt.py 代码如下 #!/usr/bin/env python # -*- …

【LM、LLM】浅尝二叉树在前馈神经网络上的应用

前言 随着大模型的发展&#xff0c;模型参数量暴涨&#xff0c;以Transformer的为组成成分的隐藏神经元数量增长的越来越多。因此&#xff0c;降低前馈层的推理成本逐渐进入视野。前段时间看到本文介绍的相关工作还是MNIST数据集上的实验&#xff0c;现在这个工作推进到BERT上…

【Java程序员面试专栏 专业技能篇】Java SE核心面试指引(三):核心机制策略

关于Java SE部分的核心知识进行一网打尽,包括四部分:基础知识考察、面向对象思想、核心机制策略、Java新特性,通过一篇文章串联面试重点,并且帮助加强日常基础知识的理解,全局思维导图如下所示 本篇Blog为第三部分:核心机制策略,子节点表示追问或同级提问 异常处理 …

机器学习之自监督学习(四)MoCo系列翻译与总结(一)

Momentum Contrast for Unsupervised Visual Representation Learning Abstract 我们提出了“动量对比”&#xff08;Momentum Contrast&#xff0c;MoCo&#xff09;来进行无监督的视觉表示学习。从对比学习的角度来看&#xff0c;我们将其视为字典查找&#xff0c;通过构建…

Spring - Mybatis-设计模式总结

Mybatis-设计模式总结 1、Builder模式 2、工厂模式 3、单例模式 4、代理模式 5、组合模式 6、模板方法模式 7、适配器模式 8、装饰者模式 9、迭代器模式 虽然我们都知道有26个设计模式&#xff0c;但是大多停留在概念层面&#xff0c;真实开发中很少遇到&#xff0c;…

Day31| Leetcode 455. 分发饼干 Leetcode 376. 摆动序列 Leetcode 53. 最大子数组和

进入贪心了&#xff0c;我觉得本专题是最烧脑的专题 Leetcode 455. 分发饼干 题目链接 455 分发饼干 让大的饼干去满足需求量大的孩子即是本题的思路&#xff1a; class Solution { public:int findContentChildren(vector<int>& g, vector<int>& s) {…

【差分放大电路分析】2021-12-31

缘由有哪位愿意帮助一下的-嵌入式-CSDN问答 截图&#xff0c;数值自己去计算。上2图是接电阻&#xff0c;下2图是接三极管。

JVM内存模型及调优

本文将为大家详细介绍JVM内存模型及如何对JVM内存进行调优。我们将分为以下几个部分进行讲解&#xff1a; JVM内存模型概述JVM内存区域及作用JVM内存调优方法实战案例与优化技巧 一、JVM内存模型概述 在深入了解JVM内存模型之前&#xff0c;我们需要先了解一下Java内存模型&am…

01、Tensorflow实现二元手写数字识别

01、Tensorflow实现二元手写数字识别&#xff08;二分类问题&#xff09; 开始学习机器学习啦&#xff0c;已经把吴恩达的课全部刷完了&#xff0c;现在开始熟悉一下复现代码。对这个手写数字实部比较感兴趣&#xff0c;作为入门的素材非常合适。 基于Tensorflow 2.10.0 1、…

NeurIPS 2023|AI Agents先行者CAMEL:第一个基于大模型的多智能体框架

AI Agents是当下大模型领域备受关注的话题&#xff0c;用户可以引入多个扮演不同角色的LLM Agents参与到实际的任务中&#xff0c;Agents之间会进行竞争和协作等多种形式的动态交互&#xff0c;进而产生惊人的群体智能效果。本文介绍了来自KAUST研究团队的大模型心智交互CAMEL框…

浅谈安科瑞无线测温设备在挪威某项目的应用

摘要&#xff1a;安科瑞无线温度设备装置通过无线温度收发器和各无线温度传感器直接进行温度值的传输&#xff0c;并采用液晶显示各无线温度传感器所测温度。 Absrtact:Acre wireless temperature device directly transmits the temperature value through the wireless temp…

Nginx安装与配置、使用Nginx负载均衡及动静分离、后台服务部署、环境准备、系统拓扑图

目录 1. 系统拓扑图 2. 环境准备 3. 服务器安装 3.1 mysql&#xff0c;tomcat 3.2 Nginx的安装 4. 部署 4.1 后台服务部署 4.2 Nginx配置负载均衡及静态资源部署 1. 系统拓扑图 说明&#xff1a; 用户请求达到Nginx若请求资源为静态资源&#xff0c;则将请求转发至静态…

【蓝桥杯省赛真题47】Scratch小猫踩球 蓝桥杯scratch图形化编程 中小学生蓝桥杯省赛真题讲解

目录 scratch小猫踩球 一、题目要求 编程实现 二、案例分析 1、角色分析

vue3.0使用leaflet

1、获取天地图密钥&#xff1b; 访问:https://www.tianditu.gov.cn/ 注册并登录&#xff0c;访问开发资源 》地图API 》 地图服务》申请key 应用管理》创建新应用》获取到对应天地图key 2、引入leaflet组件 参考资料&#xff1a;https://leafletjs.com/reference.html#pa…

一盏茶的时间,入门 Node.js

一、.什么是 Node.js&#xff1f; Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时&#xff0c;用于构建高性能、可伸缩的网络应用。 它采用事件驱动、非阻塞 I/O 模型&#xff0c;使其在处理并发请求时表现出色。 二、安装 Node.js 首先&#xff0c;让我们从 Node.…

CSS3新特性(2-1)

CSS3新特性 前言border&#xff1a;radius标签属性选择器box-sizing透明度 前言 本文主要讲解CSS3有哪些新的特性和内容&#xff0c;那么好&#xff0c;本文正式开始. border&#xff1a;radius 新增了圆角边框概念&#xff0c;可以通过具体数值或者百分比&#xff0c;来让边…

互联网上门洗鞋店小程序

上门洗鞋店小程序门店版是基于原平台版进行增强的&#xff0c;结合洗鞋行业的线下实际运营经验和需求&#xff0c;专为洗鞋人和洗鞋店打造的高效、实用、有价值的管理软件系统。 它能够帮助洗鞋人建立自己的私域流量&#xff0c;实现会员用户管理&#xff0c;实现用户与商家的点…

电源控制系统架构(PCSA)之电源控制框架概览

目录 6 电源控制框架 6.1 电源控制框架概述 6.1.1 电源控制框架低功耗接口 6.1.2 电源控制框架基础设施组件 6 电源控制框架 电源控制框架是标准基础设施组件、接口和相关方法的集合&#xff0c;可用于构建SoC电源管理所需的基础设施。 本章介绍框架的主要组件和低功耗接…