30

I have a set of data points (which I can thin out) that I need to fit with a Bézier curve. I need speed over accuracy, but the fit should be decent enough to be recognizable. I'm also looking for an algorithm I can use that doesn't make much use of libraries (specifically NumPy).

I've read several research papers, but none has enough detail to fully implement. Are there any open-source examples?

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
user791684
  • 336
  • 1
  • 3
  • 6

5 Answers5

19

I have similar problem and I have found "An algorithm for automatically fitting digitized curves" from Graphics Gems (1990) about Bezier curve fitting. Additionally to that I have found source code for that article.

Unfortunately it is written in C which I don't know very well. Also, the algorithm is quite hard to understand (at least for me). I am trying to translate it into C# code. If I will be successful, I will try to share it.

File GGVecLib.c in the same folder as FitCurves.c contains basic vectors manipulation functions.

I have found a similar Stack Overflow question, Smoothing a hand-drawn curve. The approved answer provide C# code for a curve fitting algorithm from Graphic Gems.

Community
  • 1
  • 1
Archibald
  • 776
  • 8
  • 24
  • It does look complicated. Can anyone verify this code works? – user791684 Jun 24 '11 at 03:21
  • Your link for _An algorithm for automatically fitting digitized curve_ is broken. – Michael Scheper Dec 01 '14 at 03:28
  • 1
    @MichaelScheper Article was removed, it seems that they are still selling those books so this article was little bit shady. Used Graphics Gems on amazon cost around 10$. – Archibald Dec 01 '14 at 12:42
  • How sad. Thanks for updating your answer. – Michael Scheper Dec 01 '14 at 21:26
  • 1
    I ported this algorithm line-by-line to Javascript and I can confirm that it works. I used a paper copy of the book, but I found the C code by searching online. – Steve Hanov Oct 20 '15 at 00:57
  • 3
    I found a python implementation using numpy that mentions this same article: https://github.com/soswow/fit-curves/blob/master/python/fitCurves.py – saschwarz Dec 13 '15 at 23:45
  • i played with its JS version here http://soswow.github.io/fit-curves/demo/ i do not get a loop or a cusp even with highest error tolerance. Does the C algorithm behave similarly? – ProgramCpp Sep 24 '16 at 11:10
  • 1
    @saschwarz Your link has become invalid. The new link may be https://github.com/volkerp/fitCurves – Waruyama Dec 30 '19 at 21:30
14

What's missing in a lot of these answers is that you may not want to fit a single cubic Bézier curve to your data. More generally, you would like to fit a sequence of cubic Bézier curves, i.e., a piecewise cubic Bézier fit, to an arbitrary set of data.

There's a nice thesis dating from 1995, complete with MATLAB code, that does this:

% 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

To use this, you must, at minimum, specify the number of knot points, i.e., the number data points that will be used by the optimization routines to make this fit. Optionally, you can specify the knot points themselves, which increases the reliability of a fit. The thesis shows some pretty tough examples. Note that Lane's approach guarantees G1 continuity (directions of adjacent tangent vectors are identical) between the cubic Bézier segments, i.e., smooth joints. However, there can be discontinuities in curvature (changes in direction of second derivative).

I have reimplemented the code, updating it to modern MATLAB (R2015b). Contact me if you would like it.

Here's an example of using just three knot points (chosen automatically by the code) the fits two cubic Bézier segments to a Lissajous figure.

Lissajous figure

Biofloat
  • 259
  • 3
  • 10
  • 1
    I'd appreciate if you could post your re-implementation of the code to MATLAB R2015b in a [GitHub gist](https://gist.github.com/) and link to it here. Thank you! – Michael Currie Mar 16 '17 at 11:14
  • 1
    Here is the code on GitLab: https://gitlab.com/erehm/PiecewiseG1BezierFit – Biofloat Apr 29 '18 at 16:22
2

If most of the data fits the model you could try RANSAC. It would be easy enough to pick 4 points and random and fit a bezier curve from those. I'm not sure off the top of my head how expensive it would be to evaluate the curve against all the other points (part of the RANSAC algorithm). But it would be a linear solution and RANSAC is really easy to write (and there are probably open source algorithms out there).

Pace
  • 33,215
  • 10
  • 99
  • 130
  • Each iteration of RANSAC would require evaluating the curve and finding the distances to all the points. If this is in 1D then it is simple, in 2D or 3D it gets difficult because you need to find the closest point on the curve and calculate the error (Euclidean distance) to that. This will be at least O(n) per iteration. The number of iterations is given by the ratio of inliers and the size of your model. So if you would be fitting a single 4-point arc, it might be doable. The more points in the arc and the chance of getting the points right decreases exponentially. – the swine Mar 03 '17 at 11:14
  • So this would work for simple cases of single arcs but would get infinitely slow for longer splines. More importantly, note that for Beziers, the curve *does not pass through the points*, so that even if you selected the correct points, it would give you a wrong curve. You would be better off with e.g. Catmull-Rom splines that do pass through the control points. – the swine Mar 03 '17 at 11:44
  • However, this does not mean that a Bezier curve cannot be fit to a set of points. What it means is that at least some of the control points of this curve will not coincide with the data points. But if using techniques such as least squares, that hardly matters. – the swine Mar 05 '17 at 14:02
0

I had a MATLAB solution for this problem. I encountered the same problem, but my code is written in MATLAB. I hope its not too hard to translate it into Python.

You can find the control points by this code FindBezierControlPointsND.m For some reason, it does not have function "ChordLengthNormND" in its archive, but it is called at line 45.

I replaced it by following lines:

[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's MATLAB code can be obtained here.

After that, we have control points for Bezier curve, and there are lots of implementation of building Bezier curve by control points on the web.

lintseju
  • 21
  • 4
-2

First of all, make sure what you ask for is actually what you want. Fitting the points to a Bezier curve will place them in the hull of the points. Using a spline will make sure your curve goes through all points.

That said, creating the function that draws either is not complicated at all. Wikipedia has a nice article that will explain the basics, Bézier curve.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Pedery
  • 3,552
  • 1
  • 23
  • 38
  • 4
    Downvoted because this simply doesnt answer the question. Linking to Bezier curves at wikipedia is just stating the obvious, and additionally the wikipedia article doesnt address curve fitting – Ben Hutchison Nov 02 '15 at 03:00