如何将Bézier曲线拟合为一组数据?

时间:2011-06-09 20:44:54

标签: python algorithm bezier curve-fitting

我有一组数据点(我可以精简),我需要使用Bézier curve。我需要速度超过准确性,但合身应该足够好,以便可识别。我也在寻找一种我可以使用的算法,它没有太多使用库(特别是NumPy)。

我已经阅读了几篇研究论文,但没有足够的细节可以完全实现。有没有开源示例?

7 个答案:

答案 0 :(得分:17)

我有类似的问题,我从Graphics Gems(1990)找到了关于Bezier曲线拟合的“自动拟合数字化曲线的算法”。 除此之外,我还发现了source code这篇文章。

不幸的是,它是用C编写的,我不太清楚。此外,该算法很难理解(至少对我而言)。我试图将其转换为C#代码。如果我会成功,我会尝试分享。

GGVecLib.c在同一文件夹中的文件FitCurves.c包含基本的矢量操作函数。

我找到了类似的Stack Overflow问题, Smoothing a hand-drawn curve 。批准的答案提供了来自Graphic Gems的曲线拟合算法的C#代码。

答案 1 :(得分:9)

很多这些答案中缺少的是您可能不希望将单个Bézier曲线拟合到数据中。更一般地说,您希望将一系列三次Bézier曲线(即,分段三次Bézier拟合)拟合到任意数据集。

有一篇很好的论文,可以追溯到1995年,完成了MATLAB代码,可以做到这一点:

% Lane, Edward J. Fitting Data Using Piecewise G1 Cubic Bezier Curves.
% Thesis, NAVAL POSTGRADUATE SCHOOL MONTEREY CA, 1995

http://www.dtic.mil/dtic/tr/fulltext/u2/a298091.pdf

要使用此功能,您必须至少指定结点的数量,即优化例程将使用的数据点数。您可以选择自己指定结点,这样可以提高拟合的可靠性。论文展示了一些相当棘手的例子。注意,Lane的方法保证了立方Bézier段之间的G1连续性(相邻切向量的方向相同),即平滑关节。但是,曲率可能存在不连续性(二阶导数方向的变化)。

我重新实现了代码,将其更新为现代MATLAB(R2015b)。如果您愿意,请与我联系。

这是一个仅使用三个结点(由代码自动选择)的示例,将两个立方Bézier线段拟合到Lissajous图形。

Lissajous figure

答案 2 :(得分:5)

您可以将问题设置为适合噪声数据的最小二乘法。

请参阅http://nbviewer.ipython.org/5688579

请注意,一旦找出方程式,实际计算就相当简单了。实际计算是对数据进行求和,然后反转并乘以4x4矩阵。

我知道这个帖子现在已经很久了,但我发现这是一个有趣的问题,万一其他人偶然发现它。

有关最小二乘法的优秀教程,请参阅http://www.embedded.com/electrical-engineer-community/industry-blog/4027019/1/Why-all-the-math-

答案 3 :(得分:2)

如果大多数数据符合模型,您可以尝试RANSAC。选择4个点并随机选择贝塞尔曲线就足够了。我不确定在所有其他点(RANSAC算法的一部分)上评估曲线的成本是多么昂贵。但它将是一个线性解决方案,RANSAC非常容易编写(并且可能还有开源算法)。

答案 4 :(得分:2)

在这里,您可以找到引用的C代码的python实现。 https://github.com/volkerp/fitCurves

答案 5 :(得分:0)

首先,确保你要求的实际上是你想要的。将点拟合到贝塞尔曲线将它们放置在点的船体中。使用样条曲线可确保曲线遍历所有点。

也就是说,创建绘制其中任何一个的函数并不复杂。维基百科有一篇很好的文章,将解释基础知识, Bézier curve

答案 6 :(得分:0)

我有一个针对这个问题的MATLAB解决方案。 我遇到了同样的问题,但我的代码是用MATLAB编写的。 我希望将其翻译成Python并不太难。

您可以通过此代码找到控制点FindBezierControlPointsND.m 出于某种原因,它的档案中没有“ChordLengthNormND”功能, 但它在第45行被召唤。

我用以下几行代替它:

[arclen,seglen] = arclength(p(:,1),p(:,2),'sp');
t = zeros(size(p,1),1);
sums = seglen(1);
for i = 2:size(p,1)-1
    t(i) = sums / arclen;
    sums = sums + seglen(i);
end
t(end) = 1;

arclength的MATLAB代码可以在这里获得。

之后,我们有Bezier曲线的控制点,并且有许多通过Web上的控制点构建Bezier曲线的实现。