实际上,您可以使用
scipy.interpolate.inter1d
来实现此目的。您需要将多边形的x和y组件分别视为不同的系列。
以下是一个快速示例,使用正方形:
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
x = [0, 1, 1, 0, 0]
y = [0, 0, 1, 1, 0]
t = np.arange(len(x))
ti = np.linspace(0, t.max(), 10 * t.size)
xi = interp1d(t, x, kind='cubic')(ti)
yi = interp1d(t, y, kind='cubic')(ti)
fig, ax = plt.subplots()
ax.plot(xi, yi)
ax.plot(x, y)
ax.margins(0.05)
plt.show()
![输入图像说明](https://istack.dev59.com/aQK7c.webp)
然而,如您所见,这在0,0处会出现一些问题。
这是由于样条段不仅依赖于两个点。我们所插值的第一个和最后一个点并没有以我们期望的方式“连接”。我们可以通过在x和y序列中添加倒数第二个和第二个点来解决这个问题,并为样条线端点提供“包裹式”边界条件。
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
x = [0, 1, 1, 0, 0]
y = [0, 0, 1, 1, 0]
orig_len = len(x)
x = x[-3:-1] + x + x[1:3]
y = y[-3:-1] + y + y[1:3]
t = np.arange(len(x))
ti = np.linspace(2, orig_len + 1, 10 * orig_len)
xi = interp1d(t, x, kind='cubic')(ti)
yi = interp1d(t, y, kind='cubic')(ti)
fig, ax = plt.subplots()
ax.plot(xi, yi)
ax.plot(x, y)
ax.margins(0.05)
plt.show()
![输入图像描述](https://istack.dev59.com/FRWvE.webp)
只是为了展示使用您的数据时的样子:
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
x = [-0.25, -0.625, -0.125, -1.25, -1.125, -1.25,
0.875, 1.0, 1.0, 0.5, 1.0, 0.625, -0.25]
y = [1.25, 1.375, 1.5, 1.625, 1.75, 1.875, 1.875,
1.75, 1.625, 1.5, 1.375, 1.25, 1.25]
orig_len = len(x)
x = x[-3:-1] + x + x[1:3]
y = y[-3:-1] + y + y[1:3]
t = np.arange(len(x))
ti = np.linspace(2, orig_len + 1, 10 * orig_len)
xi = interp1d(t, x, kind='cubic')(ti)
yi = interp1d(t, y, kind='cubic')(ti)
fig, ax = plt.subplots()
ax.plot(xi, yi)
ax.plot(x, y)
ax.margins(0.05)
plt.show()
![输入图像描述在此](https://istack.dev59.com/KvXxa.webp)
请注意,这种方法会导致相当多的“超调”。这是由于三次样条插值造成的。@pythonstarter的建议也是处理它的另一种好方法,但贝塞尔曲线将遇到相同的问题(它们在数学上基本上是等价的,只是控制点的定义方式不同)。还有许多其他处理平滑的方法,包括专门用于平滑多边形的方法(例如指数核多项式逼近(PAEK))。我从未尝试过实现PAEK,所以我不确定它的复杂程度。如果您需要更强大的平滑功能,可以尝试查找PAEK或其他类似的方法。