我有一些需要平滑的模糊矩形2D图形。一个简化的例子:
fig, ax1 = plt.subplots(1,1, figsize=(3,3))
xs1 = [-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]
ys1 = [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]
ax1.plot(xs1, ys1)
ax1.set_ylim(0.5,2.5)
ax1.set_xlim(-2,2) ;
我已经尝试了scipy.interpolate.RectBivariateSpline,但显然需要所有点的数据(例如热图)和scipy.interpolate.interp1d,但是,合理地说,想要生成1d平滑版本。
平滑此问题的适当方法是什么?
修改以更好地修改/解释我的目标。我不需要这些线路来完成所有要点;事实上,我更喜欢他们没有经历所有的观点,因为有明确的异常点,而且应该""与邻居平均,或类似的方法。我已经包含了一个粗略的手册草图,上面是我的想法。
答案 0 :(得分:12)
Chaikin的切角算法可能是您理想的选择。对于顶点为P0,P1,... P(N-1)的给定多边形,角切割算法将为P(i)和P(i + 1)定义的每个线段生成2个新顶点
Q(i)=(3/4)P(i)+(1/4)P(i + 1)
R(i)=(1/4)P(i)+(3/4)P(i + 1)
因此,您的新多边形将具有2N个顶点。然后,您可以再次重复应用新多边形上的切角,直到达到所需的分辨率。结果将是具有许多顶点的多边形,但在显示时它们看起来会很平滑。可以证明,由此拐角切割方法产生的结果曲线将收敛为二次B样条曲线。这种方法的优点是最终的曲线永远不会过度拍摄。以下图片将让您更好地了解此算法(图片取自this link)
原始多边形
一次涂角切割
再次应用角切割
有关Chaikin角切割算法的详细信息,请参阅此 link 。
答案 1 :(得分:7)
实际上,您可以使用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()
但是,正如您所看到的,这会在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]
# Pad the x and y series so it "wraps around".
# Note that if x and y are numpy arrays, you'll need to
# use np.r_ or np.concatenate instead of addition!
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()
只是为了显示您的数据的样子:
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]
# Pad the x and y series so it "wraps around".
# Note that if x and y are numpy arrays, you'll need to
# use np.r_ or np.concatenate instead of addition!
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()
请注意,使用此方法会产生相当多的“过冲”。这是由于三次样条插值。 @ pythonstarter的建议是另一种处理它的好方法,但贝塞尔曲线会遇到同样的问题(它们在数学上基本相同,只是控制点的定义方式)。有许多其他方法来处理平滑,包括专门用于平滑多边形的方法(例如,具有指数内核的多项式近似(PAEK))。我从来没有试过实现PAEK,所以我不确定它是如何涉及的。如果您需要更强大地执行此操作,您可以尝试查看PAEK或其他类似方法。
答案 2 :(得分:3)
这是答案的更多评论,但也许您可以尝试将此多边形定义为贝塞尔曲线。代码相当简单,我确信您熟悉这条曲线的工作原理。在那种情况下,该曲线将是控制多边形。但它并不完美:首先它不是这个多边形的“平滑版本”,而是一条曲线,另一件事;曲线越高,控制多边形越小。我想说的是,也许你应该尝试使用数学工具来解决这个问题,而不是尝试使用编程技巧来平滑而不是使多边形平滑