貝塞爾曲線原理、推導及Matlab實現

zbyisgudi發表於2024-07-04

貝塞爾曲線原理、推導及Matlab實現

貝塞爾曲線原理、推導及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名。位列廠隊墊底,心疼他們的兩名車手。

跑題了,趕緊迴歸正題。

二、原理

特性

貝塞爾曲線有如下特性:

  • 透過\(n\)個控制點\(P_1, P_2, P_3, ..., P_n\)控制曲線形狀。
  • 曲線只經過起點\(P_1\)和終點\(P_n\).

構建貝塞爾曲線

  1. 一次曲線(線性):
    一次貝塞爾曲線由兩個端點\(P_0\)\(P_1\)組成,曲線由線段直接連線這兩個點,\(B(t)\)描述一條由\(P_0\)\(P_1\)的直線,可以視為一個\(P_0\)\(P_1\)的連續中間點\(Q_0\)


一次貝塞爾曲線演示.gif

線性貝塞爾曲線演示動畫,t在[0,1]區間
  1. 二次曲線
    二次貝塞爾曲線由定點\(P_0, P_1, P_2\)的函式\(B(t)\)描述。為構建貝塞爾曲線,引入中間點\(Q_0, Q_1\)
    • \(P_0, P_1\)之間的連續點\(Q_0\),描述一條線性貝塞爾曲線;
    • \(P_1, P_2\)之間的連續點\(Q_1\),描述一條線性貝塞爾曲線;
    • \(Q_0, Q_1\)之間的連續點\(B(t)\),描述一條二次貝塞爾曲線。


二次貝塞爾曲線的結構.png

二次貝塞爾曲線的結構


image

二次貝塞爾曲線演示動畫,t在[0,1]區間
  1. 三次曲線
    對於三次曲線,由定點\(P_0, P_1, P_2, P_3\)的函式\(B(t)\)描述。可以加入三個可由線性貝塞爾曲線描述的中間點\(Q_0, Q_1, Q_2\),和兩個由二次貝塞爾曲線描述的點\(R_0, R_1\)來描述:
    • \(P_0, P_1\)之間的連續點\(Q_0\),描述一條線性貝塞爾曲線;
    • \(P_1, P_2\)之間的連續點\(Q_1\),描述一條線性貝塞爾曲線;
    • \(P_2, P_3\)之間的連續點\(Q_2\),描述一條線性貝塞爾曲線;
    • \(Q_0, Q_1\)之間的連續點\(R_0\),描述一條二次貝塞爾曲線;
    • \(Q_1, Q_2\)之間的連續點\(R_1\),描述一條二次貝塞爾曲線;
    • \(R_0, R_1\)之間的連續點\(B(t)\),描述一條三次貝塞爾曲線。


三次貝塞爾曲線的結構.png

三次貝塞爾曲線的結構


image

三次貝塞爾曲線演示動畫,t在[0,1]區間
  1. 四次曲線
    對於四次曲線,由定點\(P_0, P_1, P_2, P_3, P_4\)的函式\(B(t)\)描述。可以加入四個可由線性貝塞爾曲線描述的中間點\(Q_0, Q_1, Q_2, Q_3\),三個由二次貝塞爾曲線描述的點\(R_0, R_1, R_2\),和兩個由三次貝塞爾曲線描述的點\(S_0, S_1\)來描述:
    • \(P_0, P_1\)之間的連續點\(Q_0\),描述一條線性貝塞爾曲線;
    • \(P_1, P_2\)之間的連續點\(Q_1\),描述一條線性貝塞爾曲線;
    • \(P_2, P_3\)之間的連續點\(Q_2\),描述一條線性貝塞爾曲線;
    • \(P_3, P_4\)之間的連續點\(Q_3\),描述一條線性貝塞爾曲線;
    • \(Q_0, Q_1\)之間的連續點\(R_0\),描述一條二次貝塞爾曲線;
    • \(Q_1, Q_2\)之間的連續點\(R_1\),描述一條二次貝塞爾曲線;
    • \(Q_2, Q_3\)之間的連續點\(R_2\),描述一條二次貝塞爾曲線;
    • \(R_0, R_1\)之間的連續點\(S_0\),描述一條三次貝塞爾曲線;
    • \(R_1, R_2\)之間的連續點\(S_1\),描述一條三次貝塞爾曲線;
    • \(S_0, S_1\)之間的連續點\(B(t)\),描述一條四次貝塞爾曲線。


四次貝塞爾曲線的結構.png

四次貝塞爾曲線的結構


image

四次貝塞爾曲線演示動畫,t在[0,1]區間
  1. 高階曲線
    由上文可知,為構建更高階的曲線,需要引入更多的中間點。同理可推得五次曲線:


image

五次貝塞爾曲線演示動畫,t在[0,1]區間

構建貝塞爾曲線公式

  1. 一次曲線(線性):
    \(P_0\)的座標為\((\alpha, \beta)\)\(P_1\)的座標為\((\lambda, \mu)\),引入中間點\(Q_0\)的座標為\((x, y)\),則有:

\[\frac{x - \alpha}{\lambda - x} = \frac{t}{1 - t} \]

可推得:

\[x = (1 - t)\alpha + t\lambda \tag1 \]

同理,可得:

\[\frac{y - \beta}{\mu - y} = \frac{t}{1 - t} \]

可推得:

\[y = (1 - t)\beta + t\mu \tag2 \]

整理可得:

\[\left( \begin{matrix} x \\ y \end{matrix} \right) =(1 - t) \left( \begin{matrix} \alpha \\ \beta \end{matrix} \right) + t \left( \begin{matrix} \lambda \\ \mu \end{matrix} \right) \tag3 \]

可將式\((3)\)簡寫為:

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

得到一次貝塞爾曲線公式。
2. 二次曲線
\(P_0, P_1\)上的中間點為\(Q_0\)\(P_1, P_2\)上的中間點為\(Q_1\)\(Q_0, Q_1\)上的中間點為\(R_0\)\(R_0\)即構建曲線的連續點。
帶入式\((4)\)可得:

\[\begin{matrix} Q_0 = (1 - t) P_0 + t P_1 \\ Q_1 = (1 - t) P_1 + t P_2 \\ R_0 = (1 - t) Q_0 + t Q_1 \end{matrix} \tag5 \]

將式\((5)\)中的\(Q_0\)\(Q_1\)代入\(R_0\)中,可得二次貝塞爾曲線公式:

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

  1. 三次曲線
    同理,透過引入中間點\(Q_0, Q_1, Q_2, R_0, R_1, S_0\),代入使用式\((6)\),可得三次貝塞爾曲線公式:

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

  1. 高階曲線
    可以迭代得到四次、五次貝塞爾曲線的公式:

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

\[B(t) = (1 - t) ^ 5 P_0 + 5 t (1 - t) ^ 4 P_1 + 10 t ^ 2 ( 1 - t) ^ 3 P_2 + 10 t ^ 3 (1 - t) ^ 2 P_3 + 5 t ^ 4 (1 - t) P_4 + t ^ 5 P_5, t \in [0, 1] \tag9 \]

三、推導

一般化

觀察上文中\(1\)\(5\)階貝塞爾曲線,發現其各項中的常數係數滿足組合數規律,故對於\(n\)階貝塞爾曲線,給出定點\(P_0, P_1, P_2, ..., P_n\),其貝塞爾曲線可用下式表示:

\[B(t) = \left( \begin{matrix} n \\ 0 \end{matrix} \right) (1 - t) ^ n t ^ 0 P_0 + \left( \begin{matrix} n \\ 1 \end{matrix} \right) (1 - t) ^ {n - 1} t ^ 1 P_1 + \cdots + \left( \begin{matrix} n \\ n - 1 \end{matrix} \right) (1 - t) ^ 1 t ^ {n - 1} P_{n - 1} + \left( \begin{matrix} n \\ n \end{matrix} \right) (1 - t) ^ 0 t ^ n P_n, t \in [0, 1] \tag{10} \]

可化簡為:

\[B(t) = \sum_{i = 0}^\infty \left( \begin{matrix} n \\ i \end{matrix} \right) (1 - t) ^ {n - i} t ^ i P_i, t \in [0, 1] \tag{11} \]

式中組合數:

\[\left( \begin{matrix} n \\ i \end{matrix} \right) = \frac{n !}{i ! \cdot (n - i) !} \]

多項式表達

同時,式\((11)\)也可表示為:

\[B(t) = \sum_{i = 0}^\infty b_{i, n}(t) P_i, t \in [0, 1] \tag{12} \]

其中多項式:

\[b_{i, n}(t) = \left( \begin{matrix} n \\ i \end{matrix} \right) (1 - t) ^ {n - i} t ^ i, i = 0, 1, 2, \cdots, n \tag{13} \]

\((13)\)被稱作\(n\)Bernsteain多項式

Bernsteain多項式
假設開展一個實驗,其成功的機率為\(u\)。若連續進行這個實驗\(n\)次,成功的次數恰好為\(i\)次,那麼其成功機率是多少呢?
能夠確定成功機率為:\(b_{i, n}(t) = \left( \begin{matrix} n \\ i \end{matrix} \right) (1 - t) ^ {n - i} t ^ i, i = 0, 1, 2, \cdots, n\).
這便是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

影像結果

六階貝塞爾曲線

六階貝塞爾曲線.png

十四階貝塞爾曲線

十四階貝塞爾曲線.png

五、參考

  1. 維基百科_貝塞爾曲線

相關文章