scipy 中的等间隔样条评估
Equally spaced spline evaluation in scipy
我正在使用 scipy 构建曲线的双变量样条(类似于椭圆),其中 splprep
和 splev
。目的是为了平滑点。
问题是我试图平滑的点并没有沿着路径均匀分布,当我尝试评估样条曲线时我会得到不均匀分布,但我想要均匀分布的点样条.
这是一个示例,展示了我的数据的样子和类似的结果(实际上,在我的例子中,这种效果更为明显):
t = np.r_[0:2*np.pi:100.j, 0.142:np.pi+0.1:100j, 0.07+np.pi/2:0.23+np.pi:200j]
t = np.random.normal(t, 0.01)
t = np.unique(t)
# plt.plot(t)
r = np.asarray([1.0, 1.01] * (len(t) // 2)) # np.random.normal() # 1, 0.005, size=len(t))
xy = np.asarray([np.cos(t) * r, np.sin(t) * r]).T
# plt.plot(*xy.T, '.')
# plt.axis('equal')
tck, _ = splprep(xy.T, s=0, per=True)
xi, yi = splev(np.linspace(0, 1, 200), tck)
plt.subplots(figsize=(10, 10))
plt.plot(xi, yi, '.')
plt.axis('equal')
正如您从下图中看到的,有一个区域的点更密集:我想避免这种效果,并让点均匀分布(如果它们相对于质心,例如每 0.5 度 1 个点)。
我认为这是因为点会在密集区域形成 "jagged" 模式:例如,请参见此图,显示圆顶部的点频率如何变化。
我认为这与 u
在 splprep
中的计算方式有关(see doc) 我认为我可以通过调整 u
参数来解决这个问题,但是不知道怎么算:现在的计算方式显然没问题,我想不出更好的策略:
v = [0]
for i in range(1, len(xy)):
vi = v[i - 1] + sum((xy[i] - xy[i - 1]) ** 2) ** 0.5
v.append(vi)
u = [v[i] / v[-1] for i in range(1, len(xy))]
考虑到使用样条 是 我试图用来从数据集中删除额外点的方法 (xy
),我唯一的想法是以某种方式重新计算 u
以获得所需的效果,但我不知道如何。
如何平滑我的数据以确保样条曲线上的评估点彼此之间的距离大致相同?
编辑
我意识到我基本上必须将 u
设置为每个点的角度(除以 2pi,以在 0 和 1 内归一化)。我试过点看起来均匀分布,但出于某种原因我得到了一些异常值
uu = t / (2 * np.pi) # u1# 2
tck, _ = splprep(xy.T, u=uu, s=0, per=True)
xi, yi = splev(np.linspace(0, 1, 200), tck)
plt.subplots(figsize=(10, 10))
plt.plot(xi, yi)#, '.')
plt.axis('equal')
问题是,我不明白这些是从哪里来的。我怀疑这取决于样条曲线的计算方式,但无法弄清楚如何解决这个问题。我现在唯一可以使用的解决方案是使用平滑,但这是一种非常反复试验的方法,我宁愿不采用。
强制 u=t
使插值器的生活变得太艰难,因为一些 t
值彼此非常接近,而相应的点由于变化 [=13] 而不是那么接近=].这会导致插值曲线与数据的偏差很大,即第二个图上的异常值。
相反,使用默认值 u
计算样条,然后重新参数化与极角成比例。为此,我首先评估参数域中等间距值的样条(如您的第一次尝试),用 unwrap(arctan2)
找到每个结果点的极角,然后找到 u-> 的倒数具有线性插值的角度函数。插入样条中的这个反函数根据极角生成均匀间隔的点。
xx, yy = splev(np.linspace(0, 1, 200), tck)
s = np.unwrap(np.arctan2(yy, xx))
s_inv = np.interp(np.linspace(s[0], s[-1], len(s)), s, np.linspace(0, 1, len(s)))
xi, yi = splev(s_inv, tck)
我正在使用 scipy 构建曲线的双变量样条(类似于椭圆),其中 splprep
和 splev
。目的是为了平滑点。
问题是我试图平滑的点并没有沿着路径均匀分布,当我尝试评估样条曲线时我会得到不均匀分布,但我想要均匀分布的点样条.
这是一个示例,展示了我的数据的样子和类似的结果(实际上,在我的例子中,这种效果更为明显):
t = np.r_[0:2*np.pi:100.j, 0.142:np.pi+0.1:100j, 0.07+np.pi/2:0.23+np.pi:200j]
t = np.random.normal(t, 0.01)
t = np.unique(t)
# plt.plot(t)
r = np.asarray([1.0, 1.01] * (len(t) // 2)) # np.random.normal() # 1, 0.005, size=len(t))
xy = np.asarray([np.cos(t) * r, np.sin(t) * r]).T
# plt.plot(*xy.T, '.')
# plt.axis('equal')
tck, _ = splprep(xy.T, s=0, per=True)
xi, yi = splev(np.linspace(0, 1, 200), tck)
plt.subplots(figsize=(10, 10))
plt.plot(xi, yi, '.')
plt.axis('equal')
正如您从下图中看到的,有一个区域的点更密集:我想避免这种效果,并让点均匀分布(如果它们相对于质心,例如每 0.5 度 1 个点)。
我认为这是因为点会在密集区域形成 "jagged" 模式:例如,请参见此图,显示圆顶部的点频率如何变化。
我认为这与 u
在 splprep
中的计算方式有关(see doc) 我认为我可以通过调整 u
参数来解决这个问题,但是不知道怎么算:现在的计算方式显然没问题,我想不出更好的策略:
v = [0]
for i in range(1, len(xy)):
vi = v[i - 1] + sum((xy[i] - xy[i - 1]) ** 2) ** 0.5
v.append(vi)
u = [v[i] / v[-1] for i in range(1, len(xy))]
考虑到使用样条 是 我试图用来从数据集中删除额外点的方法 (xy
),我唯一的想法是以某种方式重新计算 u
以获得所需的效果,但我不知道如何。
如何平滑我的数据以确保样条曲线上的评估点彼此之间的距离大致相同?
编辑
我意识到我基本上必须将 u
设置为每个点的角度(除以 2pi,以在 0 和 1 内归一化)。我试过点看起来均匀分布,但出于某种原因我得到了一些异常值
uu = t / (2 * np.pi) # u1# 2
tck, _ = splprep(xy.T, u=uu, s=0, per=True)
xi, yi = splev(np.linspace(0, 1, 200), tck)
plt.subplots(figsize=(10, 10))
plt.plot(xi, yi)#, '.')
plt.axis('equal')
问题是,我不明白这些是从哪里来的。我怀疑这取决于样条曲线的计算方式,但无法弄清楚如何解决这个问题。我现在唯一可以使用的解决方案是使用平滑,但这是一种非常反复试验的方法,我宁愿不采用。
强制 u=t
使插值器的生活变得太艰难,因为一些 t
值彼此非常接近,而相应的点由于变化 [=13] 而不是那么接近=].这会导致插值曲线与数据的偏差很大,即第二个图上的异常值。
相反,使用默认值 u
计算样条,然后重新参数化与极角成比例。为此,我首先评估参数域中等间距值的样条(如您的第一次尝试),用 unwrap(arctan2)
找到每个结果点的极角,然后找到 u-> 的倒数具有线性插值的角度函数。插入样条中的这个反函数根据极角生成均匀间隔的点。
xx, yy = splev(np.linspace(0, 1, 200), tck)
s = np.unwrap(np.arctan2(yy, xx))
s_inv = np.interp(np.linspace(s[0], s[-1], len(s)), s, np.linspace(0, 1, len(s)))
xi, yi = splev(s_inv, tck)