关于python:用Python动画来展示二阶贝赛尔曲线

2次阅读

共计 4000 个字符,预计需要花费 10 分钟才能阅读完成。

说起来贝氏曲线,咱们可能首先会想到上面这个男人:

图 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 np
import matplotlib.pyplot as plt
from matplotlib import animation

因为咱们用的是 matplotlib 来做的演示,所以要设置一下 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=10
y1=80
x2=50
y2=10
x3=90
y3=80
dots_num=100

接下来是取得贝塞尔曲线的轨迹的函数:



def two_degree_bc(x1=10, y1=80, x2=50, y2=10, x3=90, y3=80, dots_num=100): #bezier curve
    global xt, yt, x_dots12, x_dots23, y_dots12, y_dots23
    xt = [] #指标点的 x 坐标
    yt = [] #指标点的 y 坐标
    x_dots12 = np.linspace(x1, x2, dots_num) #线段 AB 的 x 坐标
    y_dots12 = np.linspace(y1, y2, dots_num) #线段 AB 的 y 坐标
    x_dots23 = np.linspace(x2, x3, dots_num) #线段 BC 的 x 坐标
    y_dots23 = np.linspace(y2, y3, dots_num) #线段 BC 的 y 坐标
    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') #绘制 AB 线段
ax.plot([x2, x3], [y2, y3], color='#3e82fc') #绘制 BC 线段
ax.plot(xt,yt,color='orange') #绘制指标曲线
art1, = ax.plot(x_dots12[0], y_dots12[0], color='green', marker='o') #不能用 scatter,因为失去的对象不是一个 list,是一个 object
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') #plot 失去的后果是一个 list,只蕴含一个元素,即一个形态 object
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

有须要的能够去自行下载。

作者简介:小李子,数据分析爱好者,善于数据可视化,比拟关注机器学习畛域,心愿能和业内敌人多学习交换

——

欢送搜寻及关注:Crossin 的编程教室

这里还有更多精彩。一起学,走得远

正文完
 0