【Bezier + BSpline + CatmullRom】移动机器人曲线路径规划

问题:现有 n + 1 n+1 n+1个2维的离散点 P i = ( x i , y i ) , ( i = 0 , 1 , ⋯   , n ) {P_i} = \left( {{x_i},{y_i}} \right),\left( {i = 0,1, \cdots ,n} \right) Pi=(xi,yi),(i=0,1,,n), 如何用 P i {P_i} Pi拟合一条平滑的曲线,最后将曲线分割成数条 2阶/3阶贝塞尔曲线,并保证这数条曲线段拼接处是连续的,即全局可导。

2阶Bezier3阶Bezier
在这里插入图片描述在这里插入图片描述

1 Bezier路径拟合


1.1 Bezier曲线绘制原理

Bezier曲线有两个简单的规律:
1、k阶的Bezier曲线需要用到k+1个数据点。 如: 3阶Bezier曲线需要用到4个数据点。
2、Berzier曲线只保证经过起点和终点,不保证经过中间所有的控制点。Berzier曲线用到的第1个数据点和倒数第1个数据点分别被称为起点和终点,中间的所有数据被称为控制点。

关注 P i {P_i} Pi的4个数据点:
P 0 = ( x 0 , y 0 ) , P 1 = ( x 1 , y 1 ) , P 2 = ( x 2 , y 2 ) , P 3 = ( x 3 , y 3 ) {P_0} = \left( {{x_0},{y_0}} \right),{P_1} = \left( {{x_1},{y_1}} \right),{P_2} = \left( {{x_2},{y_2}} \right),{P_3} = \left( {{x_3},{y_3}} \right) P0=(x0,y0),P1=(x1,y1),P2=(x2,y2),P3=(x3,y3)

定义向量 t ≜ 0 : δ t : 1 t \triangleq 0:\delta t:1 t0:δt:1(这是MatLAB的写法, δ t \delta t δt决定曲线绘制精度)。
1阶、2阶、3阶和n阶的Bezier曲线公式分别如下:
B 1 s t = ( 1 − t ) P 0 + t P 1 B 2 n d = ( 1 − t ) 2 P 0 + 2 ( 1 − t ) t P 1 + t 2 P 2 B 3 r d = ( 1 − t ) 3 P 0 + 3 ( 1 − t ) 2 t P 1 + 3 ( 1 − t ) t 2 P 2 + t 3 P 3 B n t h = ∑ i = 0 n a ( i ) ⋅ ( 1 − t ) b ( i ) ⋅ t c ( i ) ⋅ P i (1) \begin{aligned}{B_{1st}} &= \left( {1 - t} \right){P_0} + t{P_1}\\ {B_{2nd}} &= {\left( {1 - t} \right)^2}{P_0} + 2\left( {1 - t} \right)t{P_1} + {t^2}{P_2}\\ {B_{3rd}} &= {\left( {1 - t} \right)^3}{P_0} + 3{\left( {1 - t} \right)^2}t{P_1} + 3\left( {1 - t} \right){t^2}{P_2} + {t^3}{P_3}\\ {B_{nth}} &= \sum\limits_{i = 0}^n {a\left( i \right) \cdot {{\left( {1 - t} \right)}^{b\left( i \right)}} \cdot {t^{c\left( i \right)}} \cdot {P_i}}\end{aligned} \tag{1} B1stB2ndB3rdBnth=(1t)P0+tP1=(1t)2P0+2(1t)tP1+t2P2=(1t)3P0+3(1t)2tP1+3(1t)t2P2+t3P3=i=0na(i)(1t)b(i)tc(i)Pi(1)

其中,
{ a ( i ) =   n + 1 阶杨辉三角第 n + 1 行的第 i + 1 列的数 b ( i ) = n − i ; c ( i ) = i \left\{ \begin{aligned} a\left( i \right) &= {\text{ }}n + 1 阶杨辉三角第n+1行的第i+1列的数 \\ b\left( i \right) &= n - i;c\left( i \right) = i \\ \end{aligned} \right. {a(i)b(i)= n+1阶杨辉三角第n+1行的第i+1列的数=ni;c(i)=i

下面给出计算 n + 1 n+1 n+1阶杨辉三角矩阵的Matlab代码

clear all; close all; clc;
n = 5;
YH = zeros(n+1,n+1);
for i = 1:1:n+1
    YH(i,1) = 1; %1列元素
    YH(i,i) = 1; % 对角线元素
end

for i = 3:1:n+1 % 从第三行开始,因为前两行都是1
    for j = 2:1:i-1 %1列和第i列已经都被赋值为1YH(i,j) = YH(i-1,j-1) + YH(i-1,j);
    end
end

a = YH(n+1,:) % 取n+1行作为系数

% 运行结果 
% n = 0;	1
% n = 1;	1     1
% n = 2;	1     2     1
% n = 3;	1     3     3     1
% n = 4;	1     4     6     4     1
% n = 5;	1     5    10    10     5     1

1.2 基于Bezier曲线的路径拟合实验

2阶Bezier曲线绘制如下:
2阶Bezier曲线绘制
3阶Bezier曲线绘制如下:
3阶Bezier曲线绘制
n阶-Bezier曲线绘制如下 (n = 10)
n阶Bezier曲线绘制

实验结果分析
1、对于 n + 1 n+1 n+1个离散数据点,用 n n n阶的Bezier曲线来路径拟合并不是一个好的选择,很明显,上图的拟合效果很差
2、用 n n n阶Bezier曲线路径拟合会导致运算量暴增,阶次爆炸。
3、除计算量问题外,根据Bezier本身的原理,我们也是无法直接把 n n n阶Bezier分割成多个2阶/3阶的贝塞尔曲线的。

要解决本文所提问题,我们只能通过其他的曲线拟合方法先实现路径拟合,然后再把它分割转换成2阶/3阶贝塞尔曲线的描述方式。下面将会介绍BSpline和Catmull_ROM两种曲线拟合方法。


2 BSpline路径拟合-分段拼接

通过调研发现,用BSpline曲线来拟合路径,是可以采用分段拼接的方式的,而且它可以保证拼接处是连续的,即全局可导。

2.1 Bspline曲线绘制原理

BSpline曲线有两个简单的规律:
1、k阶的BSpline曲线需要用到k+1个数据点。 如: 3阶BSpline曲线需要用到4个数据点。
2、BSpline曲线的特点是不经过任何数据点(这让我觉得用这个东西搞路径拟合有点离谱)

关注 P i {P_i} Pi的4个数据点:
P 0 = ( x 0 , y 0 ) , P 1 = ( x 1 , y 1 ) , P 2 = ( x 2 , y 2 ) , P 3 = ( x 3 , y 3 ) {P_0} = \left( {{x_0},{y_0}} \right),{P_1} = \left( {{x_1},{y_1}} \right),{P_2} = \left( {{x_2},{y_2}} \right),{P_3} = \left( {{x_3},{y_3}} \right) P0=(x0,y0),P1=(x1,y1),P2=(x2,y2),P3=(x3,y3)

定义向量 t ≜ 0 : δ t : 1 t \triangleq 0:\delta t:1 t0:δt:1(这是MatLAB的写法, δ t \delta t δt决定曲线绘制精度)。
2阶BSpline拟合公式:
{ a 0 = 1 2 ( x 0 + x 1 ) a 1 = x 1 − x 0 a 2 = 1 2 ( x 0 − 2 x 1 + x 2 ) , { b 0 = 1 2 ( y 0 + y 1 ) b 1 = y 1 − y 0 b 2 = 1 2 ( y 0 − 2 y 1 + y 2 ) (2) \left\{ \begin{aligned} {a_0} &= \frac{1}{2}\left( {{x_0} + {x_1}} \right) \\ {a_1} &= {x_1} - {x_0} \\ {a_2} &= \frac{1}{2}\left( {{x_0} - 2{x_1} + {x_2}} \right) \\ \end{aligned} \right.,\left\{ \begin{aligned} {b_0} &= \frac{1}{2}\left( {{y_0} + {y_1}} \right) \\ {b_1} &= {y_1} - {y_0} \\ {b_2} &= \frac{1}{2}\left( {{y_0} - 2{y_1} + {y_2}} \right) \\ \end{aligned} \right.\tag{2} a0a1a2=21(x0+x1)=x1x0=21(x02x1+x2), b0b1b2=21(y0+y1)=y1y0=21(y02y1+y2)(2)

B ( t ) = ( x ( t ) , y ( t ) ) ⇒ { x ( t ) = a 0 + a 1 t + a 2 t 2 y ( t ) = b 0 + b 1 t + b 2 t 2 (3) B\left( t \right) = \left( {x\left( t \right),y\left( t \right)} \right) \Rightarrow \left\{ \begin{aligned} x\left( t \right) &= {a_0} + {a_1}t + {a_2}{t^2} \\ y\left( t \right) &= {b_0} + {b_1}t + {b_2}{t^2} \\ \end{aligned} \right.\tag{3} B(t)=(x(t),y(t)){x(t)y(t)=a0+a1t+a2t2=b0+b1t+b2t2(3)

3阶BSpline拟合公式:
{ a 0 = 1 6 ( x 0 + 4 x 1 + x 2 ) a 1 = − 1 2 ( x 0 − x 2 ) a 2 = 1 2 ( x 0 − 2 x 1 + x 2 ) a 3 = − 1 6 ( x 0 − 3 x 1 + 3 x 2 − x 3 ) , { b 0 = 1 6 ( y 0 + y x 1 + y 2 ) b 1 = − 1 2 ( y 0 − y 2 ) b 2 = 1 2 ( y 0 − 2 y 1 + y 2 ) b 3 = − 1 6 ( y 0 − 3 y 1 + 3 y 2 − y 3 ) (4) \left\{ \begin{aligned} {a_0} &= \frac{1}{6}\left( {{x_0} + 4{x_1} + {x_2}} \right) \\ {a_1} &= - \frac{1}{2}\left( {{x_0} - {x_2}} \right) \\ {a_2} &= \frac{1}{2}\left( {{x_0} - 2{x_1} + {x_2}} \right) \\ {a_3} &= - \frac{1}{6}\left( {{x_0} - 3{x_1} + 3{x_2} - {x_3}} \right) \\ \end{aligned} \right.,\left\{ \begin{aligned} {b_0} &= \frac{1}{6}\left( {{y_0} + y{x_1} + {y_2}} \right) \\ {b_1} &= - \frac{1}{2}\left( {{y_0} - {y_2}} \right)\\ {b_2} &= \frac{1}{2}\left( {{y_0} - 2{y_1} + {y_2}} \right) \\ {b_3} &= - \frac{1}{6}\left( {{y_0} - 3{y_1} + 3{y_2} - {y_3}} \right) \\ \end{aligned} \right.\tag{4} a0a1a2a3=61(x0+4x1+x2)=21(x0x2)=21(x02x1+x2)=61(x03x1+3x2x3), b0b1b2b3=61(y0+yx1+y2)=21(y0y2)=21(y02y1+y2)=61(y03y1+3y2y3)(4)

B ( t ) = ( x ( t ) , y ( t ) ) ⇒ { x ( t ) = a 0 + a 1 t + a 2 t 2 + a 3 t 3 y ( t ) = b 0 + b 1 t + b 2 t 2 + b 3 t 3 (5) B\left( t \right) = \left( {x\left( t \right),y\left( t \right)} \right) \Rightarrow \left\{ \begin{aligned} x\left( t \right) &= {a_0} + {a_1}t + {a_2}{t^2} + {a_3}{t^3} \\ y\left( t \right) &= {b_0} + {b_1}t + {b_2}{t^2} + {b_3}{t^3} \\ \end{aligned} \right.\tag{5} B(t)=(x(t),y(t)){x(t)y(t)=a0+a1t+a2t2+a3t3=b0+b1t+b2t2+b3t3(5)


2.2 Bspline分段拼接方法

假设现在有待拟合的n+1个离散点 P i = ( x i , y i ) , ( i = 0 , 1 , ⋯   , n ) {P_i} = \left( {{x_i},{y_i}} \right),\left( {i = 0,1, \cdots ,n} \right) Pi=(xi,yi),(i=0,1,,n) ,采用2阶BSpline分段拼接拟合过程如下:
P 0 , P 1 , P 2 {P_0},{P_1},{P_2} P0,P1,P2为控制点绘制第1条2阶BSpline
P 1 , P 2 , P 3 {P_1},{P_2},{P_3} P1,P2,P3为控制点绘制第2条2阶BSpline

P n − 2 , P n − 1 , P n {P_{n-2}},{P_{n-1}},{P_{n}} Pn2,Pn1,Pn为控制点绘制第n-1条2阶BSpline
由于BSpline曲线不经过任何控制点,我们想让它经过第一个控制 P 0 P_0 P0和最后一个 P n P_ n Pn控制点 ,则需要修改 P 0 P_0 P0 P n P_ n Pn。 注意2阶BSpline曲线与控制点相连线段相切于其中点。

在这里插入图片描述在这里插入图片描述

P 1 − P 0 = P 0 − P 0 ′ ⇒ P 0 ′ = 2 P 0 − P 1 P n ′ − P n = P n − P n − 1 ⇒ P n ′ = 2 P n − P n − 1 (6) \begin{aligned} {P_1} - {P_0} &= {P_0} - P_0' \Rightarrow P_0' = 2{P_0} - {P_1} \\ P_n' - {P_n} &= {P_n} - {P_{n - 1}} \Rightarrow P_n' = 2{P_n} - {P_{n - 1}} \\ \end{aligned}\tag{6} P1P0PnPn=P0P0P0=2P0P1=PnPn1Pn=2PnPn1(6)

假设现在有待拟合的n+1个离散点 P i = ( x i , y i ) , ( i = 0 , 1 , ⋯   , n ) {P_i} = \left( {{x_i},{y_i}} \right),\left( {i = 0,1, \cdots ,n} \right) Pi=(xi,yi),(i=0,1,,n) ,采用3阶BSpline分段拼接拟合过程如下:
P 0 , P 1 , P 2 , P 3 {P_0},{P_1},{P_2},{P_3} P0,P1,P2,P3为控制点绘制第1条3阶BSpline
P 1 , P 2 , P 3 , P 4 {P_1},{P_2},{P_3},{P_4} P1,P2,P3,P4为控制点绘制第2条3阶BSpline

P n − 3 , P n − 2 , P n − 1 , P n {P_{n-3}},{P_{n-2}},{P_{n-1}},{P_{n}} Pn3,Pn2,Pn1,Pn为控制点绘制第n-2条3阶BSpline
由于BSpline不经过任何控制点,我们想让它经过第一个控制 P 0 P_0 P0和最后一个 P n P_ n Pn控制点 ,则需要修改 P 0 P_0 P0 P n P_ n Pn 。 修改前先描述一下3阶BSpline曲线与控制点之间的关系。
在这里插入图片描述
M 1 M_1 M1 P 0 P_0 P0 P 2 P_2 P2的中点, M 2 M_2 M2 P 1 P_1 P1 P 3 P_3 P3的中点, P 1 S = 1 3 P 1 M 1 {P_1}S = \frac{1}{3}{P_1}{M_1} P1S=31P1M1 P 2 E = 1 3 P 2 M 2 {P_2}E = \frac{1}{3}{P_2}{M_2} P2E=31P2M2, S E ~ \tilde{SE} SE~就是我们通过这4个控制点画出的3阶BSpline曲线。

现在修改为:

在这里插入图片描述在这里插入图片描述

{ M = 1 2 ( P 0 ′ + P 2 ) 3 ( P 0 − P 1 ) = M − P 1 ⇒ P 0 ′ = 6 P 0 − 4 P 1 − P 2 (7) \left\{ \begin{aligned} M &= \frac{1}{2}\left( {P_0' + {P_2}} \right)\\ 3\left( {{P_0} - {P_1}} \right) &= M - {P_1} \end{aligned} \right. \Rightarrow P_0' = 6{P_0} - 4{P_1} - {P_2}\tag{7} M3(P0P1)=21(P0+P2)=MP1P0=6P04P1P2(7)

同理,
P n ′ = 6 P n − 4 P n − 1 − P n − 2 (8) P_n' = 6{P_n} - 4{P_{n - 1}} - {P_{n - 2}}\tag{8} Pn=6Pn4Pn1Pn2(8)


2.3 基于BSpline曲线的路径拟合实验

2阶BSpline
在这里插入图片描述
2阶Bspline拟合11个数据点(不修改P0和Pn点,双击图片可放大看细节)
在这里插入图片描述
2阶Bspline拟合11个数据点(修改P0和Pn点,双击图片可放大看细节)
在这里插入图片描述
3阶BSpline
在这里插入图片描述
3阶Bspline拟合11个数据点(不修改P0和Pn点,双击图片可放大看细节)
在这里插入图片描述
3阶Bspline拟合11个数据点(修改P0和Pn点,双击图片可放大看细节)
在这里插入图片描述

实验结果分析
1、验证了BSpline用分段拼接拟合的可行性,很明显,拟合曲线是全局可导的;
2、拟合精度明显比n阶的Bezier曲线要高。对于 n + 1 n+1 n+1个离散数据点,现在我们已经用 n − 1 n-1 n1条的2阶BSpline曲线或者 n − 2 n-2 n2条的3阶BSpline曲线拼接拟合,完成。

现在的问题是如何将2阶和3阶的BSpline曲线用Bezier曲线的描述。


2.4 BSpline To Bezier

以2阶为例

2阶Bezier公式如下
B 2 n d = ( 1 − t ) 2 P 0 + 2 ( 1 − t ) t P 1 + t 2 P 2 {B_{2nd}} = {\left( {1 - t} \right)^2}{P_0} + 2\left( {1 - t} \right)t{P_1} + {t^2}{P_2} B2nd=(1t)2P0+2(1t)tP1+t2P2

2阶BSpline公式如下
{ a 0 = 1 2 ( x 0 + x 1 ) a 1 = x 1 − x 0 a 2 = 1 2 ( x 0 − 2 x 1 + x 2 ) , { b 0 = 1 2 ( y 0 + y 1 ) b 1 = y 1 − y 0 b 2 = 1 2 ( y 0 − 2 y 1 + y 2 ) \left\{ \begin{aligned} {a_0} &= \frac{1}{2}\left( {{x_0} + {x_1}} \right) \\ {a_1} &= {x_1} - {x_0} \\ {a_2} &= \frac{1}{2}\left( {{x_0} - 2{x_1} + {x_2}} \right) \\ \end{aligned} \right.,\left\{ \begin{aligned} {b_0} &= \frac{1}{2}\left( {{y_0} + {y_1}} \right) \\ {b_1} &= {y_1} - {y_0} \\ {b_2} &= \frac{1}{2}\left( {{y_0} - 2{y_1} + {y_2}} \right) \\ \end{aligned} \right. a0a1a2=21(x0+x1)=x1x0=21(x02x1+x2), b0b1b2=21(y0+y1)=y1y0=21(y02y1+y2)

B ( t ) = ( x ( t ) , y ( t ) ) ⇒ { x ( t ) = a 0 + a 1 t + a 2 t 2 y ( t ) = b 0 + b 1 t + b 2 t 2 B\left( t \right) = \left( {x\left( t \right),y\left( t \right)} \right) \Rightarrow \left\{ \begin{aligned} x\left( t \right) &= {a_0} + {a_1}t + {a_2}{t^2} \\ y\left( t \right) &= {b_0} + {b_1}t + {b_2}{t^2} \\ \end{aligned} \right. B(t)=(x(t),y(t)){x(t)y(t)=a0+a1t+a2t2=b0+b1t+b2t2

观察规律, 无论Bezier还是BSpline都是关于 t t t的2阶线性函数,因此从原理上他们是可以完全等价的。观察Bezier的公式, t t t的系数完全由控制点 P 0 , P 1 , P 2 {P_0},{P_1},{P_2} P0,P1,P2确定,也就是说3个控制可以唯一确定一条2阶的Bezier曲线,那么我们只要求出 P 0 , P 1 , P 2 {P_0},{P_1},{P_2} P0,P1,P2就完成了BSpline到Bezier的转换。
B ( t ) = B 2 n d B\left( t \right) = {B_{2nd}} B(t)=B2nd,让 t t t的各阶系数分别相等,即可推导出 P 0 , P 1 , P 2 {P_0},{P_1},{P_2} P0,P1,P2 a 0 , a 1 , a 2 , b 0 , b 1 , b 2 {a_0},{a_1},{a_2},{b_0},{b_1},{b_2} a0,a1,a2,b0,b1,b2表示的代数表达式:

{ x 0 = a 0 x 1 = a 0 + 1 2 a 1 x 2 = a 0 + a 1 + a 2 , { y 0 = b 0 y 1 = b 0 + 1 2 b 1 y 2 = b 0 + b 1 + b 2 (9) \left\{ \begin{array}{l} {x_0} = {a_0}\\\\ {x_1} = {a_0} + \frac{1}{2}{a_1}\\\\ {x_2} = {a_0} + {a_1} + {a_2} \end{array} \right.,\left\{ \begin{array}{l} {y_0} = {b_0}\\\\ {y_1} = {b_0} + \frac{1}{2}{b_1}\\\\ {y_2} = {b_0} + {b_1} + {b_2} \end{array} \right.\tag{9} x0=a0x1=a0+21a1x2=a0+a1+a2, y0=b0y1=b0+21b1y2=b0+b1+b2(9)

P 0 = ( x 0 , y 0 ) , P 1 = ( x 1 , y 1 ) , P 2 = ( x 2 , y 2 ) (10) {P_0} = \left( {{x_0},{y_0}} \right),{P_1} = \left( {{x_1},{y_1}} \right),{P_2} = \left( {{x_2},{y_2}} \right)\tag{10} P0=(x0,y0),P1=(x1,y1),P2=(x2,y2)(10)

注意:这里的 P 0 = ( x 0 , y 0 ) {P_0} = \left( {{x_0},{y_0}} \right) P0=(x0,y0),并不是原始的需要拟合的数据点。而是用Bezier来等价描述BSpline的数据点。

同理,3阶的转换公式如下:
{ x 0 = a 0 x 1 = a 0 + 1 3 a 1 x 2 = a 0 + 2 3 a 1 + 1 3 a 2 x 3 = a 0 + a 1 + a 2 + a 3 , { y 0 = b 0 y 1 = b 0 + 1 3 b 1 y 2 = b 0 + 2 3 b 1 + 1 3 b 2 y 3 = b 0 + b 1 + b 2 + b 3 (11) \left\{ \begin{array}{l} {x_0} = {a_0}\\\\ {x_1} = {a_0} + \frac{1}{3}{a_1}\\\\ {x_2} = {a_0} + \frac{2}{3}{a_1} + \frac{1}{3}{a_2}\\\\ {x_3} = {a_0} + {a_1} + {a_2} + {a_3} \end{array} \right.,\left\{ \begin{array}{l} {y_0} = {b_0}\\\\ {y_1} = {b_0} + \frac{1}{3}{b_1}\\\\ {y_2} = {b_0} + \frac{2}{3}{b_1} + \frac{1}{3}{b_2}\\\\ {y_3} = {b_0} + {b_1} + {b_2} + {b_3} \end{array} \right.\tag{11} x0=a0x1=a0+31a1x2=a0+32a1+31a2x3=a0+a1+a2+a3, y0=b0y1=b0+31b1y2=b0+32b1+31b2y3=b0+b1+b2+b3(11)

P 0 = ( x 0 , y 0 ) , P 1 = ( x 1 , y 1 ) , P 2 = ( x 2 , y 2 ) , P 3 = ( x 3 , y 3 ) (12) {P_0} = \left( {{x_0},{y_0}} \right),{P_1} = \left( {{x_1},{y_1}} \right),{P_2} = \left( {{x_2},{y_2}} \right),{P_3} = \left( {{x_3},{y_3}} \right)\tag{12} P0=(x0,y0),P1=(x1,y1),P2=(x2,y2),P3=(x3,y3)(12)

基于BSpline的路径拟合到此结束,BSpline由于其包络性平滑性,广泛应用于无人驾驶路径规划领域。但由于BSpline不经过任何数据点,在某些特殊情况下,并不适用,因此接下来我们介绍一种经过所有点的曲线拟合方式 Catmull_Rom


3 Catmull_Rom路径拟合-分段拼接

通过调研发现,用Catmull_Rom曲线来拟合路径,也是可以采用分段拼接的方式的,而且它同样可以保证拼接处是连续的,即全局可导,而且它还有一个致命优势,那就是它可以经过所有用于拟合的数据点。

3.1 Catmull_Rom曲线绘制原理

Catmull_Rom曲线有两个特点:
1、Catmull_Rom是3阶线性拟合,至少需要4个数据点;
2、假设我现在用A B C D 4个数据点绘制Catmull_Rom曲线,曲线只会经过B C

关注 P i {P_i} Pi的4个数据点:
P 0 = ( x 0 , y 0 ) , P 1 = ( x 1 , y 1 ) , P 2 = ( x 2 , y 2 ) , P 3 = ( x 3 , y 3 ) {P_0} = \left( {{x_0},{y_0}} \right),{P_1} = \left( {{x_1},{y_1}} \right),{P_2} = \left( {{x_2},{y_2}} \right),{P_3} = \left( {{x_3},{y_3}} \right) P0=(x0,y0),P1=(x1,y1),P2=(x2,y2),P3=(x3,y3)

定义向量 t ≜ 0 : δ t : 1 t \triangleq 0:\delta t:1 t0:δt:1(这是MatLAB的写法, δ t \delta t δt决定曲线绘制精度)。
Catmull_Rom拟合公式:
{ a 0 = x 1 a 1 = 1 2 ( − x 0 + x 2 ) a 2 = 1 2 ( 2 x 0 − 5 x 1 + 4 x 2 − x 3 ) a 3 = 1 2 ( − x 0 + 3 x 1 − 3 x 2 + x 3 ) , { b 0 = y 1 b 1 = 1 2 ( − y 0 + y 2 ) b 2 = 1 2 ( 2 y 0 − 5 y 1 + 4 y 2 − y 3 ) b 3 = 1 2 ( − y 0 + 3 y 1 − 3 y 2 + y 3 ) (13) \left\{ \begin{array}{l} {a_0} = {x_1}\\\\ {a_1} = \frac{1}{2}\left( { - {x_0} + {x_2}} \right)\\\\ {a_2} = \frac{1}{2}\left( {2{x_0} - 5{x_1} + 4{x_2} - {x_3}} \right)\\\\ {a_3} = \frac{1}{2}\left( { - {x_0} + 3{x_1} - 3{x_2} + {x_3}} \right) \end{array} \right.,\left\{ \begin{array}{l} {b_0} = {y_1}\\\\ {b_1} = \frac{1}{2}\left( { - {y_0} + {y_2}} \right)\\\\ {b_2} = \frac{1}{2}\left( {2{y_0} - 5{y_1} + 4{y_2} - {y_3}} \right)\\\\ {b_3} = \frac{1}{2}\left( { - {y_0} + 3{y_1} - 3{y_2} + {y_3}} \right) \end{array} \right.\tag{13} a0=x1a1=21(x0+x2)a2=21(2x05x1+4x2x3)a3=21(x0+3x13x2+x3), b0=y1b1=21(y0+y2)b2=21(2y05y1+4y2y3)b3=21(y0+3y13y2+y3)(13)

C a t m u l l _ R o m ( t ) = ( x ( t ) , y ( t ) ) ⇒ { x ( t ) = a 0 + a 1 t + a 2 t 2 + a 3 t 3 y ( t ) = b 0 + b 1 t + b 2 t 2 + b 3 t 3 (14) Catmull\_Rom\left( t \right) = \left( {x\left( t \right),y\left( t \right)} \right) \Rightarrow \left\{ \begin{array}{l} x\left( t \right) = {a_0} + {a_1}t + {a_2}{t^2} + {a_3}{t^3}\\\\ y\left( t \right) = {b_0} + {b_1}t + {b_2}{t^2} + {b_3}{t^3} \end{array} \right.\tag{14} Catmull_Rom(t)=(x(t),y(t)) x(t)=a0+a1t+a2t2+a3t3y(t)=b0+b1t+b2t2+b3t3(14)


3.2 Catmull_Rom分段拼接方法

前面我们也提到了,假设我现在用A B C D 4个数据点绘制Catmull_Rom曲线,曲线只会经过B C。如果我用B C D E个数据点绘制Catmull_Rom曲线,只会经过C D。如果想让拟合曲线经过所有控制点,则只需要分别在首和尾各添加一个控制点。
添加首尾两点的定义如下:

P s ≜ ( x s , y s ) , P e ≜ ( x e , y e ) (15) {P_s} \triangleq \left( {{x_s},{y_s}} \right),{P_e} \triangleq \left( {{x_e},{y_e}} \right)\tag{15} Ps(xs,ys),Pe(xe,ye)(15)

x s = x 0 + ( x 0 − x 1 ) y s = y 0 + ( y 0 − y 1 ) x e = x n + ( x n − x n − 1 ) y e = y n + ( y n − y n − 1 ) (16) \begin{aligned} {x_s} &= {x_0} + \left( {{x_0} - {x_1}} \right) \\ {y_s} &= {y_0} + \left( {{y_0} - {y_1}} \right) \\ {x_e} &= {x_n} + \left( {{x_n} - {x_{n - 1}}} \right)\\ {y_e} &= {y_n} + \left( {{y_n} - {y_{n - 1}}} \right) \end{aligned}\tag{16} xsysxeye=x0+(x0x1)=y0+(y0y1)=xn+(xnxn1)=yn+(ynyn1)(16)

P s , P 0 , P 1 , P 2 , P 3 , ⋯   , P n , P e {P_s},{P_0},{P_1},{P_2},{P_3}, \cdots ,{P_n},{P_e} Ps,P0,P1,P2,P3,,Pn,Pe为待拟合的数据点。

P s , P 0 , P 1 , P 2 {P_s},{P_0},{P_1},{P_2} Ps,P0,P1,P2绘制第1条Catmull_Rom曲线
P 0 , P 1 , P 2 , P 3 {P_0},{P_1},{P_2},{P_3} P0,P1,P2,P3绘制第2条Catmull_Rom曲线

P n − 2 , P n − 1 , P n , P e {P_{n-2}},{P_{n-1}},{P_n},{P_e} Pn2,Pn1,Pn,Pe为控制点绘制第n条Catmull_Rom曲线


3.3 基于Catmull_Rom曲线的路径拟合实验

直接上图
在这里插入图片描述

显然,Catmull_Rom曲线的拟合效果是很好的,对于数据点噪声较小的情况,是很适合用这种穿过所有数据点的曲线拟合方式的。


3.4 Catmull_Rom To Bezier

本质是 Catmull_Rom也是关于 t t t3阶线性函数,因此从原理上每一条Catmull_Rom曲线段是可以完全等价为3阶的Bezier曲线的。
Catmull_Rom和BSpline都是用 a 0 , a 1 , a 2 , a 3 , b 0 , b 1 , b 2 , b 3 {a_0},{a_1},{a_2},{a_3},{b_0},{b_1},{b_2},{b_3} a0,a1,a2,a3,b0,b1,b2,b3作为系数,因此Catmull_Rom的转换公式和3阶BSpline的转换公式一样。
{ x 0 = a 0 x 1 = a 0 + 1 3 a 1 x 2 = a 0 + 2 3 a 1 + 1 3 a 2 x 3 = a 0 + a 1 + a 2 + a 3 , { y 0 = b 0 y 1 = b 0 + 1 3 b 1 y 2 = b 0 + 2 3 b 1 + 1 3 b 2 y 3 = b 0 + b 1 + b 2 + b 3 (17) \left\{ \begin{array}{l} {x_0} = {a_0}\\\\ {x_1} = {a_0} + \frac{1}{3}{a_1}\\\\ {x_2} = {a_0} + \frac{2}{3}{a_1} + \frac{1}{3}{a_2}\\\\ {x_3} = {a_0} + {a_1} + {a_2} + {a_3} \end{array} \right.,\left\{ \begin{array}{l} {y_0} = {b_0}\\\\ {y_1} = {b_0} + \frac{1}{3}{b_1}\\\\ {y_2} = {b_0} + \frac{2}{3}{b_1} + \frac{1}{3}{b_2}\\\\ {y_3} = {b_0} + {b_1} + {b_2} + {b_3} \end{array} \right.\tag{17} x0=a0x1=a0+31a1x2=a0+32a1+31a2x3=a0+a1+a2+a3, y0=b0y1=b0+31b1y2=b0+32b1+31b2y3=b0+b1+b2+b3(17)

P 0 = ( x 0 , y 0 ) , P 1 = ( x 1 , y 1 ) , P 2 = ( x 2 , y 2 ) , P 3 = ( x 3 , y 3 ) (18) {P_0} = \left( {{x_0},{y_0}} \right),{P_1} = \left( {{x_1},{y_1}} \right),{P_2} = \left( {{x_2},{y_2}} \right),{P_3} = \left( {{x_3},{y_3}} \right)\tag{18} P0=(x0,y0),P1=(x1,y1),P2=(x2,y2),P3=(x3,y3)(18)

参考文献:

https://shenchunxu.blog.csdn.net/article/details/54411098?spm=1001.2014.3001.5506
https://zhuanlan.zhihu.com/p/137539722

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

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

相关文章

HDFS的API操作

目录 客户端环境准备: 添加环境变量: 配置Path环境变量: IDEA操作: 创建包名: HDFS的API案例操作: 封装代码: 封装代码1: 封装代码2: 实现操作: 1.创…

每日一博 - Java 异步编程的 Promise 模式 CompletableFuture

文章目录概述概述Executor与线程池Java 中的线程池使用线程池的注意事项强烈建议使用有界队列默认拒绝策略要慎重使用注意异常处理的问题如何获取任务执行结果概述 最近在阅读耗子叔的《左耳听风》 , 记一些小笔记 概述 在 Java 中,在 JDK 1.8 里也引入…

深度学习应用技巧总结与pytorch框架下训练过程的记忆技巧

大家好,我是微学AI,今天给大家总结一下深度学习模型训练过程中的一些技巧总结,以及pytorch框架下训练过程的记忆技巧,很有用的干货,理解模型训练过程的步骤,让流程难懂,难记忆的过程变得简单&am…

通讯录-文件操作版

之前我们写过通讯录-动态开辟版,但里面的数据录入后,若退出程序,里面的数据也就跟着一起销毁,无法保存,所以今天我们来写可建议将通讯录信息保存起来的版本,这只要在原来的基础上加以改进就可以了。首先&am…

发光立方体效果 html+css

一.话不多&#xff0c;看效果 css简单创意特效&#xff0c;关注我看更多简单创意特效~ 二.实现&#xff08;附完整代码&#xff09; 定义标签&#xff1a; <div class"container"><div class"q1"></div><div class"h2"&…

Day921.chatGPT

chatGPT Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于chatGPT的内容。 一、什么是chatGPT ChatGPT&#xff08;全名&#xff1a;Chat Generative Pre-trained Transformer&#xff09;&#xff0c;ChatGPT 是一种基于 GPT (Generative Pre-trained Transformer)…

【Linux】进程的基础概念 进程的相关操作 进程的状态

进程一、进程的基本知识1、基本概念2、进程的描述 —— PCB3、task_ struct内容分类二、进程的相关操作1、在Linux下查看进程2、通过系统调用在代码中获取进程标示符3、如何创建子进程4、关于fork()的一些深度理解三、进程的状态Linux中的进程的状态四、僵尸进程与孤儿进程僵尸…

L2-014 列车调度 L1-082 种钻石 L1-083 谁能进图书馆

输入格式&#xff1a; 输入第一行给出一个整数N (2 ≤ N ≤105 )&#xff0c;下一行给出从1到N的整数序号的一个重排列。数字间以空格分隔。 输出格式&#xff1a; 在一行中输出可以将输入的列车按序号递减的顺序调离所需要的最少的铁轨条数。 输入样例&#xff1a; 9 8 4 2 …

STM32开发(九)STM32F103 通信 —— I2C通信编程详解

文章目录一、基础知识点二、开发环境三、STM32CubeMX相关配置四、Vscode代码讲解GPIO模拟I2C代码SHT30相关代码main函数中循环代码五、结果演示方式一、示波器分析I2C数据方式2、通过Modbus将获取到的数据传到PC上一、基础知识点 本实验通过I2C通信获取SHT30温湿度值&#xff…

一文带你看透前端世界里的日期时间,对就是Date

很高兴我们能够通过不同空间&#xff0c;不同时间&#xff0c;通过这篇博客相识&#xff0c;那一定是一种缘分&#xff0c;一种你和狗哥的缘分。今天我希望通过这篇博客对我所熟知的前端世界里的日期时间做一个汇总&#xff0c;不止是代码上的汇总哦&#xff01; 目录 一、时区…

flex布局优化(两端对齐,从左至右)

文章目录前言方式一 nth-child方式二 gap属性方式三 设置margin左右两边为负值总结前言 flex布局是前端常用的布局方式之一&#xff0c;但在使用过程中&#xff0c;我们总是感觉不太方便&#xff0c;因为日常开发中&#xff0c;大多数时候&#xff0c;我们想要的效果是这样的 …

C++数据结构 —— 哈希表、unordered_map/set封装

目录 1.哈希概念 1.1哈希函数 1.2哈希冲突 2.闭散列实现 3.开散列实现 4.容器的封装 4.1unordered_map 4.2unordered_set 4.3封装过程中遇到的问题 1.哈希概念 顺序结构以及平衡二叉搜索树结构中&#xff0c;在查找一个元素时需要经过比较。顺序查找时间复杂度为O(N…

顺序栈的实现

目录 一、数据结构中的栈 二、接口函数 三、栈的初始化 四、入栈 五、判断栈是否为空 六、出栈 七、栈顶元素及元素总数 八、顺序栈的销毁 一、数据结构中的栈 首先&#xff0c;栈&#xff08;Stack&#xff09;这个词在数据结构和操作系统两个学科中都有出现。 操作系…

图像分割系列(一)

图像分割分类 语义分割 把每个像素都打上标签&#xff08;这个像素点是人&#xff0c;树&#xff0c;背景等&#xff09; &#xff08;语义分割只区分类别&#xff0c;不区分类别中具体单位&#xff09; 实例分割 实例分割不光要区别类别&#xff0c;还要区分类别中每一个…

面向切面编程AOP

1.Spring的AOP简介 1.1什么是AOP AOP为Aspect Oriented Programming的缩写&#xff0c;意思是面向切面编程&#xff0c;是通过预编译和运行期动态代理实现程序功能维护的一种技术 AOP是OOP&#xff08;面向对象&#xff09;的延续&#xff0c;利用AOP可以对业务逻辑的各部分…

5个代码技巧,加速你的Python

5个代码技巧&#xff0c;加速你的Python 人生苦短&#xff0c;快学Python&#xff01; Python作为一种功能强大的编程语言&#xff0c;因其简单易学而受到很多初学者的青睐。它的应用领域又非常广泛&#xff1a;科学计算、游戏开发、爬虫、人工智能、自动化办公、Web应用开发…

蓝桥杯C++组怒刷50道真题(填空题)

&#x1f33c;深夜伤感网抑云 - 南辰Music/御小兮 - 单曲 - 网易云音乐 &#x1f33c;多年后再见你 - 乔洋/周林枫 - 单曲 - 网易云音乐 18~22年真题&#xff0c;50题才停更&#xff0c;课业繁忙&#xff0c;有空就更&#xff0c;2023/3/18/23:01写下 目录 &#x1f44a;填…

【C++】智能指针

文章目录&#x1f4d6; 前言1. 智能指针的引入1.1 内存泄露的危害&#xff1a;1.2 异常安全中的内存泄露&#xff1a;1.3 RAII思想&#xff1a;1.3 拦截异常解决不了的内存泄漏&#xff1a;1.4 智能指针解决&#xff1a;2. 智能指针的拷贝2.1 直接拷贝的问题&#xff1a;2.2 au…

STM32实战项目-触摸按键

前言&#xff1a; 通过触摸按键控制LED灯以及继电器&#xff0c;具体实现功能如下&#xff1a; 1、触摸按键1单击与长按&#xff0c;控制LED1&#xff1b; 2、触摸按键2单击与长按&#xff0c;控制LED2; 3、触摸按键3单击与长按&#xff0c;控制LED3; 4、触摸按键4单击与长…

详解Spring、SpringBoot、SpringCloud三者的联系与区别

一、Spring Spring 是一个轻量级的Java 开发框架&#xff0c;主要依存于SSM 框架&#xff0c;即Spring MVC Spring Mybatis&#xff0c;定位很明确&#xff0c;Spring MVC主要负责view 层的显示&#xff0c;Spring 利用IOC 和AOP 来处理业务&#xff0c;Mybatis则是数据的持…
最新文章