贝塞尔曲线原理、推导及Matlab实现

一、简介

贝塞尔曲线提出

在数学的数值分析领域中,贝塞尔曲线(English:Bézier curve)是计算机图形学中相当重要的参数曲线。更高维度的广泛化贝塞尔曲线就称作贝兹曲面,其中贝兹三角是一种特殊的实例。

贝塞尔曲线于1962年,由法国工程师皮埃尔·贝兹Pierre Bézier)所广泛发表,他运用贝塞尔曲线来为汽车的主体进行设计。贝塞尔曲线最初由保尔·德·卡斯特里奥于1959年运用德卡斯特里奥算法开发,以稳定数值的方法求出贝塞尔曲线。

贝塞尔曲线与F1的渊源

说到皮埃尔·贝兹,就不得不提他作为雷诺公司的一名工程师,曾引领了设计和制造业的转型,将它们从单纯使用数学和计算工具带向了计算机辅助设计和三维模型,同时是实体造型、几何模型和物理模型领域的奠定者之一。

而雷诺公司早期于1977年开始,作为车队和发动机供应商在不同时期里参加了F1(一级方程式赛事)。在1977年的最后五站比赛中,雷诺以厂队的身份踏进了F1比赛,并且将涡轮增压器引入其第一款赛车雷诺 RS01中却遭众人嘲笑,然而在法国的分站赢得胜利之后,不到两年时间,所有一流车队都改用涡轮发动机。在1992年雷诺凭英国车手文素和威廉士车队拿下史上第一个年度车队冠军,而接下来五年的年度车队冠军也都是使用雷诺发动机(除1995年是班尼顿,其余皆为威廉士),不过随着其在98年退出F1,雷诺在F1的霸业也宣告结束。雷诺在2000年接手贝纳通车队重返一级方程式赛车。在2002年,车队改名为雷诺一级方程式车队,更在2005年和2006年赛季中同时夺得车队和车手世界冠军。

现今雷诺公司旗下的F1车队为AlpineF1车队(法语:Alpine F1 Team),全名倍世AlpineF1车队(法语:BWT Alpine F1 Team)。本赛季Alpine车队的新赛车A524在赛季伊始便严重缺乏竞争力;赛季揭幕战巴林大奖赛上,排位赛中双车排名垫底在第一节即被淘汰,正赛17、18名带回。在沙特大奖赛,双车17、18位发车,正赛加斯利因变速箱问题退赛,奥康带回13名。位列厂队垫底,心疼他们的两名车手。

跑题了,赶紧回归正题。

二、原理

特性

贝塞尔曲线有如下特性:

  • 通过python 贝塞尔曲线生成轨迹_matlab个控制点python 贝塞尔曲线生成轨迹_matlab_02控制曲线形状。
  • 曲线只经过起点python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_03和终点python 贝塞尔曲线生成轨迹_算法_04.

构建贝塞尔曲线

  1. 一次曲线(线性):
    一次贝塞尔曲线由两个端点python 贝塞尔曲线生成轨迹_算法_05python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_03组成,曲线由线段直接连接这两个点,python 贝塞尔曲线生成轨迹_贝塞尔曲线_07描述一条由python 贝塞尔曲线生成轨迹_算法_05python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_03的直线,可以视为一个python 贝塞尔曲线生成轨迹_算法_05python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_03的连续中间点python 贝塞尔曲线生成轨迹_算法_12




python 贝塞尔曲线生成轨迹_贝塞尔曲线_13


线性贝塞尔曲线演示动画,t在[0,1]区间


  1. 二次曲线
    二次贝塞尔曲线由定点python 贝塞尔曲线生成轨迹_贝塞尔曲线_14的函数python 贝塞尔曲线生成轨迹_贝塞尔曲线_07描述。为构建贝塞尔曲线,引入中间点python 贝塞尔曲线生成轨迹_matlab_16
  • python 贝塞尔曲线生成轨迹_数学建模_17之间的连续点python 贝塞尔曲线生成轨迹_贝塞尔曲线_18,描述一条线性贝塞尔曲线;
  • python 贝塞尔曲线生成轨迹_算法_19之间的连续点python 贝塞尔曲线生成轨迹_贝塞尔曲线_20,描述一条线性贝塞尔曲线;
  • python 贝塞尔曲线生成轨迹_matlab_21之间的连续点python 贝塞尔曲线生成轨迹_算法_22,描述一条二次贝塞尔曲线。



python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_23


二次贝塞尔曲线的结构



python 贝塞尔曲线生成轨迹_算法_24


二次贝塞尔曲线演示动画,t在[0,1]区间

  1. 三次曲线
    对于三次曲线,由定点python 贝塞尔曲线生成轨迹_算法_25的函数python 贝塞尔曲线生成轨迹_贝塞尔曲线_07描述。可以加入三个可由线性贝塞尔曲线描述的中间点python 贝塞尔曲线生成轨迹_matlab_27,和两个由二次贝塞尔曲线描述的点python 贝塞尔曲线生成轨迹_matlab_28来描述:
  • python 贝塞尔曲线生成轨迹_数学建模_17之间的连续点python 贝塞尔曲线生成轨迹_贝塞尔曲线_18,描述一条线性贝塞尔曲线;
  • python 贝塞尔曲线生成轨迹_算法_19之间的连续点python 贝塞尔曲线生成轨迹_贝塞尔曲线_20,描述一条线性贝塞尔曲线;
  • python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_33之间的连续点python 贝塞尔曲线生成轨迹_算法_34,描述一条线性贝塞尔曲线;
  • python 贝塞尔曲线生成轨迹_matlab_21之间的连续点python 贝塞尔曲线生成轨迹_数学建模_36,描述一条二次贝塞尔曲线;
  • python 贝塞尔曲线生成轨迹_matlab_37之间的连续点python 贝塞尔曲线生成轨迹_数学建模_38,描述一条二次贝塞尔曲线;
  • python 贝塞尔曲线生成轨迹_matlab_39之间的连续点python 贝塞尔曲线生成轨迹_算法_22,描述一条三次贝塞尔曲线。



python 贝塞尔曲线生成轨迹_贝塞尔曲线_41


三次贝塞尔曲线的结构



python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_42


三次贝塞尔曲线演示动画,t在[0,1]区间

  1. 四次曲线
    对于四次曲线,由定点python 贝塞尔曲线生成轨迹_算法_43的函数python 贝塞尔曲线生成轨迹_贝塞尔曲线_07描述。可以加入四个可由线性贝塞尔曲线描述的中间点python 贝塞尔曲线生成轨迹_贝塞尔曲线_45,三个由二次贝塞尔曲线描述的点python 贝塞尔曲线生成轨迹_算法_46,和两个由三次贝塞尔曲线描述的点python 贝塞尔曲线生成轨迹_matlab_47来描述:
  • python 贝塞尔曲线生成轨迹_数学建模_17之间的连续点python 贝塞尔曲线生成轨迹_贝塞尔曲线_18,描述一条线性贝塞尔曲线;
  • python 贝塞尔曲线生成轨迹_算法_19之间的连续点python 贝塞尔曲线生成轨迹_贝塞尔曲线_20,描述一条线性贝塞尔曲线;
  • python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_33之间的连续点python 贝塞尔曲线生成轨迹_算法_34,描述一条线性贝塞尔曲线;
  • python 贝塞尔曲线生成轨迹_算法_54之间的连续点python 贝塞尔曲线生成轨迹_贝塞尔曲线_55,描述一条线性贝塞尔曲线;
  • python 贝塞尔曲线生成轨迹_matlab_21之间的连续点python 贝塞尔曲线生成轨迹_数学建模_36,描述一条二次贝塞尔曲线;
  • python 贝塞尔曲线生成轨迹_matlab_37之间的连续点python 贝塞尔曲线生成轨迹_数学建模_38,描述一条二次贝塞尔曲线;
  • python 贝塞尔曲线生成轨迹_算法_60之间的连续点python 贝塞尔曲线生成轨迹_数学建模_61,描述一条二次贝塞尔曲线;
  • python 贝塞尔曲线生成轨迹_matlab_39之间的连续点python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_63,描述一条三次贝塞尔曲线;
  • python 贝塞尔曲线生成轨迹_数学建模_64之间的连续点python 贝塞尔曲线生成轨迹_贝塞尔曲线_65,描述一条三次贝塞尔曲线;
  • python 贝塞尔曲线生成轨迹_算法_66之间的连续点python 贝塞尔曲线生成轨迹_算法_22,描述一条四次贝塞尔曲线。



python 贝塞尔曲线生成轨迹_matlab_68


四次贝塞尔曲线的结构



python 贝塞尔曲线生成轨迹_算法_69


四次贝塞尔曲线演示动画,t在[0,1]区间

  1. 高阶曲线
    由上文可知,为构建更高阶的曲线,需要引入更多的中间点。同理可推得五次曲线:



python 贝塞尔曲线生成轨迹_数学建模_70


五次贝塞尔曲线演示动画,t在[0,1]区间

构建贝塞尔曲线公式

  1. 一次曲线(线性):
    python 贝塞尔曲线生成轨迹_算法_05的坐标为python 贝塞尔曲线生成轨迹_贝塞尔曲线_72python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_03的坐标为python 贝塞尔曲线生成轨迹_数学建模_74,引入中间点python 贝塞尔曲线生成轨迹_算法_12的坐标为python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_76,则有:
    python 贝塞尔曲线生成轨迹_matlab_77
    可推得:
    python 贝塞尔曲线生成轨迹_matlab_78
    同理,可得:
    python 贝塞尔曲线生成轨迹_matlab_79
    可推得:
    python 贝塞尔曲线生成轨迹_数学建模_80
    整理可得:
    python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_81
    可将式python 贝塞尔曲线生成轨迹_贝塞尔曲线_82简写为:
    python 贝塞尔曲线生成轨迹_数学建模_83
    得到一次贝塞尔曲线公式。
  2. 二次曲线
    python 贝塞尔曲线生成轨迹_matlab_84上的中间点为python 贝塞尔曲线生成轨迹_算法_12python 贝塞尔曲线生成轨迹_matlab_86上的中间点为python 贝塞尔曲线生成轨迹_数学建模_87python 贝塞尔曲线生成轨迹_matlab_16上的中间点为python 贝塞尔曲线生成轨迹_matlab_89python 贝塞尔曲线生成轨迹_matlab_89即构建曲线的连续点。
    带入式python 贝塞尔曲线生成轨迹_算法_91可得:
    python 贝塞尔曲线生成轨迹_算法_92
    将式python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_93中的python 贝塞尔曲线生成轨迹_算法_12python 贝塞尔曲线生成轨迹_数学建模_87代入python 贝塞尔曲线生成轨迹_matlab_89中,可得二次贝塞尔曲线公式:
    python 贝塞尔曲线生成轨迹_数学建模_97
  3. 三次曲线
    同理,通过引入中间点python 贝塞尔曲线生成轨迹_算法_98,代入使用式python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_99,可得三次贝塞尔曲线公式:
    python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_100
  4. 高阶曲线
    可以迭代得到四次、五次贝塞尔曲线的公式:
    python 贝塞尔曲线生成轨迹_matlab_101

python 贝塞尔曲线生成轨迹_算法_102

三、推导

一般化

观察上文中python 贝塞尔曲线生成轨迹_数学建模_103python 贝塞尔曲线生成轨迹_matlab_104阶贝塞尔曲线,发现其各项中的常数系数满足组合数规律,故对于python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_105阶贝塞尔曲线,给出定点python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_106,其贝塞尔曲线可用下式表示:
python 贝塞尔曲线生成轨迹_贝塞尔曲线_107
可化简为:
python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_108
式中组合数:
python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_109

多项式表达

同时,式python 贝塞尔曲线生成轨迹_matlab_110也可表示为:
python 贝塞尔曲线生成轨迹_算法_111
其中多项式:
python 贝塞尔曲线生成轨迹_数学建模_112
python 贝塞尔曲线生成轨迹_matlab_113被称作python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_105Bernsteain多项式

Bernsteain多项式
假设开展一个实验,其成功的概率为python 贝塞尔曲线生成轨迹_数学建模_115。若连续进行这个实验python 贝塞尔曲线生成轨迹_matlab次,成功的次数恰好为python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_117次,那么其成功概率是多少呢?
能够确定成功概率为:python 贝塞尔曲线生成轨迹_算法_118.
这便是Bernsteain多项式。

四、应用(Matlab实现)

实现目标

  1. 能够进行控制点坐标的输入。
  2. 计算贝塞尔曲线。
  3. 绘制贝塞尔曲线及其控制点。

脚本编写

main.m(主函数,调用输入函数、贝塞尔曲线计算函数及绘制贝塞尔曲线)

%% 初始化
clc
clear

%% 输入
n = input("请输入控制点个数:\n");
P = pos_input(n);

%% 调用贝塞尔曲线计算函数
P = P';  % 坐标矩阵转置,便于曲线运算及绘图
[t, p] = bezier_curve(P, n - 1);  % 阶数为控制点个数 - 1

%% 绘制贝塞尔曲线
plot(t, p, '-b');  % 绘制贝塞尔曲线
hold on;
plot(P(1,:), P(2,:), '-ro');  % 绘制控制点
title(sprintf('贝塞尔曲线 (阶数: %d)', n - 1));
xlabel('X');
ylabel('Y');
grid on;
legend('贝塞尔曲线', '控制点');
hold off;

bezier_curve.m(贝塞尔曲线函数,计算n阶贝塞尔曲线)

function [Px, Py] = bezier_curve(control_points, order)
    % 计算贝塞尔曲线上的点
    t = linspace(0, 1, 1000);  % 在[0, 1]范围内生成点
    curve = zeros(2, numel(t));  % 初始化曲线矩阵,numel函数用于获取数组元素的数目
    for i = 0 : order
        curve = curve + nchoosek(order, i) * ((1 - t) .^ (order - i)) .* ...
        (t .^ i) .* control_points(:, i + 1);  % 该计算公式即上文中式(11),nchoosek函数用于计算组合数
    end
    Px = curve(1, :);
    Py = curve(2, :);
end

pos_input.m(输入函数,输入控制点坐标)

function P = pos_input(I)
   % 输入贝塞尔曲线控制点 
    P = ones(I, 2);  % 初始化坐标矩阵 
        for i = 1 : I
            P(i, :) = input("请输入输入坐标点P" + num2str(i - 1) + "(以一维矩阵形式输入): \n");
        end
end

图像结果

六阶贝塞尔曲线

python 贝塞尔曲线生成轨迹_贝塞尔曲线_119

十四阶贝塞尔曲线

python 贝塞尔曲线生成轨迹_python 贝塞尔曲线生成轨迹_120

五、参考

  1. 维基百科_贝塞尔曲线