用Python動畫來展示二階貝賽爾曲線

2021-02-20 Crossin的編程教室

說起來貝氏曲線,我們可能首先會想到下面這個男人:

圖1. 一位不願透露姓名的英國球員

但實際上我們說的不是這個叫貝克漢姆的英國男人,而是另外一個人,就是下面這個叫「皮埃爾·貝塞爾」(Pierre Bézier)的法國男人:

圖2. 皮埃爾·貝塞爾

貝塞爾論起知名度,也許不如小貝,但說起對人類的貢獻,那可是槓槓的,著名的「貝塞爾曲線」就出自他之手。1962年,貝塞爾發表了貝塞爾曲線的相關理論研究,當時在雷諾公司工作的他,主要運用貝塞爾曲線進行汽車設計。說到這裡可能還是有很多人沒明白貝塞爾曲線到底是什麼,看一下下面這個圖,大家就明白了。

圖3. 設計中用到的貝賽爾曲線

在Photoshop等多種設計軟體中,畫曲線時主要用到的是就是貝賽爾曲線,就是類似於上圖中的這個曲線,設計師們可以通過控制中間的控制點來畫出自己需要的曲線。早先設計師們想要用電腦畫出一條直線灰常簡單,但要畫出一條平滑的曲線卻非常難,而貝塞爾曲線的誕生,讓大家用電腦繪製出一條平滑曲線成為了現實,這也就是貝塞爾曲線的最大用途。

而今天我們就來說一下最簡單的二階貝塞爾曲線的推導,並用matplotlib進行展示。(實際上最簡單的是一階,但因為其只有一條直線,所以沒有什麼實際用途,就忽略了)

我們先來了解一下二階貝賽爾曲線的原理。假如連在一起的兩條線段AB和BC,如下圖:

圖4. 二階貝賽爾曲線原理圖 1

現在AB上取一點D,BC上取一點E,使得AD/AB=BE/BC,如下圖:

圖5. 二階貝賽爾曲線原理圖 2

 

而在線段DE上還要求一點F,使得DF/DE=AD/AB=BE/BC,如下圖:

圖6. 二階貝賽爾曲線原理圖 3

 

而當D在AB上不斷移動,E在BC上不斷移動,形成的F點的軌跡便是一條曲線,這條曲線就是二階貝塞爾曲線。這就是今天我們要推導並演示的曲線。

下面直接用Python代碼來展示一下。首先還是導入各種包:

import numpy as npimport matplotlib.pyplot as pltfrom matplotlib import animation

因為我們用的是matplotlib來做的演示,所以要設置一下matplotlib的後端,也就是顯示方式。這一行代碼最好單獨使用,否則容易失效,所以把它單獨列出來:

這是非常重要的一步,這一步能讓matplotlib在繪圖時彈出一個新窗口,而不是在原窗口直接繪製,因為原窗口無法顯示動畫,這裡用了ipython的magic 命令,也就是在一個命令前面加上「%」。在這裡說明一下,筆者用的是win7系統,開發工具為Anaconda最新版,可以直接去Anaconda官網下載。

因為我們要用到A、B、C三個點,所以要設置一下三個點坐標。A點坐標為x1和y1,B點為x2和y2,C點為x3和y3,再設置一個區間內點的個數dots_num,這個dots_num後面會有解釋。所有這些變量的值都可以隨意設定,但有一些要求,因為筆者把繪圖的坐標系設定在100,也就是x軸和y軸的範圍都是0—100,所以上面三個點的坐標都不要超過這個範圍,而dots_num的數量儘可能大一些,做動畫時更連貫一些,所以上面這些參數的設置如下:

x1=10y1=80x2=50y2=10x3=90y3=80dots_num=100

接下來是獲得貝塞爾曲線的軌跡的函數:

def two_degree_bc(x1=10, y1=80, x2=50, y2=10, x3=90, y3=80, dots_num=100):     global xt, yt, x_dots12, x_dots23, y_dots12, y_dots23    xt = []     yt = []     x_dots12 = np.linspace(x1, x2, dots_num)     y_dots12 = np.linspace(y1, y2, dots_num)     x_dots23 = np.linspace(x2, x3, dots_num)     y_dots23 = np.linspace(y2, y3, dots_num)     for i in range(dots_num):         x = x_dots12[i] + (x_dots23[i]-x_dots12[i])*i / (dots_num-1)        y = y_dots12[i] + (y_dots23[i]-y_dots12[i])*i / (dots_num-1)        xt.append(x)        yt.append(y)

這裡的xt和yt是兩個list,就是用來存放目標點的x坐標和y坐標,而x_dots12和y_dots12分別是線段AB的x和y坐標,x_dots23和y_dots23分別是線段BC的x和y坐標,這四個是numpy的array格式,所有這些數據都設置成全局變量。而從上面的代碼中我們可以看到變量dots_num的作用是在線段AB和BC上取這麼多的點,然後用這些點推導目標點的坐標,點的數量越多,目標點的坐標也就越多,繪製出來的曲線也就更平滑。

接下來是動畫函數,這個函數後面再解釋:

def run(i):    art1.set_data(x_dots12[i], y_dots12[i])    art2.set_data(x_dots23[i], y_dots23[i])    art3.set_data([x_dots12[i], x_dots23[i]], [y_dots12[i], y_dots23[i]])    art4.set_data(xt[i], yt[i])return art1,art2,art3,art4

最後就是繪製動畫了,代碼如下:

two_degree_bc() fig, ax = plt.subplots(figsize=(8,8))ax.set_aspect(1) plt.xlim([0,100]) plt.ylim([0,100])ax.plot([x1, x2], [y1, y2], color='#3e82fc') ax.plot([x2, x3], [y2, y3], color='#3e82fc') ax.plot(xt,yt,color='orange') art1, = ax.plot(x_dots12[0], y_dots12[0], color='green', marker='o') art2, = ax.plot(x_dots23[0], y_dots23[0], color='green', marker='o')art3, = ax.plot([x_dots12[0], x_dots23[0]], [y_dots12[0], y_dots23[0]], color = 'purple') art4, = ax.plot(xt[0], yt[0], color='red', marker='o') ani = animation.FuncAnimation(    fig, run, frames=range(100), interval=2, save_count=50)plt.show()

這裡首先運行two_degree_bc()函數得到目標點的軌跡,然後繪製AB、BC線段以及目標曲線,這些都是靜態圖。接著從變量art1開始就是繪製動畫的部分了。這部分比較複雜,一共有art1、art2、art3和art4這四個變量,其分別對應線段AB、BC、DE和目標曲線的移動軌跡,點在這四個軌跡上移動,才能形成動畫。而要生成動畫,就要用到animation的方法FuncAnimation,其含有多個參數,fig就是我們繪圖的那個畫布,run就是我們生成動畫時運行的函數,frames是幀畫面,其每一幀畫面包含了這些移動軌跡中的一個點所對應的靜態圖,把這些點的軌跡也就是每一幀連起來就是動畫軌跡,frames一般是一個sequence,也就是包含多個變量,每個變量都賦值給run函數,run函數利用這個參數生成一個靜態圖,這麼多靜態圖連起來就是動畫,這和我們在電影或電視中看到的動畫片是一樣道理。interval是幀之間的時間間隔,200代表0.2秒,這個可以隨意設定。save_count=50是把幀緩存起來用於回放,緩存幀的數量越多,回放越流暢,這個影響不大,隨意設定。

下面再說一下運行動畫的函數run的作用,可以看到run一共有5行代碼,前4行代碼是繪圖代碼,最後一個是返回參數的代碼,前4行中每一行都代表了前面我們說過的點的軌跡, art1是線段AB上的點,用set_data(x_dots12[i], y_dots12[i])方法就生成了一個對應的幀,變量i就是前面講的frames裡的一個參數,生成的這個幀返回給FuncAnimation,讓其用於連續播放,這就形成了動畫。後面art2、art3和art4的道理是一樣的。生成的動畫效果的靜態截圖如下:

圖7. 二階貝賽爾曲線靜態成圖

 

最後再放上一個動圖,讓我們在一個深V的運動中結束本次話題:

圖8. 二階貝賽爾曲線動態示意圖

 

二階貝塞爾曲線的推導相對還容易一些,而三階甚至更高階的推導就複雜一點,筆者目前正在研究三階貝賽爾曲線,以後會給大家分享一下。

完整代碼已經上傳:

https://gitee.com/leonmovie/two_degree_bc

有需要的可以去自行下載。

作者簡介:小李子,數據分析愛好者,擅長數據可視化,比較關注機器學習領域,希望能和業內朋友多學習交流,個人微信 tyrant100

相關焦點

  • 「科普掃盲」貝塞爾曲線
    貝賽爾曲線的前世今生貝塞爾曲線,這個命名規則一眼看上去大概是一個叫貝塞爾的數學家發明的。但,貝塞爾曲線依據的最原始的數學公式,是在1912年在數學界廣為人知的伯恩斯坦多項式。簡單理解,伯恩斯坦多項式可以用來證明,在[ a, b ] 區間上所有的連續函數都可以用多項式來逼近,並且收斂性很強,也就是一致收斂。
  • Bézier curve | 貝茲曲線 |貝塞爾曲線知多少
    貝塞爾曲線的繪製NO.01 | 二階曲線在平面內選3個不同線的點並且依次用線段連接,在AB和BC線段上找出點D和點E,使得 AD/AB = BE/BC,連接DE,在DE上尋找點F,F點需要滿足:DF/DE = AD/AB = BE/BC,根據DE線段和計算公式找出所有的F點並將其連接起來。
  • 用Python畫朵玫瑰,只要五分鐘
    最近一個項目在用python,想著這次不用java了,用python給媽媽個禮物吧。Turtle庫是Python語言中一個非常強大的繪製圖像的函數庫,她提供了很多強大的方法,可以方便快速的繪圖,今天我們就來試一下,畫朵玫瑰送給媽媽。
  • 典型習題:(120218)對坐標的曲線積分與二階微分方程綜合題求解
    「對坐標的曲線積分與二階微分方程求解」題型的求解思路以及相關的知識點:一、一階線性微分方程的求解方法(1) 當Q(x)恆等於0時,為齊次線性方程,使用可分離變量法求解;(2) 當Q二、可降解的微分方程類型及典型問題求解可將階的微分方程歸根結底可以歸結為一階微分方程問題,針對於一般教材中只討論了二階的類型,可以擴展為如下三種類型:(1) y(n)=f(x)對於這樣的n階微分方程可以採取對右端逐步積分的方法,通過n次不定積分即得到包含有n個相互獨立的任意常數的通解
  • 一日一技:用Python程序求解二次方程式
    用Python程序求解二次方程式 當我們已給出係數a,b和c時,用python程序計算二次方程的根值。 另外,說明一下,下面的示例,需要你有一定的python基礎,不然對於新手來說,會難以理解。 因此,這篇文章,適合於有一定python學習基礎的小夥伴。
  • 二階導數真實的幾何意義是什麼,它比一階導數小嗎?
    我們都知道,函數f(x)的導數就可以解釋為某個X值所對應的圖形的斜率,圖像越陡說明導數值很大,向下傾斜說明導數為負,那麼導數的導數就是二階導數,它表示了斜率的變化,那二階導數的幾何意義在圖形上如何體現呢?
  • 二階高通濾波器的阻抗特性及濾波效果分析
    本期筆者將重點分析二階高通濾波器的阻抗特性及濾波效果,僅供參考。1 二階高通濾波器的結構及原理二階高通濾波器結構如圖1所示。 二階高通濾波器由電抗器L、電容器C和電阻器R組成,利用電抗器L和電容器C的諧振原理,使濾波支路對大於調諧頻率的諧波電流呈低阻特性,從而達到濾除諧波的目的。2 二階高通濾波器的阻抗特性
  • 用Python建模來深度了解
    現在得到一個二階微分方程,它描繪了兩個物體間因重力而存在的相互作用。為簡化解法,可以將其分解成兩個一階微分方程。物體的加速度是物體速率隨時間的變化,因此速率的一階微分可以替代位置的二階微分。類似地,速率可表示為位置的一階微分。
  • Python帶你找回童年的萬花尺
    $ python spiro.py --sparams 300 100 0.9圖2-6展示了輸出結果。如你所見,這段代碼根據用戶指定的參數繪製了一條螺線,圖2-5和它不同,展示了幾個隨機螺線的動畫。還將學習以下幾點:用turtle模塊創建圖形;使用參數方程;利用數學方程來生成曲線;用線段來畫曲線;用定時器來生成圖形動畫;將圖形保存為圖像文件。 參數方程在本節中,你將看到用參數方程來畫圓的簡單例子。參數方程將曲線上點的坐標表示為一個變量的函數,該變量稱為參數。
  • 【圓錐曲線】二次曲線方程與形狀的關係
    我們默認讀者已經知道:1.二階、三階行列式及其計算方法2.矩陣乘法的計算方法3.矩陣乘法的性質:  ,即 對於基礎較為薄弱的普通初高中生,建議只閱讀「二次曲線方程的化簡」、「二次曲線形狀的判定」和文末「二次型的線性規劃」部分。
  • python學習筆記:兩個變量之間的互相關圖形和簡單動畫曲線
    1.簡單動畫曲線(下圖實際上應該是動態圖)import numpy as npfrom matplotlib import pyplot as plt#導入animation創建動畫from matplotlib import animation
  • 一文看懂二階lc低通濾波器的設計及原理
    另外,線路板還大量採用「蛇行線+貼片鉭電容」來組成LC電路,因為蛇行線在電路板上來回折行,也可以看作一個小電感。   濾波電路的原理實際是L、c元件基本特性的組合利用。該電路的這種特點可用圖中的幅一頻(U-F特性曲線概括。對於圖9—3(d)所示的濾波電路,它利用Cl和Ll並聯對諧振信號阻抗大、C,和L,,串聯對諧振信號阻抗小的特點,容易讓諧振頻率以外的信號通過,而抑制諧振信號廠F通過,所以稱為帶阻濾波電路。該電路的特點可用圖中的幅一頻(U-F性曲線來概括。
  • 磁性二階拓撲絕緣體
    近幾年關於二階拓撲絕緣體的理論研究很多,但是其實現材料卻非常稀少,尤其是二維的二階拓撲絕緣體。因此,尋找二階拓撲絕緣體材料是一個重要的科學問題。在此基礎上,他們進一步提出了二階拓撲絕緣體材料的搜尋方案,並以Bi/EuO材料為例做了系統的理論計算研究。以下著重討論二維體系。對於二維時間反演不變的一階拓撲絕緣體,其一維的邊緣上會出現無能隙的拓撲邊緣態,通常表現為兩條能帶的線性交叉,其交點位於邊界布裡淵區的時間反演不動點處。這樣線性交叉的邊緣態可以用一維狄拉克方程來描述。這時,可引入磁場,破壞時間反演對稱性。
  • Python用wordcloud展示,有你名字嗎?
    >可以開始了馬上開始精彩內容……01數據準備今天,我們來詳細了解下如何利用這些提取的文本內容,進行數據展示,我們使用wordcloud詞雲圖展示Excel中的內容。用Python將電子表格Excel展示在界面中,PyQt5之QTableWidget應用
  • 改裝車,刷一階,二階是什麼意思呢?
    刷階呢也就是刷ECU,一階呢就是在原廠原車沒有改動的情況下對ECU進行升級,二階呢就需要對發動機、進氣、排氣進行改動後進行升級。刷ECU就是重新對汽車ECU進行數據讀寫的意思。另外原裝帶渦輪車型一般設定發動機轉速在1800左右渦輪才起作用,而改裝ECU後,渦輪會更早地介入,約1500轉左右渦輪就介入,從而使扭矩更早地發揮,最大扭矩輸出曲線變得更寬,因此也會使汽車相對原車更加省油。3、改裝後自動波車型換檔會變得更平順,動力銜接更順暢。