简体   繁体   中英

How can I get a cubic bezier curve closest to given points?

Given n points:

p0, p1, p2, ..., pn;

How can I get the point c1, c2 so that the cubic bezier curve defined by

p0, c1, c2, pn

closest to the given points?

I tried least square method. I wrote this after I read the pdf document in http://www.mathworks.com/matlabcentral/fileexchange/15542-cubic-bezier-least-square-fitting . But I can't find a good t(i) function.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;

namespace BezierFitting
{
    class CubicBezierFittingCalculator
    {
        private List<Point> data;

        public CubicBezierFittingCalculator(List<Point> data)
        {
            this.data = data;
        }

        private double t(int i)
        {
            return (double)(i - 1) / (data.Count - 1);
            // double s = 0.0, d = 0.0;
            // 
            // for (int j = 1; j < data.Count; j++)
            // {
            //     if (j < i)
            //     {
            //         s += (data[j] - data[j - 1]).Length;
            //     }
            //     d += (data[j] - data[j - 1]).Length;
            // }
            // return s / d;
        }

        public void Calc(ref Point p1, ref Point p2)
        {
            double n = data.Count;
            Vector p0 = (Vector)data.First();
            Vector p3 = (Vector)data.Last();

            double a1 = 0.0, a2 = 0.0, a12 = 0.0;
            Vector c1 = new Vector(0.0, 0.0), c2 = new Vector(0.0, 0.0);
            for (int i = 1; i <= n; i++)
            {
                double ti = t(i), qi = 1 - ti;
                double ti2 = ti * ti, qi2 = qi * qi;
                double ti3 = ti * ti2, qi3 = qi * qi2;
                double ti4 = ti * ti3, qi4 = qi * qi3;
                a1 += ti2 * qi4;
                a2 += ti4 * qi2;
                a12 += ti3 * qi3;

                Vector pi = (Vector)data[i - 1];
                Vector m = pi - qi3 * p0 - ti3 * p3;
                c1 += ti * qi2 * m;
                c2 += ti2 * qi * m;
            }
            a1 *= 9.0;
            a2 *= 9.0;
            a12 *= 9.0;
            c1 *= 3.0;
            c2 *= 3.0;

            double d = a1 * a2 - a12 * a12;
            p1 = (Point)((a2 * c1 - a12 * c2) / d);
            p2 = (Point)((a1 * c2 - a12 * c1) / d);
        }
    }
}

What's the best way to get a cubic bezier curve closest to given points?

For example, here are 30 points:

22, 245
26, 240
39, 242
51, 231
127, 189
136, 185
140, 174
147, 171
163, 162
169, 155
179, 107
181, 147
189, 168
193, 187
196, 75
199, 76
200, 185
201, 68
204, 73
205, 68
208, 123
213, 118
216, 210
216, 211
218, 68
226, 65
227, 110
228, 102
229, 87
252, 247

Those points are distributed around the the cubic bezier curve controled by four points:

P0 (0, 256), P1 (512, 0), P2 (0, 0), P3 (256, 256).

Suppose the curve is from (0, 256) to (256, 256), how to get rest two control points close to the origional points?

You might want to have a look at this page : http://www.antigrain.com/research/bezier_interpolation/index.html

It's a very good implementation, though as the author writes : "This method is pure heuristic and empiric. It probably gives a wrong result from the point of view of strict mathematical modeling. But in practice the result is good enough and it requires absolute minimum of calculations. "

It's in C++ but is really easily portable to any language... Pass each of your "edges" through the control points calculation function, then through the bezier calculation one, and you have it. To perform bezier smooth on a polygon, pass a last edge with your last and first point.

贝齐尔顺利

A (cubic) bezier curve is a way to define a cubic parametric spline of the general form P=A*t^3+B*t^2+C*t+D where P,A,B,C and D are (two-dimensional, ie vectorial) weights. Using Bernstein polynoms, you can calculate the weights A,B,C and D given four control points P0, P1, P2 and P3 as known from practically all vector drawing programs.

Since you only have four control points but want to fit an arbitrary number of arbitrary points, I suspect that there's no unique solution. For instance, given inputs (0,0),(1,0),(1,1) and (0,1), for every "optimal" solution (whatever it be), you could construct an aequivalent solution by mirroring the spline along the main diagonal.

There is a general approach for this kind of problems which is to construct an equation for the sum of squares of the distances for all points to a generic bezier curve (ie a curve defined by variables A,B,C and D), calculate tha first devirative and set it to zero and solve the resulting system for A,B,C and D. This usually leads to a linear system of equations (sorry, it would take me some time to do the maths, and it's been a long time since I did this ...). But, as I said, I think that for your problem, this wouldn't result in a unique solution.

If you define an order on the input points, ie you want to fit a polygon line using a single bezier curve, I think that there are too many degrees of freedom for a unique solution (but, again, I don't have the time or maybe the skills to prove that ...)

Your problem is very hard if you want to create curves with cusps. I can think of a heuristic to create an initial set of control points. For the first control point, try taking the first 1/3 of the points you have available, when sorted from the distance to the first anchor point. The sorting is necessary, otherwise, you may be jumping all over. Take that 1/3 of your points and do a linear least squares fit, which is has linear time complexity. That gives you the direction your curve needs to take off. Do the same thing with the last 1/3, and you have the "landing" direction.

Use those linear solutions to create vectors pointing away from the anchor points, then try making those vectors longer and shorter, trying to minimize the error. The control points would be along those vectors from the anchor points.

Here are some other ideas (I can only post two links!): physics forum question bezier curve fitting thesis

Judging by your question, I am assuming that you just wish to optimise the curve fit over the 2 'inner' control points of the cubic bezier. This is not an easy problem to solve as the bezier curve is described parametrically. The most obvious solution would be to use least-squares orthogonal distance regression but this is difficult as you will need to generate footpoint parameters onto the Bezier curve for each point you wish to fit. If this problem requires a specific anayltic solution and you have some mathematical education I would recommend reading "The NURBS Book" by Peigl and Tiller and becoming familiar with approximation theory and optimisation techniques. If not, I would go for a more heuristic type of approach as this type of problem is unlikely to be solved with a simple answer here.

Khan's function uses two versions of t[i], where t[i] represents the guess for closest point on the approximation curve to input point p[i]. The first simply uses uniform t[i] = i/(N-1), the second uses chord length. Whilst I couldn't find Khan's function, I think this simply calculates the linear distance p[i] to p[i+1], set t[0] to 0, t[1] to the distance p[0] to p[1], t[2] to t[1] + distance p[1] to p[2], and so on. The divide by the last value to put everything in the range 0-1.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM