13

我有一个不均匀间隔的 (x,y) 值列表。是此问题中使用的存档。

我能够在值之间进行插值,但我得到的不是等间距的插值点。这就是我所做的:

x_data = [0.613,0.615,0.615,...]
y_data = [5.919,5.349,5.413,...]

# Interpolate values for x and y.
t = np.linspace(0, 1, len(x_data))
t2 = np.linspace(0, 1, 100)
# One-dimensional linear interpolation.
x2 = np.interp(t2, t, x_data)
y2 = np.interp(t2, t, y_data)

# Plot x,y data.
plt.scatter(x_data, y_data, marker='o', color='k', s=40, lw=0.)

# Plot interpolated points.
plt.scatter(x2, y2, marker='o', color='r', s=10, lw=0.5)

结果是:

在此处输入图像描述

可以看出,在图中原始点分布更密集的部分,红点更靠近。

我需要一种方法来根据给定的步长值(比如 0.1)生成在 x、y 中等距的插值点


正如askewchan正确指出的那样,当我的意思是“在 x、y 中等距”时,我的意思是曲线中的两个连续插值点应该彼此相距相同的值(欧几里得直线距离)。


我尝试了 unubtu 的答案,它适用于平滑曲线,但似乎不那么平滑:

非平滑曲线

发生这种情况是因为代码以欧几里德方式而不是直接在曲线上计算点距离,并且我需要曲线上的距离在点之间是相同的。这个问题可以以某种方式解决吗?

4

5 回答 5

18

将您的 xy 数据转换为参数化曲线,即计算点之间的所有距离并通过累积求和生成曲线上的坐标。然后相对于新坐标独立地插入 x 和 y 坐标。

import numpy as np
from matplotlib import pyplot as plt

data = '''0.615   5.349
    0.615   5.413
    0.617   6.674
    0.617   6.616
    0.63    7.418
    0.642   7.809
    0.648   8.04
    0.673   8.789
    0.695   9.45
    0.712   9.825
    0.734   10.265
    0.748   10.516
    0.764   10.782
    0.775   10.979
    0.783   11.1
    0.808   11.479
    0.849   11.951
    0.899   12.295
    0.951   12.537
    0.972   12.675
    1.038   12.937
    1.098   13.173
    1.162   13.464
    1.228   13.789
    1.294   14.126
    1.363   14.518
    1.441   14.969
    1.545   15.538
    1.64    16.071
    1.765   16.7
    1.904   17.484
    2.027   18.36
    2.123   19.235
    2.149   19.655
    2.172   20.096
    2.198   20.528
    2.221   20.945
    2.265   21.352
    2.312   21.76
    2.365   22.228
    2.401   22.836
    2.477   23.804'''

data = np.array([line.split() for line in data.split('\n')],dtype=float)

x,y = data.T
xd = np.diff(x)
yd = np.diff(y)
dist = np.sqrt(xd**2+yd**2)
u = np.cumsum(dist)
u = np.hstack([[0],u])

t = np.linspace(0,u.max(),10)
xn = np.interp(t, u, x)
yn = np.interp(t, u, y)

f = plt.figure()
ax = f.add_subplot(111)
ax.set_aspect('equal')
ax.plot(x,y,'o', alpha=0.3)
ax.plot(xn,yn,'ro', markersize=8)
ax.set_xlim(0,5)

代码生成的图

于 2013-10-01T17:10:26.803 回答
10

让我们首先考虑一个简单的案例。假设您的数据看起来像下面的蓝线。

在此处输入图像描述

如果您想选择相距较远的等距点,那么(1,2) 处的尖点是第一个等距点的位置r会有一些临界值。r

如果您想要的点之间的距离大于这个临界距离,那么第一个等距点将从 (1,2) 跳到某个非常不同的地方——由绿色弧线与蓝线的交点描绘。这种变化不是渐进的。

这个玩具案例表明,参数的微小变化r可能会对解产生根本的、不连续的影响。

它还建议您必须先知道第 i 个等距点的位置,然后才能确定第 (i+1) 个等距点的位置。

因此,似乎需要一个迭代解决方案:

import numpy as np
import matplotlib.pyplot as plt
import math

x, y = np.genfromtxt('data', unpack=True, skip_header=1)
# find lots of points on the piecewise linear curve defined by x and y
M = 1000
t = np.linspace(0, len(x), M)
x = np.interp(t, np.arange(len(x)), x)
y = np.interp(t, np.arange(len(y)), y)
tol = 1.5
i, idx = 0, [0]
while i < len(x):
    total_dist = 0
    for j in range(i+1, len(x)):
        total_dist += math.sqrt((x[j]-x[j-1])**2 + (y[j]-y[j-1])**2)
        if total_dist > tol:
            idx.append(j)
            break
    i = j+1

xn = x[idx]
yn = y[idx]
fig, ax = plt.subplots()
ax.plot(x, y, '-')
ax.scatter(xn, yn, s=50)
ax.set_aspect('equal')
plt.show()

在此处输入图像描述

注意:我将纵横比设置为'equal'以使点等距更明显。

于 2013-10-01T14:18:40.570 回答
2

以下脚本将以相等的步长插入点x_max - x_min / len(x) = 0.04438

import numpy as np
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt

data = np.loadtxt('data.txt')
x = data[:,0]
y = data[:,1]

f = interp1d(x, y)
x_new = np.linspace(np.min(x), np.max(x), x.shape[0])
y_new = f(x_new)

plt.plot(x,y,'o', x_new, y_new, '*r')
plt.show()

在此处输入图像描述

于 2013-10-01T14:41:45.807 回答
2

扩展@Christian K. 的答案,这里是如何使用scipy.interpolate.interpn. 假设我们要重新采样到 10 个等距点:

import numpy as np
import scipy
# Assuming that 'data' is rows x dims (where dims is the dimensionality)
diffs = data[1:, :] - data[:-1, :]
dist = np.linalg.norm(diffs, axis=1)
u = np.cumsum(dist)
u = np.hstack([[0], u])
t = np.linspace(0, u[-1], 10)
resampled = scipy.interpolate.interpn((u,), pts, t)
于 2020-03-17T00:33:22.037 回答
0

可以沿曲线生成等距点。但是必须有更多的定义你想要一个真正的答案。抱歉,我为此任务编写的代码是在 MATLAB 中,但我可以描述一般的想法。有三种可能性。

首先,就简单的欧几里得距离而言,这些点与邻居的距离是否真正等距?这样做需要找到曲线上任意点与固定半径圆的交点。然后沿着曲线走。

接下来,如果您打算将距离表示为沿曲线本身的距离,如果曲线是分段线性的,那么问题又很容易解决。只需沿着曲线走,因为线段上的距离很容易测量。

最后,如果您打算让曲线成为三次样条曲线,这同样不是非常困难,但需要更多的工作。这里的诀窍是:

  • 计算沿曲线的点到点的分段线性弧长。称之为吨。
  • 生成一对三次样条,x(t), y(t)。
  • 将 x 和 y 微分为 t 的函数。由于这些是立方段,这很容易。导数函数将是分段二次的。
  • 使用 ode 求解器沿曲线移动,积分微分弧长函数。在 MATLAB 中,ODE45 运行良好。

因此,一个集成

sqrt((x')^2 + (y')^2)

同样,在 MATLAB 中,可以设置 ODE45 来识别函数穿过某些指定点的位置。

如果您的 MATLAB 技能能够胜任这项任务,您可以查看interparc中的代码以获得更多解释。这是相当好的注释代码。

于 2013-10-01T14:33:54.730 回答