贝塞尔曲线(Bezier Curve)原理、公式推导及matlab代码实现

目录

参考链接

定义

直观理解

 公式推导

一次贝塞尔曲线(线性公式)

二次贝塞尔曲线(二次方公式)

 三次贝塞尔曲线(三次方公式)

n次贝塞尔曲线(一般参数公式)

代码实现


参考链接

贝塞尔曲线(Bezier Curve)原理及公式推导_bezier曲线-CSDN博客

贝塞尔曲线(Bezier Curve)原理、公式推导及matlab代码实现-CSDN博客

贝塞尔曲线——这个是可以在线控制点来绘制贝塞尔曲线的网站

定义

贝塞尔曲线用于计算机图形绘制形状,CSS 动画和许多其他地方。

贝塞尔曲线(Bezier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线,贝兹曲线定义:起始点、终止点(也称锚点)、控制点。通过调整控制点,贝塞尔曲线的形状会发生变化。 贝塞尔曲线是计算机图形学中相当重要的参数曲线,在一些比较成熟的位图软件中也有贝塞尔曲线工具,如PhotoShop等。

1962年,法国数学家Pierre Bézier第一个研究了这种矢量绘制曲线的方法,并给出了详细的计算公式,因此按照这样的公式绘制出来的曲线就用他的姓氏来命名,称为贝塞尔曲线。

贝塞尔曲线的一些特性:

  • 使用n个控制点\{P_1,P_2,\cdots ,P_n\}来控制曲线的形状
  • 曲线通过起始点P_1 和终止点P_n,接近但不通过中间点P_2\sim P_{n-1}
  • 曲线的阶次等于控制点的数量减一。 对于两个点我们能得到一条线性曲线(直线),三个点 — 一条二阶曲线,四个点 — 一条三阶曲线。

  • 曲线总是在控制点的凸包内部

由于最后一个属性,在计算机图形学中,可以优化相交测试。如果凸包不相交,则曲线也不相交。因此,首先检查凸包的交叉点可以非常快地给出“无交叉”结果。检查交叉区域或凸包更容易,因为它们是矩形,三角形等(见上图),比曲线简单的多。

直观理解

Step 1. 在二维平面内选三个不同的点并依次用线段连接

Step 2. 在线段ABBC上找到DE两点,使得\frac{AD}{DB}=\frac{BE}{EC}

 Step 3. 连接DE,并在DE上找到F点,使其满足\frac{DE}{FE}=\frac{AD}{DB}=\frac{BE}{EC}(抛物线的三切线定理)

Step 4. 找出符合上述条件的所有点

 上述为一个二阶贝塞尔曲线。同样的有n阶贝塞尔曲线:

曲线图示
一阶

二阶

三阶

四阶

五阶

 公式推导

一次贝塞尔曲线(线性公式)

定义:给定点P_0P_1,线性贝塞尔曲线只是一条两点之间的直线,这条线由下式给出,且其等同于线性插值:

B(t)=P_0+(P_0-P_1)t=(1-t)P_0+tP_1,t\in [0,1]

其中,公式里的P_0P_1同步表示为其xy轴坐标。

假设P_0坐标为(a.b)P_1坐标为(c,d)P_2坐标为(x,y),则有:

 \frac{x-a}{c-x}=\frac{t}{1-t}\Rightarrow x=(1-t)a+tc

同理有:

\frac{y-b}{d-y}=\frac{t}{1-t}\Rightarrow y=(1-t)b+td

于是可将上式简写为:


B(t)=(1-t)P_0+tP_1,t\in [0,1]

二次贝塞尔曲线(二次方公式)

定义:二次贝塞尔曲线的路径由给定点P_0P_1P_2的函数B(t)给出:

B(t)=(1-t)^2P_0+2t(1-t)P_1+t^2P_2,t\in [0,1]

 假设P_0P_1上的点为AP_1P_2上的点为BAB上的点为C(也即C为曲线上的点。则根据一次贝塞尔曲线公式有:

A=(1-t)P_0+tP_1

B=(1-t)P_1+tP_2

C=(1-t)A+tB

将上式中AB带入C中,即可得到二次贝塞尔曲线的公式:


B(t)=(1-t)^2P_0+2t(1-t)P_1+t^2P_2,t\in [0,1]

 三次贝塞尔曲线(三次方公式)

同理可得三次贝塞尔曲线公式:

B(t)=(1-t)^3P_0+3t(1-t)^2P_1+3t^2(1-t)P_2+t^3P_3,t\in [0,1]

n次贝塞尔曲线(一般参数公式)

定义:给定点P_0P_1\cdots ,P_n,则n次贝塞尔曲线由下式给出:

n次贝塞尔曲线的公式可由如下递归表达:

 \mathrm{P}_{0}^{\mathrm{n}}=(1-\mathrm{t}) \mathrm{P}_{0}^{\mathrm{n}-1}+\mathrm{tP}_{1}^{\mathrm{n}-1}, \mathrm{t} \in[0,1]

进一步可以得到贝塞尔曲线的递推计算公式:

\mathrm{P}_{\mathrm{i}}^{\mathrm{k}}\left\{\begin{array}{l} \mathrm{P}_{\mathrm{i}}, \mathrm{k}=0 \\ (1-\mathrm{t}) \mathrm{P}_{\mathrm{i}}^{\mathrm{k}-1}+\mathrm{tP}_{\mathrm{i}+1}^{\mathrm{k}-1}, \mathrm{k}=1,2, \ldots, \mathrm{n} ; \mathrm{i}=0,1, \ldots, \mathrm{n}-\mathrm{k} \end{array}\right.

代码实现

首先来看不同阶数的贝塞尔曲线公式,来找共同点:

N=2:         B(t)=(1-t)P_0+tP_1,t\in [0,1]

N=3:         B(t)=(1-t)^2P_0+2t(1-t)P_1+t^2P_2,t\in [0,1]

N=4:        B(t)=(1-t)^3P_0+3t(1-t)^2P_1+3t^2(1-t)P_2+t^3P_3,t\in [0,1]

可将贝塞尔曲线一般参数公式中的表达式用如下方式表示:
设有常数 a,b 和 c,则该表达式可统一表示为如下形式:

a(1-t)^bt^cP_n

根据上面的分析就可以总结出 a,b,c 对应的取值规则:

b: (N - 1)递减到 0 (b 为 1-t 的幂)
c: 0 递增到 (N - 1) (c 为 t 的幂)
a: 在 N 分别为 1,2,3,4,5 时将其值用如下形式表示: 

N=1:---------1
N=2:--------1 1
N=3:------1 2 1
N=4:-----1 3 3 1
N=5:---1 4 6 4 1
a 值的改变规则为: 杨辉三角

-------------------------------------------------------------------

理论基础有了,开始写代码

a 值用杨辉三角计算,b ,c 值在for 循环里计算,P_n从传入的点坐标读取。

step1:首先使用杨辉三角的方式生成a值
 

    N = len(control_points)ta = np.zeros((N, N))# 初始化杨辉三角左右两边的值为1for i in range(N):ta[i, 0] = 1ta[i, i] = 1# 计算杨辉三角for row in range(2, N):for col in range(1, row):ta[row, col] = ta[row-1, col-1] + ta[row-1, col]

step2:生成贝塞尔曲线上的点

    p = np.zeros((M, 2))for i in range(M):t = i / M  # 确定每一个点的比例for k in range(N):c = k  # 分别确定 a, b, c 三个系数b = N - c - 1  # 分别确定 a, b, c 三个系数a = ta[N-1, k]  # 分别确定 a, b, c 三个系数# 确定点的 x 和 y 坐标p[i, 0] += a * (1 - t)**b * t**c * control_points[k, 0]p[i, 1] += a * (1 - t)**b * t**c * control_points[k, 1]

完整代码


# N表示控制点个数,M表示时间步
import numpy as np
from scipy.special import combdef calculate_bezier_curve(control_points, M=1000):N = len(control_points)ta = np.zeros((N, N))# 初始化杨辉三角左右两边的值为1for i in range(N):ta[i, 0] = 1ta[i, i] = 1# 计算杨辉三角for row in range(2, N):for col in range(1, row):ta[row, col] = ta[row-1, col-1] + ta[row-1, col]p = np.zeros((M, 2))for i in range(M):t = i / M  # 确定每一个点的比例for k in range(N):c = k  # 分别确定 a, b, c 三个系数b = N - c - 1  # 分别确定 a, b, c 三个系数a = ta[N-1, k]  # 分别确定 a, b, c 三个系数# 确定点的 x 和 y 坐标p[i, 0] += a * (1 - t)**b * t**c * control_points[k, 0]p[i, 1] += a * (1 - t)**b * t**c * control_points[k, 1]return p# 示例调用
control_points = np.array([(0, 0), (1, 2), (2, 0)])
result_points = calculate_bezier_curve(control_points)# 打印结果
print(result_points)# 可视化
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 6))
plt.plot(result_points[:, 0], result_points[:, 1], label='Bezier Curve')

下图是一个生成的二阶贝塞尔曲线(有3个控制点)

 另外一种实现方式:

def bezier_curve(points, n_times=1000):"""Generate a Bezier curve from control points.Args:points (list of tuples): control points.n_times (int): number of time steps (resolution of the curve).Returns:list of tuples: points on the bezier curve."""n_points = len(points)t = np.linspace(0, 1, n_times)curve = np.zeros((n_times, 2))for i in range(n_points):binom = comb(n_points - 1, i) # 计算二项式系数,即组合数。表示从 n_points - 1 个元素中选择 i 个元素的方式有多少种。curve += np.outer(binom * (t ** i) * ((1 - t) ** (n_points - 1 - i)), points[i])return curvecontrol_points1 = [(0, 0), (1, 2), (2, 0)]
bezier1 = bezier_curve(control_points1)
print(bezier1)

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

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

相关文章

20. 从零用Rust编写正反向代理,四层反向代理stream(tcp与udp)实现

wmproxy wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 静态文件服务器,四层TCP/UDP转发,内网穿透,后续将实现websocket代理等,会将实现过程分享出来,感兴趣的可以一起造个轮子 项目地址 gite: https:…

GPT应用程序上线注意的问题

在将GPT应用程序上线之前,有一些重要的问题需要注意,以确保应用程序的成功运行、用户满意度和合规性。以下是一些建议,希望对大家有所帮助。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎交流合作。 合规性和…

如何查看iPad尺寸,这里提供两种办法

构成iPad尺寸的因素包括屏幕大小、宽度、深度和高度。由于iPad有不同的尺寸,你可以毫不费力地测量自己的尺寸。 苹果的iPad是当今最畅销的小工具之一。它是笔记本电脑的绝佳替代品,非常适合完成工作、看电影和上网。然而,出于各种目的&#…

STM32-调用 vTaskStartScheduler API 后出现 HardFault

STM32 移植 FreeRTOS 后调用 vTaskStartScheduler() 后出现 HardFault 异常。 原因分析: FreeRTOS 配置头文件 FreeRTOSConfig.h 中与中断有关的配置和通过系统接口 void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup) 设置的中断分组冲突。 /* The lo…

Spring Security工作原理(一)

过滤器 Spring Security的Servlet支持是基于Servlet过滤器的,因此首先了解过滤器的一般作用是很有帮助的。下图显示了单个HTTP请求处理程序的典型分层结构。 处理客户端发送的请求时,容器创建一个FilterChain,其中包含Filter实例和Servlet&a…

【C++】:STL序列式容器list源码剖析

一、list概述 总的来说:环形双向链表 特点: 底层是使用链表实现的,支持双向顺序访问 在list中任何位置进行插入和删除的速度都很快 不支持随机访问,为了访问一个元素,必须遍历整个容器 与其他容器相比,额外…

基于Python的Climate Indices库计算SPEI(标准化降水蒸散发指数)05—栅格SPEI的计算

热闹的尽头是孤寂,在虚浮的欢闹中保持自己,纷繁世间,可报期望者不过二三。 文章目录 前言1. 概述2.1 目的2.2 说明 2. 版本2.1 天津,2024年1月18日,Version1 3. 微信公众号GISRSGeography 一、数据1. 输入数据2. 输出…

MySQL---经典SQL练习题

MySQL---经典50道练习题 素材:练习题目:解题: 素材: 1.学生表 Student(SId,Sname,Sage,Ssex) SId 学生编号,Sname 学生姓名,Sage 出生年月,Ssex 学生性别 2.课程表 Course(CId,Cname,TId) CId 课程编号,Cname 课程名称,TId 教师编号 3.教师表 Teacher(T…

Spring重要知识点

一、Spring中相关概念 1.IOC 控制反转 IoC(Inverse of Control:控制反转)是⼀种设计思想,就是将原本在程序中⼿动创建对象的控制权,交由Spring框架来管理。IoC 在其他语⾔中也有应⽤,并⾮ Spring 所独有。 IoC 容器…

ADSelfService Plus 推出离线多因素身份验证以提升远程工作安全性

采用先进验证方法,确保在任何时间、地点或连接问题下对业务数据的合法访问即使远程用户未连接到身份验证服务器或互联网,也可通过MFA安全认证。 MFA 得克萨斯州德尔瓦雷 — 2023年5月3日 — Zoho Corporation 旗下的企业IT管理部门ManageEngine今日宣布…

加速电压对扫描电子显微镜成像的影响

扫描电子显微镜(SEM)是一种利用聚焦电子束扫描样品表面,通过激发和收集二次电子、特征X射线等信号,获得样品表面形貌和成分信息的分析仪器。在SEM成像过程中,加速电压是一个关键参数,对成像效果具有重要影响…

WordPress回收站自动清空时间?如何关闭回收站或设置自动清理天数?

我们在WordPress后台的文章、页面、评论等页面都可以看到有回收站,意思就是我们不能直接删除某篇文章、页面、评论,而是需要现将它们移至回收站,然后再到回收站永久删除,或等回收站自动清理。 如上图所示,WordPress 6.…