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

    // 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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenCV- 学习笔记(Python)图像处理基础

本专栏&#xff1a;主要记录OpenCV&#xff08;Python&#xff09;学习笔记 OpenCV 图像处理基础 灰度图 import cv2 #opencv读取的格式是BGR import numpy as np import matplotlib.pyplot as plt#Matplotlib是RGB %matplotlib inline ​ imgcv2.imread(cat.jpg) img_gray…

Linux技能篇-非交互式修改密码

今天的文章没有格式&#xff0c;简单分享一个小技能&#xff0c;就是标题所说–非交互式修改密码。 一、普通方式修改用户密码 最普通的修改密码的命令就是passwd命令 [rootlocalhost ~]# passwd root Changing password for user root. New password: Retype new password:…

基于孔雀算法优化概率神经网络PNN的分类预测 - 附代码

基于孔雀算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于孔雀算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于孔雀优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络的光滑…

《C++PrimePlus》第9章 内存模型和名称空间

9.1 单独编译 Visual Studio中新建头文件和源代码 通过解决方案资源管理器&#xff0c;如图所示&#xff1a; 分成三部分的程序&#xff08;直角坐标转换为极坐标&#xff09; 头文件coordin.h #ifndef __COORDIN_H__ // 如果没有被定义过 #define __COORDIN_H__struct pola…

两巨头Facebook 和 GitHub 联手推出 Atom-IDE

9月13日&#xff0c;GitHub 宣布与 Facebook 合作推出了 Atom-IDE —— 它包括一系列将类 IDE 功能带到 Atom 的可选工具包。初次发布的版本包括更智能、感知上下文的自动完成&#xff1b;导航功能&#xff0c;如大纲视图和定义跳转(outline view and goto-definition)&#xf…

[UE4][C++]基于UUserWidget的一种序列图播放方法

最近在做一个大项目&#xff0c;鸽了几个月了....... 一、传统方法Flipbook 这种方法适合序列图较少的情况下、可以一个一个添加进来然后调整顺序。蓝图也比较友好可以直接设置很多属性和功能。这里简单了解一下即可&#xff0c;想要深入了解的同学可以自行搜索。 1.1创建Fli…

用 Addon 增强 Node.js 和 Electron 应用的原生能力

前言 Node.js Addon 是 Node.js 中为 JavaScript 环境提供 C/C 交互能力的机制。其形态十分类似 Java 的 JNI&#xff0c;都是通过提供一套 C/C SDK&#xff0c;用于在 C/C 中创建函数方法、进行数据转换&#xff0c;以便 JavaScript / Java 等语言进行调用。这样编写的代码通常…

大模型推理加速框架vllm部署的实战方案

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

【教学类-06-07】20231124 (55格版)X-X之间的加法、减法、加减混合题

背景需求 在大四班里&#xff0c;预测试55格“5以内、10以内、20以内的加法题、减法题、加减混合题”的“实用性”。 由于只打印一份20以内加法减法混合题。 “这套20以内的加减法最难”&#xff0c;我询问谁会做&#xff08;摸底幼儿的水平&#xff09; 有两位男孩举手想挑…

python——第十二天

内置模块或者其他模块学习方式&#xff1a; dir help os模块负责程序与操作系统的交互&#xff0c;提供了访问操作系统底层的接口&#xff1b;即os模块提供了非常丰富的方法用来处理文件和目录。 os&#xff1a; os.path 遍历C盘代码 import os from os import path def …

1|1111

1、指定在每天凌晨4&#xff1a;00将该时间点之前的系统日志信息&#xff08;/var/log/messages &#xff09;备份到目录下/backup&#xff0c;备份后日志文件名显示格式logfileYY-MM-DD-HH-MM 2、配置ssh免密登陆&#xff1a;客户端主机通过redhat用户基于秘钥验证方式进行远…

手写一个简单版的Spring

1. 创建一个工程及初始化 创建Java工程 创建对应的包 config&#xff1a;为配置类包 service&#xff1a;定义的将要被自己写的Spring容器管理的组件bean spring&#xff1a;里面定义自己写的Spring的类文件&#xff0c;包含子包anno注解包 test&#xff1a;定义测试类 2.…

springboot+vue基本微信小程序的外卖点餐平台系统

项目介绍 餐饮行业是一个传统的行业。根据当前发展现状&#xff0c;网络信息时代的全面普及&#xff0c;餐饮行业也在发生着变化&#xff0c;单就点餐这一方面&#xff0c;利用手机点单正在逐步进入人们的生活。传统的点餐方式&#xff0c;不仅会耗费大量的人力、时间&#xf…

C++入门第九篇---Stack和Queue模拟实现,优先级队列

前言&#xff1a; 我们已经掌握了string vector list三种最基本的数据容器模板&#xff0c;而对于数据结构的内容来说&#xff0c;其余的数据结构容器基本都是这三种容器的延申和扩展&#xff0c;在他们的基础上扩展出更多功能和用法&#xff0c;今天我们便来模拟实现一下C库中…

【OpenSTL】方便好用的时空预测开源库

OpenSTL&#xff1a;方便好用的时空预测开源库 时空预测学习是一种学习范式&#xff0c;它使得模型能够通过在无监督的情况下从给定的过去帧预测未来帧&#xff0c;从而学习空间和时间的模式。尽管近年来取得了显著的进展&#xff0c;但由于不同的设置、复杂的实现和难以复现性…

Go语言的学习笔记2——Go语言源文件的结构布局

用一个只有main函数的go文件来简单说一下Go语言的源文件结构布局&#xff0c;主要分为包名、引入的包和具体函数。下边是main.go示例代码&#xff1a; package mainimport "fmt"func main() { fmt.Println("hello, world") }package main就是表明这个文件…

AlDente Pro v1.22.2(mac电池最大充电限制工具)

AlDente Pro是一款适用于Mac操作系统的小工具&#xff0c;可以帮助您限制电池充电量以延长电池寿命。通常情况下&#xff0c;电池在充满的状态下会继续接受电源充电&#xff0c;这可能会导致电池寿命缩短。使用AlDente Pro&#xff0c;您可以设置电池只充到特定的充电水平&…

高清动态壁纸软件Live Wallpaper Themes 4K mac中文版功能

Live Wallpaper & Themes 4K mac是一款提供各种高清动态壁纸和主题的应用程序。该应用程序提供了大量的动态壁纸和主题&#xff0c;包括自然、动物、城市、抽象等各种类别&#xff0c;可以满足用户不同的需求。除了壁纸和主题之外&#xff0c;该应用程序还提供了许多其他功…

拦截器详解

一、概述 什么是拦截器&#xff1f; 是一种动态拦截方法调用的机制&#xff0c;类似于过滤器。Spring框架中提供的&#xff0c;用来动态拦截控制方法的执行。 到底是干啥用的&#xff1f; 拦截请求用的&#xff0c;在指定的方法调用前后&#xff0c;执行在拦截器中编写的程序 …

苹果App加急审核

苹果App加急审核 &#xff08;注意加急的次数&#xff0c;有的说一年能加急两次&#xff0c;有的说不止两次。遇到紧急问题了就用&#xff0c;非紧急 等一等也行&#xff09; 1.登录苹果账号 Sign In - Apple &#xff08; https://developer.apple.com/contact/app-store/?…