【贝塞尔曲线拟合】

news/2024/5/18 15:04:52/文章来源:https://blog.csdn.net/weixin_43879302/article/details/127337936

贝塞尔曲线拟合

  • 问题描述
  • 拟合曲线生成过程
  • 参考程序
  • 注意事项

问题描述

已知一条n阶贝塞尔曲线L(P0,P1,P2,P3,...,Pn)L(P0, P1, P2, P3, ..., Pn)L(P0,P1,P2,P3,...,Pn)P0P0P0为起点,P1P1P1为第一个控制点,P2P2P2为第二个控制点,P3P3P3为第三个控制点,PnPnPn为终点)和一个点P,拟合一条连接新的n阶贝塞尔曲线L1(P01,P11,P21,P31,...,Pn1,)L_{1}(P0_{1}, P1_{1}, P2_{1}, P3_{1},..., Pn_{1}, )L1P01,P11,P21,P31,...,Pn1,P01P0_{1}P01和点PPP相重合,Pn1Pn_{1}Pn1PnPnPn相重合,曲线LLL尽可能和曲线L1L_{1}L1相重合,如图1所示。



图1

拟合曲线生成过程

其中新的贝塞尔曲线的起点和终点是确定的,需要生成所有的控制点,如公式(1)所示。
P01=PP11=f(P1,P2,P3,...,Pn,t)P21=f(P2,P3,...,Pn,t)P31=f(P3,P4,...,Pn,t)...Pn1=Pn(1)\begin{array}{l} P0_{1} = P \\ P1_{1} = f(P1,P2,P3,...,Pn,t) \\ P2_{1} = f(P2, P3, ..., Pn,t) \\ P3_{1} = f(P3, P4, ..., Pn,t) \\ ... \\ Pn_{1} = Pn \end{array} \tag1 P01=PP11=f(P1,P2,P3,...,Pn,t)P21=f(P2,P3,...,Pn,t)P31=f(P3,P4,...,Pn,t)...Pn1=Pn(1)
在公式(1)中,函数fff表示贝塞尔曲线,阶数为点的个数减1,ttt表示与点PPP最近的贝塞尔曲线点的时间参数。

参考程序

#!/usr/bin/env python3
#-*- coding:utf-8 -*-import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import mathclass Point:x = 0.0    #单位my = 0.0    #单位myaw = 0.0    #单位raddef __init__(self, x=0.0, y=0.0, yaw=0.0):self.x = xself.y = yself.yaw = yawdef __str__(self):return ("(x: {}; y: {}; yaw: {})".format(self.x, self.y, self.yaw))def display(l1, l2):print(l1[0], l1[1], l1[2], l1[3], l1[4], l1[5])print(l2[0], l2[1], l2[2], l2[3], l2[4], l2[5])fig = plt.figure()# # 连续性的画图# ax = fig.add_subplot(1, 1, 1)# # 设置图像显示的时候XY轴比例# ax.axis("equal")# # 开启一个画图的窗口# plt.ion()# plt.xlim(-10, 10)# plt.ylim(-10, 10)x1_list = []y1_list = []for t in np.arange(0.0, 1.0, 0.01):p = calcu5BezierCurvePoint(l1[0], l1[1], l1[2], l1[3], l1[4], l1[5], t)x1_list.append(p.x)y1_list.append(p.y)plt.plot(x1_list, y1_list, '-')x2_list = []y2_list = []for t in np.arange(0.0, 1.0, 0.01):p = calcu5BezierCurvePoint(l2[0], l2[1], l2[2], l2[3], l2[4], l2[5], t)x2_list.append(p.x)y2_list.append(p.y)plt.plot(x2_list, y2_list, '-')plt.show()def calcuSlopeOfBezierCurve(p0, p1, p2, p3, p4, p5, t):dx = 0.0dy = 0.0l_t = 1.0 - tdx = 5.0 * (l_t * l_t * l_t * l_t * (p1.x - p0.x) + 4 * l_t * l_t * l_t * t * (p2.x - p1.x) +6 * l_t * l_t * t * t * (p3.x - p2.x) + 4 * l_t * t * t * t * (p4.x - p3.x) + t * t * t * t * (p5.x - p4.x))dy = 5.0 * (l_t * l_t * l_t * l_t * (p1.y - p0.y) + 4 * l_t * l_t * l_t * t * (p2.y - p1.y) +6 * l_t * l_t * t * t * (p3.y - p2.y) + 4 * l_t * t * t * t * (p4.y - p3.y) + t * t * t * t * (p5.y - p4.y))return dx, dydef calcu1BezierCurvePoint(p0, p1, t):l_t = 1.0 - tx = l_t * p0.x + t * p1.xy = l_t * p0.y + t * p1.yreturn Point(x, y, 0)def calcu2BezierCurvePoint(p0, p1, p2, t):l_t = 1.0 - tx = l_t * l_t * p0.x + 2 * l_t * t * p1.x + t * t * p2.xy = l_t * l_t * p0.y + 2 * l_t * t * p1.y + t * t * p2.yreturn Point(x, y, 0)def calcu3BezierCurvePoint(p0, p1, p2, p3, t):l_t = 1.0 - tx = l_t * l_t * l_t * p0.x + 3 * l_t * l_t * t * p1.x + 3 * l_t * t * t * p2.x + t * t * t * p3.xy = l_t * l_t * l_t * p0.y + 3 * l_t * l_t * t * p1.y + 3 * l_t * t * t * p2.y + t * t * t * p3.yreturn Point(x, y, 0)def calcu4BezierCurvePoint(p0, p1, p2, p3, p4, t):l_t = 1.0 - tx = l_t * l_t * l_t * l_t * p0.x + 4 * l_t * l_t * l_t * t * p1.x + 6 * l_t * l_t * t * t * p2.x + \4 * l_t * t * t * t * p3.x + t * t * t * t * p4.xy = l_t * l_t * l_t * l_t * p0.y + 4 * l_t * l_t * l_t * t * p1.y + 6 * l_t * l_t * t * t * p2.y + \4 * l_t * t * t * t * p3.y + t * t * t * t * p4.yreturn Point(x, y, 0)def calcu5BezierCurvePoint(p0, p1, p2, p3, p4, p5, t):l_t = 1.0 - tx = l_t * l_t * l_t * l_t * l_t * p0.x + 5 * l_t * l_t * l_t * l_t * t * p1.x + 10 * l_t * l_t * l_t * t * t * p2.x + \10 * l_t * l_t * t * t * t * p3.x + 5 * l_t * t * t * t * t * p4.x + t * t * t * t * t * p5.xy = l_t * l_t * l_t * l_t * l_t * p0.y + 5 * l_t * l_t * l_t * l_t * t * p1.y + 10 * l_t * l_t * l_t * t * t * p2.y + \10 * l_t * l_t * t * t * t * p3.y + 5 * l_t * t * t * t * t * p4.y + t * t * t * t * t * p5.ydx, dy = calcuSlopeOfBezierCurve(p0, p1, p2, p3, p4, p5, t)return Point(x, y, math.atan2(dy, dx))def calcuClosetPointIn5Bezier(p0, p1, p2, p3, p4, p5, start_point):min_d = 99999999.0min_t = 0.0for t in np.arange(0.0, 1.001, 0.01):p = calcu5BezierCurvePoint(p0, p1, p2, p3, p4, p5, t)d = math.hypot(p.y - start_point.y, p.x - start_point.x)if min_d > d:min_d = dmin_t = treturn min_tdef bezierFit(p0, p1, p2, p3, p4, p5, start_point):p00 = Point()p01 = Point()p02 = Point()p03 = Point()p04 = Point()p05 = Point()t = calcuClosetPointIn5Bezier(p0, p1, p2, p3, p4, p5, start_point)p00 = start_pointp01 = calcu4BezierCurvePoint(p1, p2, p3, p4, p5, t)p02 = calcu3BezierCurvePoint(p2, p3, p4, p5, t)p03 = calcu2BezierCurvePoint(p3, p4, p5, t)p04 = calcu1BezierCurvePoint(p4, p5, t)p05 = p5return p00, p01, p02, p03, p04, p05def bezierFit2(p0, p1, p2, p3, p4, p5, end_point):p00 = Point()p01 = Point()p02 = Point()p03 = Point()p04 = Point()p05 = Point()t = calcuClosetPointIn5Bezier(p0, p1, p2, p3, p4, p5, end_point)p00 = p0p01 = calcu1BezierCurvePoint(p0, p1, t)p02 = calcu2BezierCurvePoint(p0, p1, p2, t)p03 = calcu3BezierCurvePoint(p0, p1, p2, p3, t)p04 = calcu4BezierCurvePoint(p0, p1, p2, p3, p4, t)p05 = end_pointreturn p00, p01, p02, p03, p04, p05if __name__ == "__main__":p0 = Point(0.0, 0.0)p1 = Point(1.0, 1.0)p2 = Point(2.0, -1.0)p3 = Point(3.0, 1.0)p4 = Point(4.0, -1.0)p5 = Point(5.0, 0.0)start_pose = Point(2.5, 0.0)p00, p01, p02, p03, p04, p05 = bezierFit2(p0, p1, p2, p3, p4, p5, start_pose)display([p0, p1, p2, p3, p4, p5], [p00, p01, p02, p03, p04, p05])

注意事项

  1. PPP在贝塞尔曲线附近能保证较好的效果;
  2. 本文只介绍正向的拟合过程,逆向的拟合过程调换以下顺序即可;

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

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

相关文章

Mysql删除重复数据只保留一条

(1)以这张表为例: CREATE TABLE test (id varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 注解id,name varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 名字,PRIMARY KEY…

队列的顺序存储结构

说白了,就是一个数组 ,然后在两端进行操作 ,两端用首队指针和尾指针分别指向 ,然后进行相关的删除,插入操作, 目的还是模拟现实对数据的处理 ●描述队列 •数据元素data , 元素具有同一类型ElemType ,最多为MaxSize(数组容量) •当前队首front •当前队尾 rear 定义队列的数据…

RK3588安装部署openmediavault

RK3588安装部署openmediavault部署准备Debian 10 文件系统编译和获取安装 openmediavault安装基础依赖安装 openmediavault 原秘钥环添加 openmediavault 官方原安装 openmediavault 基础依赖安装 openmediavaultopenmediavault 相关资料: https://docs.openmediav…

YOLOX 学习笔记

笔记来源:https://www.bilibili.com/video/BV1jo4y1D7CF/?vd_source2ed6e8af02f9ba8cb90b90e99bd4ccee 近年来,目标检测的工程应用研究中,YOLO系列以快速响应、高精度、结构简单以及容易部署的特点备受工程研究人员的青睐。同时,…

3. HDFS分布式文件系统

3.1 HDFS简介 随着数据量越来越大,在一个操作系统存不下所有的数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS只是分布…

CloudlaC是什么?

目录1. CloudIaC的简介2. 部署安装2.1 下载并解压安装包2.2 安装并启动Docker2.3 安装并启动Mysql2.4 安装并启动 Consul2.5 编辑配置文件2.6 初始化MySQL2.7 安装iaC服务2.8 启动 IaC 服务2.9 拉取 ct-worker 镜像2.10 下载前端部署包并解压2.11 安装nginx并配置2.12 访问web页…

【笔试刷题训练】day_04

选择题 C/C中各种进制的表示方法 二进制:在数字的末尾加b,如101010b 八进制:在数字前面加数字0,如0123 十进制:数字本身,如123 十六进制:数字前面加0x 或者 数字后面加h,如0x123、12…

字节跳动C++云原生二面(65min)

字节跳动C云原生二面(65min) 面试问题 HTTP1.0 、1.1和2.0 的区别和差异是什么 《HTTP1.0和1.1的区别》HTTP1.1 默认开启长连接(keep-alive) 而HTTP1.0需要添加参数,在一定程度上减少了建立和关闭连接的消耗和延迟HT…

AntDesign-Vue Table 查询与分页

前言 之前的增删改查小 Demo 已经快要进行到最后一步了,这节的任务是将请求数据的方式改为 分页,并且增加 分页条件查询 的功能。 页面布局 <a-table:data-source="dataSource":columns="columns":pagination="pagination" > <!-- ↑…

02 docker安装

这里写目录标题CenterOS安装使用远程镜像仓库安装设置yum远程仓库第二步&#xff1a;安装docker安装第三步&#xff1a;docker镜像加速器debian/Ubuntu安装docker官网&#xff1a;https://www.docker.com/ docker镜像库&#xff1a;https://hub.docker.com/ Docker CE&#xf…

truffle安装问题-无法加载文件

在powershell 下输入以下命令 set-executionpolicy remotesigned问题解决搜索 复制

【C语言】文件版本通讯录

文章目录文件版本通讯录一、test.c&#xff08;通讯录主干&#xff09;1.通讯录菜单的实现2.创建通讯录&#xff0c;初始化通讯录3.通讯录功能的调用二、contact.c(函数的实现)1.通讯录初始化2.查看联系人是否存在函数实现3.单个修改联系人各项的信息函数实现4.修改联系人信息目…

【PyTorch深度学习项目实战100例】—— 基于Transformer实现Twitter文本隐喻二分类 | 第43例

前言 大家好,我是阿光。 本专栏整理了《PyTorch深度学习项目实战100例》,内包含了各种不同的深度学习项目,包含项目原理以及源码,每一个项目实例都附带有完整的代码+数据集。 正在更新中~ ✨ 🚨 我的项目环境: 平台:Windows10语言环境:python3.7编译器:PyCharmPy…

[Vue] TodoList 案例

前言 系列文章目录&#xff1a; [Vue]目录 老师的课件笔记&#xff0c;不含视频 https://www.aliyundrive.com/s/B8sDe5u56BU 笔记在线版&#xff1a; https://note.youdao.com/s/5vP46EPC 视频&#xff1a;尚硅谷Vue2.0Vue3.0全套教程丨vuejs从入门到精通 文章目录前言1. 组件…

《uni-app》一个非canvas的飞机对战小游戏实现-敌机模型实现

这是一个没有套路的前端博主&#xff0c;热衷各种前端向的骚操作&#xff0c;经常想到哪就写到哪&#xff0c;如果有感兴趣的技术和前端效果可以留言&#xff5e;博主看到后会去代替大家踩坑的&#xff5e;接下来的几篇都是uni-app的小实战&#xff0c;有助于我们更好的去学习u…

行业大洗牌,软件测试饱和了?到底怎样才能走出职场困境......

人生三大emo瞬间&#xff1a;工作不顺&#xff0c;薪资不涨&#xff0c;求职被拒。 都说成年人的世界里没有容易二字&#xff0c;这句话在职场里体现地淋漓尽致&#xff1a; 工作5年&#xff0c;还没来得及升职&#xff0c;薪资被倒挂&#xff0c;岗位被优化&#xff1b;晚上…

无代码 AI 概览(Levity)

介绍 在构建我们自己的平台时&#xff0c;我们一直密切关注无代码 AI 领域。 我们意识到非技术人员构建定制的人工智能解决方案和人工智能驱动的流程自动化是多么困难。 虽然无代码市场作为一个整体正在成熟&#xff08;Dreamweaver 和 MS Frontpage&#xff0c;最早的 WYSIWYG…

开源在线客服系统源码(支持PC/H5/公众号/小程序)基于golang的网页在线客服系统

近年来市面上出现了越来越多的在线客服系统,还不断有新的在线客服企业加入,这让刚接触在线客服系统的人挑得眼花缭乱,那到底应该怎么选择一个适合企业使用的在线客服系统呢 我先给大家介绍下在线客服发展的历史,然后介绍下客服系统都有哪些功能,最后我们根据各类条件来筛选…

代码随想录算法训练营第四天 | 24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题 02.07. 链表相交 142.环形链表II

24. 两两交换链表中的节点 本题是一道模拟过程的题目。搞清楚两两交换的步骤之后,写出对应的代码也就不是难题了。不过在学习题解的过程中发现,两两交换的步骤也有很多种实现方式。自己在做题目的时候使用的思路如下:进行两两交换之前,设置三个指针,分别指向dummy,head和…

记录一下java生产环境CPU占用过高实例

背景&#xff1a;今天还是像往常一样下班后坐公交车回家&#xff0c;突然工作微信群里发来一个截图&#xff0c;我点开一看是我之前上线的服务占用CPU过高了导致程序直接卡死。记录分享一下我的解决思路希望可以帮到你们。 目录 1. top【先查看监控里每个逻辑cpu情况】 2. jm…