2D轨迹的路径简化和平滑算法

时间:2015-01-01 13:26:51

标签: algorithm computational-geometry

我正在寻找一种路径简化和平滑2D轨迹的算法。所以我有一个2D点的有序列表。这些要点应该简化,例如使用Ramer-Douglas-Peucker算法。但输出必须是平滑的,因此生成的路径应该由贝塞尔曲线或样条曲线构造。是否可以对Ramer-Douglas-Peucker算法进行任何修改?

我在paper.js库中找到了一个路径简化算法,它正是我正在搜索的内容:http://paperjs.org/examples/path-simplification/但是我无法从未记录的javascript源代码中理解算法。

3 个答案:

答案 0 :(得分:11)

您要做的工作属于"曲线拟合"的范畴。曲线拟合有很多不同的算法,但几乎所有的曲线拟合算法都可以分为两个不同的类别:插值和近似。插值算法产生的曲线精确地通过所有数据点,而近似算法生成靠近数据点的曲线。当然,也存在混合算法。

由于您希望对数据点进行平滑处理,因此您应该寻找近似算法。对于您提到的两种算法:RDP算法和Schneider算法(Paper.js中的算法),它们都是近似算法。所以,基本上你可以使用它们中的任何一个。对于RDP,在获得简化路径后,您可以使用通过简化路径的顶点创建Catmull Rom样条曲线或Overhauser样条曲线来获得平滑曲线。但是,您无法直接控制生成的样条曲线与原始路径中的顶点之间的偏差。

对于Schneider算法,它将首先通过具有末端切线约束的三次贝塞尔曲线拟合数据点。如果与得到的曲线的偏差太大,那么它会将数据点分成两个区域"并使用具有末端切线约束的三次贝塞尔曲线拟合每个数据区域。将重复该过程,直到对所有三次贝塞尔曲线的偏差足够小。结果,它产生一系列立方贝塞尔曲线,最多连接C1连续性(很可能它实际上只是G1)。此外,由于该算法从原始数据点评估末端切线,因此数据点中的噪声将影响末端切线评估,因此影响三次贝塞尔拟合。

如果你可以花时间在曲线拟合的主题上,你应该研究B样条曲线的最小二乘拟合。这将生成具有高连续性的输出曲线(例如,对于立方B样条曲线,C2)。如果你没有多少时间花在上面,那么施耐德的算法是一个很好的选择,可以在实现成本(如果你必须用特定的语言重新实现它)和结果曲线之间取得平衡。 #39;质量。

答案 1 :(得分:5)

您尝试做的事情称为 Curve Fitting.

虽然Ramer-Douglas-Peucker算法基本上通过去除不必要的点来平滑折线中的“噪声” - 但曲线拟合算法将适合通过这些点的贝塞尔曲线。

Here在Youtube上是一个非常好的例子,here是描述算法本身的原始论文。


至于Paper.js示例:

  • This是该特定功能的Github链接 你提到过这个评论很好。那篇研究论文 使用的是 this

  • 同样here是关于邮件列表的非常简短的讨论 什么是使用和什么不是(显然使用Ramer-Douglas-Peucker 但稍后删除

答案 2 :(得分:0)

就我而言,我发现Catmull-Rom样条线最容易应用。 Mika的《编码位》中的Smooth Paths Using Catmull-Rom Splines文章非常有帮助。我用它在Unity3D项目中用C#实现样条插值脚本。这是脚本:

public static Vector2 CatmullRomInterpolation(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t, float alpha = .5f, float tension = 0)
{
    float t01 = Mathf.Pow(Vector2.Distance(p0, p1), alpha);
    float t12 = Mathf.Pow(Vector2.Distance(p1, p2), alpha);
    float t23 = Mathf.Pow(Vector2.Distance(p2, p3), alpha);
    Vector2 m1 = (1.0f - tension) * (p2 - p1 + t12 * ((p1 - p0) / t01 - (p2 - p0) / (t01 + t12)));
    Vector2 m2 = (1.0f - tension) * (p2 - p1 + t12 * ((p3 - p2) / t23 - (p3 - p1) / (t12 + t23)));
    return (2.0f * (p1 - p2) + m1 + m2) * Mathf.Pow(t, 3) + (-3.0f * (p1 - p2) - m1 - m1 - m2) * Mathf.Pow(t, 2) + m1 * t + p1;
}

p0和p3是控制点,应该与路径中的起点和终点p1和p2不同。