C# 如何获得最接近给定点的三次贝塞尔曲线?

C# 如何获得最接近给定点的三次贝塞尔曲线?,c#,algorithm,math,bezier,curve-fitting,C#,Algorithm,Math,Bezier,Curve Fitting,给定n点: p0,p1,p2,…,pn 如何得到点c1,c2,使三次贝塞尔曲线由 p0,c1,c2,pn 最接近给定点 我试过最小二乘法。我是在读了pdf文档后写的。但是我找不到一个好的t(I)函数 using System; using System.Collections.Generic; using System.Linq; using System.Windows; namespace BezierFitting { class CubicBezierFittingCalcul

给定n点:

p0,p1,p2,…,pn

如何得到点c1,c2,使三次贝塞尔曲线由

p0,c1,c2,pn

最接近给定点

我试过最小二乘法。我是在读了pdf文档后写的。但是我找不到一个好的t(I)函数

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);
        }
    }
}
这些点分布在由四个点控制的三次贝塞尔曲线周围:

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

假设曲线从(0,256)到(256,256),如何使其余两个控制点靠近原始点?

A(三次)贝塞尔曲线是一种定义一般形式的三次参数样条曲线p=A*t^3+B*t^2+C*t+D的方法,其中p、A、B、C和D是(二维,即向量)权重。使用Bernstein多项式,可以计算给定四个控制点P0、P1、P2和P3的权重A、B、C和D,这四个控制点是几乎所有矢量绘图程序中已知的

由于您只有四个控制点,但希望适合任意数量的任意点,因此我怀疑没有唯一的解决方案。例如,给定输入(0,0)、(1,0)、(1,1)和(0,1),对于每个“最佳”解决方案(无论是什么),可以通过沿主对角线镜像样条曲线来构造一个等效解决方案

这类问题有一种通用方法,即构造一个方程,求出所有点到一般贝塞尔曲线(即由变量a、B、C和D定义的曲线)距离的平方和,计算出第一个偏差,并将其设为零,然后解出a、B的结果系,这通常会导致一个线性方程组(对不起,我需要一些时间来做数学,我已经很久没有做过了…)。但是,正如我所说的,我认为对于你的问题,这不会产生一个独特的解决方案


如果您在输入点上定义顺序,即,您希望使用单个贝塞尔曲线拟合多边形线,我认为对于唯一的解决方案来说,自由度太多了(但是,同样,我没有时间或者可能没有技能来证明…

如果您想创建带尖点的曲线,您的问题非常困难。我可以想出一种启发式方法来创建一组初始控制点。对于第一个控制点,从到第一个锚定点的距离排序时,尝试获取可用点的前1/3。排序是必要的,否则,你可能会跳得到处都是。取三分之一的点,进行线性最小二乘拟合,这具有线性时间复杂度。这为你的曲线提供了出发的方向。对最后1/3做同样的事情,你就有了“着陆”的方向

使用这些线性解决方案创建指向远离锚定点的向量,然后尝试使这些向量变长变短,以尽量减小误差。控制点将沿着锚定点的矢量

以下是一些其他想法(我只能发布两个链接!)

根据您的问题判断,我假设您只希望优化三次贝塞尔的2个“内部”控制点上的曲线拟合。这不是一个容易解决的问题,因为贝塞尔曲线是参数化描述的。最明显的解决方案是使用最小二乘正交距离回归,但这很困难,因为您需要为希望拟合的每个点在Bezier曲线上生成脚点参数。如果这个问题需要一个特定的分析解决方案,并且您受过一些数学教育,我建议您阅读Peigl和Tiller的《NURBS手册》,熟悉近似理论和优化技术。如果不是,我会选择一种更具启发性的方法,因为这类问题不可能用简单的答案来解决。

您可能想看看

这是一个非常好的实现,尽管正如作者所写:“这种方法纯粹是启发式和经验性的。从严格数学建模的角度来看,它可能给出错误的结果。但在实践中,结果已经足够好了,并且需要绝对最小的计算量。”

<>这是C++语言,但它很容易移植到任何语言… 通过控制点计算函数传递每个“边”,然后通过贝塞尔计算函数传递一条,就得到了它。 若要对多边形执行bezier平滑,请使用最后一个点和第一个点传递最后一条边


Khan的函数使用了两种版本的t[i],其中t[i]表示近似曲线上最接近输入点p[i]的点的猜测。第一个简单地使用统一的t[i]=i/(N-1),第二个使用弦长。虽然我找不到Khan的函数,但我认为这只是计算线性距离p[I]到p[I+1],将t[0]设置为0,t[1]设置为距离p[0]到p[1],t[2]到t[1]+距离p[1]到p[2],依此类推。将值除以最后一个值,使所有值都在0-1范围内

你是在给定点拟合一个三次多项式吗?引入“控制点”c1和c2可唯一确定适合四个点p0、c1、c2、pn的三次多项式。现在,“最佳方式”需要一个亲密度标准。假设数据由2D点组成,x坐标为独立值,y坐标为(功能)相关值,点p0、…、pn按(不同的)递增x坐标排列。你的曲线精确地拟合第一个点和最后一个点,所以“最近的曲线”可能会使y值或其他目标的平方和误差最小化。这是我想要拟合的三次贝塞尔曲线。不是一个三次多项式。您可以使用Bernstein基来计算新的控制点,如中所述,在
应用程序插值
部分下不要采取错误的方式,但在我看来,您缺少对此的基本理解。“贝塞尔”不是一种曲线,就像“样条曲线”不是一种曲线一样
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