贝塞尔曲线最小二乘法拟合(随意切向/切向方向统一)------路适用于绝大多数的最小二乘法拟合

标题@TOC

注意

本文出现大量公式,但是博主保证,只要专心看下去,公式都不难的。

简介

最近参加了一个拟合边缘的项目,本来是刚接手的时候只有直线拟合和2、3次线性拟合,因为实验品是丰富多样的,再加上客户比较挑,两端之间的交界处那边希望看起来圆滑点,在这里插入图片描述
所以以上这三种显然是无法满足的,于是就想到了贝塞尔曲线,最终效果还是蛮好的,因为公式是自己纯手推的,所以想到特地来趁热记录下,免得后天又忘天上去了。先提醒一下,本篇博客公式是比较多,但是仔细看的话公式大部分都是积分,并不涉及其他比较深奥的公式,仔细看就很简单,相信我。
话不多说,先上效果图
红色部分是拟合后的效果
上图红色部分为拟合后的效果,并非是一段三次贝塞尔,而是好多段拼合起来的
一段的效果如下
在这里插入图片描述
显然不可行。
下图是源数据
在这里插入图片描述
只看红色部分哦!

贝塞尔曲线

贝塞尔曲线我就不过多介绍了,不清楚的同学可以问一问度娘,不过熟悉ps的同学应该知道里面的钢笔工具就是贝塞尔,写到这瞬间感觉自己快实现自动抠图了,
在这里插入图片描述
飘一下下就行了,自动抠图可谈不上,本次实验全是基于已有源数据的情况下进行的,源数据的获取不在本文范畴。
下面是三次贝塞尔曲线公式【(这里的公式存在一点问题,有一位细心的朋友指正了一下,但是因为后面的公式都是用这个错误的公式推导的,博主也懒得改了,所以各位同学只要学习方法即可,自己动手尝试的时候不要被我的公式误导了,正确的公式是 B ( t ) = P 0 ( 1 − t ) 3 + 3 ∗ P 1 t ( 1 − t ) 2 + 3 ∗ P 2 t 2 ( 1 − t ) + P 3 t 3 , t ∈ ( 0 , 1 ) . B(t) = P_0(1-t)^3+3*P_1t(1-t)^2+3*P_2t^2(1-t)+P_3t^3,t\in(0,1). B(t)=P0(1t)3+3P1t(1t)2+3P2t2(1t)+P3t3,t(0,1).)】
B ( t ) = P 0 ( 1 − t ) 3 + P 1 t ( 1 − t ) 2 + P 2 t 2 ( 1 − t ) + P 3 t 3 , t ∈ ( 0 , 1 ) . B(t) = P_0(1-t)^3+P_1t(1-t)^2+P_2t^2(1-t)+P_3t^3,t\in(0,1). B(t)=P0(1t)3+P1t(1t)2+P2t2(1t)+P3t3,t(0,1).
你需要知道的是:
三次贝塞尔曲线包括四个控制点,其中P0和P3分别代表曲线的起始位置和结束位置,P0到P1的方向表示曲线起始位置的切线方向,P2到P3的方向表示曲线结尾位置的切线方向。

最小二乘法拟合

曲线两端不带切向约束的公式推导

最小二乘法就是计算拟合后的位置和源数据的距离最小的时候的参数的值,假设Bix和Biy为拟合后第i个点对应的x,y坐标,Xi和Yi为源数据中第i个点的x,y坐标。N个点。
最小二乘法即是求公式:

∑ i = 1 N ( B i x − X i ) 2 + ( B i y − Y i ) 2 \sum_{i=1}^N{(B_{ix}-X_i)^2+(B_{iy}-Y_i)^2} i=1N(BixXi)2+(BiyYi)2
上述公式最小时各个参数的值即为求得的贝塞尔曲线的系数。
那让我们来思考一下这种情况下贝塞尔曲线需要计算几个系数呢?
首先首尾两个点并非是变量,而是每次拟合前要确定的也就是P0和P3是已知的量(如果未知的话或许也可以,但是我没有那样做,所以不知道最后效果如何,感兴趣的同学可以尝试一下)。P0和P3已知的情况下,曲线公式中就只剩下P1和P2作为未知量,再加上不带切向约束,P1以及P2的x,y坐标不存在线性关系,因此需要求的是四个系数:P1x,P1y,P2x和P2y。
我们假设:

t 1 = ( 1 − t ) 3 , t 2 = t ( 1 − t ) 2 , t 3 = t 2 ( 1 − t ) , t 4 = t 3 . t_1=(1-t)^3,t_2=t(1-t)^2,t_3=t^2(1-t),t_4=t^3. t1=(1t)3,t2=t(1t)2,t3=t2(1t),t4=t3.
其中 t为已知量,所以上述四个数值皆为已知量。(假设有N个源数据,第i个数据对应的 t(i-1)/(N-1) )
上述需要求解最小值的公式即为

∑ i = 1 N ( P 0 x t 1 + P 1 x t 2 + P 2 x t 3 + P 3 x t 4 − X i ) 2 + ( P 0 y t 1 + P 1 y t 2 + P 2 y t 3 + P 3 y t 4 − Y i ) 2 \sum_{i=1}^N{(P_{0x}t_1+P_{1x}t_2+P_{2x}t_3+P_{3x}t_4-X_i)^2+(P_{0y}t_1+P_{1y}t_2+P_{2y}t_3+P_{3y}t_4-Y_i)^2} i=1N(P0xt1+P1xt2+P2xt3+P3xt4Xi)2+(P0yt1+P1yt2+P2yt3+P3yt4Yi)2
因为上述公式只有P1x,P1y,P2x和P2y为未知量,所以分别对这四个变量求偏导数,四个偏导数结果同时为0时即为所求的结果,此时的贝塞尔曲线就是最接近所给源数据的贝塞尔曲线。
偏导数分别为:

  • 求P1x的偏导数为0的公式为
    ∑ i = 1 N 2 ∗ ( P 0 x t 1 + P 1 x t 2 + P 2 x t 3 + P 3 x t 4 − X i ) ∗ t 2 = 0 \sum_{i=1}^N{2*(P_{0x}t_1+P_{1x}t_2+P_{2x}t_3+P_{3x}t_4-X_i)*t_2}=0 i=1N2(P0xt1+P1xt2+P2xt3+P3xt4Xi)t2=0
  • 求P2x的偏导数为0的公式为
    ∑ i = 1 N 2 ∗ ( P 0 x t 1 + P 1 x t 2 + P 2 x t 3 + P 3 x t 4 − X i ) ∗ t 3 = 0 \sum_{i=1}^N{2*(P_{0x}t_1+P_{1x}t_2+P_{2x}t_3+P_{3x}t_4-X_i)*t_3}=0 i=1N2(P0xt1+P1xt2+P2xt3+P3xt4Xi)t3=0
  • 求P1y的偏导数为0的公式为
    ∑ i = 1 N 2 ∗ ( P 0 y t 1 + P 1 y t 2 + P 2 y t 3 + P 3 y t 4 − Y i ) ∗ t 2 = 0 \sum_{i=1}^N{2*(P_{0y}t_1+P_{1y}t_2+P_{2y}t_3+P_{3y}t_4-Y_i)*t_2}=0 i=1N2(P0yt1+P1yt2+P2yt3+P3yt4Yi)t2=0
  • 求P2y的偏导数为0的公式为
    ∑ i = 1 N 2 ∗ ( P 0 y t 1 + P 1 y t 2 + P 2 y t 3 + P 3 y t 4 − Y i ) ∗ t 3 = 0 \sum_{i=1}^N{2*(P_{0y}t_1+P_{1y}t_2+P_{2y}t_3+P_{3y}t_4-Y_i)*t_3}=0 i=1N2(P0yt1+P1yt2+P2yt3+P3yt4Yi)t3=0

上述四个公式整理之后为

∑ i = 1 N ( P 1 x t 2 + P 2 x t 3 ) ∗ t 2 = ∑ i = 1 N ( X i − P 0 x t 1 + P 3 x t 4 ) ∗ t 2 \sum_{i=1}^N{(P_{1x}t_2+P_{2x}t_3)*t_2}=\sum_{i=1}^N{(X_i-P_{0x}t_1+P_{3x}t_4)*t_2} i=1N(P1xt2+P2xt3)t2=i=1N(XiP0xt1+P3xt4)t2

∑ i = 1 N ( P 1 x t 2 + P 2 x t 3 ) ∗ t 3 = ∑ i = 1 N ( X i − P 0 x t 1 + P 3 x t 4 ) ∗ t 3 \sum_{i=1}^N{(P_{1x}t_2+P_{2x}t_3)*t_3}=\sum_{i=1}^N{(X_i-P_{0x}t_1+P_{3x}t_4)*t_3} i=1N(P1xt2+P2xt3)t3=i=1N(XiP0xt1+P3xt4)t3

∑ i = 1 N ( P 1 y t 2 + P 2 y t 3 ) ∗ t 2 = ∑ i = 1 N ( Y i − P 0 y t 1 + P 3 y t 4 ) ∗ t 2 \sum_{i=1}^N{(P_{1y}t_2+P_{2y}t_3)*t_2}=\sum_{i=1}^N{(Y_i-P_{0y}t_1+P_{3y}t_4)*t_2} i=1N(P1yt2+P2yt3)t2=i=1N(YiP0yt1+P3yt4)t2

∑ i = 1 N ( P 1 y t 2 + P 2 y t 3 ) ∗ t 3 = ∑ i = 1 N ( Y i − P 0 y t 1 + P 3 y t 4 ) ∗ t 3 \sum_{i=1}^N{(P_{1y}t_2+P_{2y}t_3)*t_3}=\sum_{i=1}^N{(Y_i-P_{0y}t_1+P_{3y}t_4)*t_3} i=1N(P1yt2+P2yt3)t3=i=1N(YiP0yt1+P3yt4)t3
继续整理,方便后续化为矩阵理解计算

∑ i = 1 N t 2 2 P 1 x + t 2 t 3 P 2 x + 0 P 1 y + 0 P 2 y = ∑ i = 1 N ( X i − P 0 x t 1 + P 3 x t 4 ) ∗ t 2 \sum_{i=1}^N{t_2^2P_{1x}+t_2t_3P_{2x}+0P_{1y}+0P_{2y}}=\sum_{i=1}^N{(X_i-P_{0x}t_1+P_{3x}t_4)*t_2} i=1Nt22P1x+t2t3P2x+0P1y+0P2y=i=1N(XiP0xt1+P3xt4)t2

∑ i = 1 N t 2 t 3 P 1 x + t 3 2 P 2 x + 0 P 1 y + 0 P 2 y = ∑ i = 1 N ( X i − P 0 x t 1 + P 3 x t 4 ) ∗ t 3 \sum_{i=1}^N{t_2t_3P_{1x}+t_3^2P_{2x}+0P_{1y}+0P_{2y}}=\sum_{i=1}^N{(X_i-P_{0x}t_1+P_{3x}t_4)*t_3} i=1Nt2t3P1x+t32P2x+0P1y+0P2y=i=1N(XiP0xt1+P3xt4)t3

∑ i = 1 N 0 P 1 x + 0 P 2 x + t 2 2 P 1 y + t 2 t 3 P 2 y = ∑ i = 1 N ( Y i − P 0 y t 1 + P 3 y t 4 ) ∗ t 2 \sum_{i=1}^N{0P_{1x}+0P_{2x}+t_2^2P_{1y}+t_2t_3P_{2y}}=\sum_{i=1}^N{(Y_i-P_{0y}t_1+P_{3y}t_4)*t_2} i=1N0P1x+0P2x+t22P1y+t2t3P2y=i=1N(YiP0yt1+P3yt4)t2

∑ i = 1 N 0 P 1 x + 0 P 2 x + t 2 t 3 P 1 y + t 3 2 P 2 y = ∑ i = 1 N ( Y i − P 0 y t 1 + P 3 y t 4 ) ∗ t 3 \sum_{i=1}^N{0P_{1x}+0P_{2x}+t_2t_3P_{1y}+t_3^2P_{2y}}=\sum_{i=1}^N{(Y_i-P_{0y}t_1+P_{3y}t_4)*t_3} i=1N0P1x+0P2x+t2t3P1y+t32P2y=i=1N(YiP0yt1+P3yt4)t3
在这里插入图片描述
细心的同学可能就发现了,上面四个公式完全可以转换成一个矩阵。

[ ∑ i = 1 N t 2 2 ∑ i = 1 N t 2 t 3 0 0 ∑ i = 1 N t 2 t 3 ∑ i = 1 N t 3 2 0 0 0 0 ∑ i = 1 N t 2 2 ∑ i = 1 N t 2 t 3 0 0 ∑ i = 1 N t 2 t 3 ∑ i = 1 N t 3 2 ] [ P 1 x P 2 x P 1 y P 2 y ] = [ ∑ i = 1 N ( X i − P 0 x t 1 + P 3 x t 4 ) ∗ t 2 ∑ i = 1 N ( X i − P 0 x t 1 + P 3 x t 4 ) ∗ t 3 ∑ i = 1 N ( Y i − P 0 y t 1 + P 3 y t 4 ) ∗ t 2 ∑ i = 1 N ( Y i − P 0 y t 1 + P 3 y t 4 ) ∗ t 3 ] \begin{bmatrix} \sum_{i=1}^N{t_2^2} & \sum_{i=1}^N{t_2t_3} & 0 & 0\\\\ \sum_{i=1}^N{t_2t_3} & \sum_{i=1}^N{t_3^2} & 0 & 0\\\\ 0 & 0 & \sum_{i=1}^N{t_2^2} & \sum_{i=1}^N{t_2t_3}\\\\ 0 & 0 & \sum_{i=1}^N{t_2t_3} & \sum_{i=1}^N{t_3^2} \end{bmatrix} \begin{bmatrix} P_{1x}\\\\ P_{2x}\\\\ P_{1y}\\\\ P_{2y} \end{bmatrix} =\begin{bmatrix} \sum_{i=1}^N{(X_i-P_{0x}t_1+P_{3x}t_4)*t_2}\\\\ \sum_{i=1}^N{(X_i-P_{0x}t_1+P_{3x}t_4)*t_3}\\\\ \sum_{i=1}^N{(Y_i-P_{0y}t_1+P_{3y}t_4)*t_2}\\\\ \sum_{i=1}^N{(Y_i-P_{0y}t_1+P_{3y}t_4)*t_3} \end{bmatrix} i=1Nt22i=1Nt2t300i=1Nt2t3i=1Nt320000i=1Nt22i=1Nt2t300i=1Nt2t3i=1Nt32P1xP2xP1yP2y=i=1N(XiP0xt1+P3xt4)t2i=1N(XiP0xt1+P3xt4)t3i=1N(YiP0yt1+P3yt4)t2i=1N(YiP0yt1+P3yt4)t3

类似于

A X = B AX=B AX=B

其中X为要求的四个变量组成的矩阵,A和B可以根据已有数据计算得出,然后可以利用opencv的solve函数估计得出X的结果,从而得出四个变量的值。
至此,两端不带切向约束的贝塞尔曲线拟合完成。

曲线一端带切向约束的公式推导

前端切向约束:
一端带切向约束的贝塞尔曲线拟合的意思是曲线某一端规定好切线方向,在此种情况下进行拟合求解,它包括前端约束和后端约束。这里只介绍前端约束即可,后端约束基本一致。

同样是求下面公式最小值时各非确定系数的值

∑ i = 1 N ( B i x − X i ) 2 + ( B i y − Y i ) 2 \sum_{i=1}^N{(B_{ix}-X_i)^2+(B_{iy}-Y_i)^2} i=1N(BixXi)2+(BiyYi)2

一端带切向约束的情况下,有几个系数是非确定的呢?

答案是三个。

很简单,和不带约束的情况一样,头尾控制点是已知确定的,只需要求取中间两个控制点。同时又因为前端的切线方向已知,因此只需要一个系数k即可求得第二个控制点,第三个控制点的x和y不存在什么线性关系,因此算作两个变量;综上所述,需要计算三个变量即可。
假设为k,P2x和P2y;
其中前端切向已知,就可以求出单位切向量vec,这样第二个控制点可以表示为

P 1 = P 0 + k ∗ v e c P_1=P_0+k*vec P1=P0+kvec

所以上述最小二乘式中的相关变量可以表示为

B i x = P 0 x t 1 + ( P 0 x + k ∗ v e c . x ) t 2 + P 2 x t 3 + P 3 x t 4 B_{ix}=P_{0x}t_1+(P_{0x}+k*vec.x)t_2+P_{2x}t_3+P_{3x}t_4 Bix=P0xt1+(P0x+kvec.x)t2+P2xt3+P3xt4

B i y = P 0 y t 1 + ( P 0 y + k ∗ v e c . y ) t 2 + P 2 y t 3 + P 3 y t 4 B_{iy}=P_{0y}t_1+(P_{0y}+k*vec.y)t_2+P_{2y}t_3+P_{3y}t_4 Biy=P0yt1+(P0y+kvec.y)t2+P2yt3+P3yt4

最小二乘式即可替换为

∑ i = 1 N ( P 0 x t 1 + ( P 0 x + k ∗ v e c . x ) t 2 + P 2 x t 3 + P 3 x t 4 − X i ) 2 + ( P 0 y t 1 + ( P 0 y + k ∗ v e c . y ) t 2 + P 2 y t 3 + P 3 y t 4 − Y i ) 2 \sum_{i=1}^N{(P_{0x}t_1+(P_{0x}+k*vec.x)t_2+P_{2x}t_3+P_{3x}t_4-X_i)^2+(P_{0y}t_1+(P_{0y}+k*vec.y)t_2+P_{2y}t_3+P_{3y}t_4-Y_i)^2} i=1N(P0xt1+(P0x+kvec.x)t2+P2xt3+P3xt4Xi)2+(P0yt1+(P0y+kvec.y)t2+P2yt3+P3yt4Yi)2

对三个未知量求偏导
偏导数分别为:

  • k的偏导数公式为
    ∑ i = 1 N 2 ∗ ( P 0 x t 1 + ( P 0 x + k ∗ v e c . x ) t 2 + P 2 x t 3 + P 3 x t 4 − X i ) ∗ t 2 ∗ v e c . x + 2 ∗ ( P 0 y t 1 + ( P 0 y + k ∗ v e c . y ) t 2 + P 2 y t 3 + P 3 y t 4 − Y i ) ∗ t 2 ∗ v e c . y = 0 \sum_{i=1}^N{2*(P_{0x}t_1+(P_{0x}+k*vec.x)t_2+P_{2x}t_3+P_{3x}t_4-X_i)*t_2*vec.x+2*(P_{0y}t_1+(P_{0y}+k*vec.y)t_2+P_{2y}t_3+P_{3y}t_4-Y_i)*t_2*vec.y}=0 i=1N2(P0xt1+(P0x+kvec.x)t2+P2xt3+P3xt4Xi)t2vec.x+2(P0yt1+(P0y+kvec.y)t2+P2yt3+P3yt4Yi)t2vec.y=0

  • 求P2x的偏导数为0的公式为
    ∑ i = 1 N 2 ∗ ( P 0 x t 1 + ( P 0 x + k ∗ v e c . x ) t 2 + P 2 x t 3 + P 3 x t 4 − X i ) ∗ t 3 = 0 \sum_{i=1}^N{2*(P_{0x}t_1+(P_{0x}+k*vec.x)t_2+P_{2x}t_3+P_{3x}t_4-X_i)*t_3}=0 i=1N2(P0xt1+(P0x+kvec.x)t2+P2xt3+P3xt4Xi)t3=0

  • 求P2y的偏导数为0的公式为
    ∑ i = 1 N 2 ∗ ( P 0 y t 1 + ( P 0 y + k ∗ v e c . y ) t 2 + P 2 y t 3 + P 3 y t 4 − Y i ) ∗ t 3 = 0 \sum_{i=1}^N{2*(P_{0y}t_1+(P_{0y}+k*vec.y)t_2+P_{2y}t_3+P_{3y}t_4-Y_i)*t_3}=0 i=1N2(P0yt1+(P0y+kvec.y)t2+P2yt3+P3yt4Yi)t3=0

上述三个公式整理后得到

∑ i = 1 N ( ( k ∗ v e c . x ) t 2 + P 2 x t 3 ) ∗ t 2 ∗ v e c . x + ( ( k ∗ v e c . y ) t 2 + P 2 y t 3 ) ∗ t 2 ∗ v e c . y = ∑ i = 1 N ( X i − P 0 x t 1 − P 0 x t 2 − P 3 x t 4 ) ∗ t 2 ∗ v e c . x + ( Y i − P 0 y t 1 − P 0 y t 2 − P 3 y t 4 ) ∗ t 2 ∗ v e c . y \sum_{i=1}^N{((k*vec.x)t_2+P_{2x}t_3)*t_2*vec.x+((k*vec.y)t_2+P_{2y}t_3)*t_2*vec.y}= \sum_{i=1}^N{(X_i-P_{0x}t_1-P_{0x}t_2-P_{3x}t_4)*t_2*vec.x+(Y_i-P_{0y}t_1-P_{0y}t_2-P_{3y}t_4)*t_2*vec.y} i=1N((kvec.x)t2+P2xt3)t2vec.x+((kvec.y)t2+P2yt3)t2vec.y=i=1N(XiP0xt1P0xt2P3xt4)t2vec.x+(YiP0yt1P0yt2P3yt4)t2vec.y

∑ i = 1 N ( ( k ∗ v e c . x ) t 2 + P 2 x t 3 ) ∗ t 3 = ∑ i = 1 N ( X i − P 0 x t 1 − P 0 x t 2 − P 3 x t 4 ) ∗ t 3 \sum_{i=1}^N{((k*vec.x)t_2+P_{2x}t_3)*t_3}= \sum_{i=1}^N{(X_i-P_{0x}t_1-P_{0x}t_2-P_{3x}t_4)*t_3} i=1N((kvec.x)t2+P2xt3)t3=i=1N(XiP0xt1P0xt2P3xt4)t3

∑ i = 1 N ( ( k ∗ v e c . y ) t 2 + P 2 y t 3 ) ∗ t 3 = ∑ i = 1 N ( Y i − P 0 y t 1 − P 0 y t 2 − P 3 y t 4 ) ∗ t 3 \sum_{i=1}^N{((k*vec.y)t_2+P_{2y}t_3)*t_3}= \sum_{i=1}^N{(Y_i-P_{0y}t_1-P_{0y}t_2-P_{3y}t_4)*t_3} i=1N((kvec.y)t2+P2yt3)t3=i=1N(YiP0yt1P0yt2P3yt4)t3

继续整理

∑ i = 1 N k ∗ t 2 2 ( v e c . x 2 + v e c . y 2 ) + P 2 x t 3 ∗ t 2 ∗ v e c . x + P 2 y t 3 ∗ t 2 ∗ v e c . y = ∑ i = 1 N ( X i − P 0 x t 1 − P 0 x t 2 − P 3 x t 4 ) ∗ t 2 ∗ v e c . x + ( Y i − P 0 y t 1 − P 0 y t 2 − P 3 y t 4 ) ∗ t 2 ∗ v e c . y \sum_{i=1}^N{k*t_2^2(vec.x^2+vec.y^2)+P_{2x}t_3*t_2*vec.x+P_{2y}t_3*t_2*vec.y}= \sum_{i=1}^N{(X_i-P_{0x}t_1-P_{0x}t_2-P_{3x}t_4)*t_2*vec.x+(Y_i-P_{0y}t_1-P_{0y}t_2-P_{3y}t_4)*t_2*vec.y} i=1Nkt22(vec.x2+vec.y2)+P2xt3t2vec.x+P2yt3t2vec.y=i=1N(XiP0xt1P0xt2P3xt4)t2vec.x+(YiP0yt1P0yt2P3yt4)t2vec.y

∑ i = 1 N k ∗ v e c . x ∗ t 2 ∗ t 3 + P 2 x t 3 2 + P 2 y ∗ 0 = ∑ i = 1 N ( X i − P 0 x t 1 − P 0 x t 2 − P 3 x t 4 ) ∗ t 3 \sum_{i=1}^N{k*vec.x*t_2*t_3+P_{2x}t_3^2+P_{2y}*0}= \sum_{i=1}^N{(X_i-P_{0x}t_1-P_{0x}t_2-P_{3x}t_4)*t_3} i=1Nkvec.xt2t3+P2xt32+P2y0=i=1N(XiP0xt1P0xt2P3xt4)t3

∑ i = 1 N k ∗ v e c . y ∗ t 2 ∗ t 3 + P 2 x ∗ 0 + P 2 y t 3 2 = ∑ i = 1 N ( Y i − P 0 y t 1 − P 0 y t 2 − P 3 y t 4 ) ∗ t 3 \sum_{i=1}^N{k*vec.y*t_2*t_3+P_{2x}*0+P_{2y}t_3^2}= \sum_{i=1}^N{(Y_i-P_{0y}t_1-P_{0y}t_2-P_{3y}t_4)*t_3} i=1Nkvec.yt2t3+P2x0+P2yt32=i=1N(YiP0yt1P0yt2P3yt4)t3

同上可以得出一个矩阵

[ ∑ i = 1 N t 2 2 ( v e c . x 2 + v e c . y 2 ) ∑ i = 1 N t 3 ∗ t 2 ∗ v e c . x ∑ i = 1 N t 3 ∗ t 2 ∗ v e c . y ∑ i = 1 N v e c . x ∗ t 2 ∗ t 3 ∑ i = 1 N t 3 2 0 ∑ i = 1 N v e c . y ∗ t 2 ∗ t 3 0 ∑ i = 1 N t 3 2 ] [ k P 2 x P 2 y ] = [ ∑ i = 1 N ( X i − P 0 x t 1 − P 0 x t 2 − P 3 x t 4 ) ∗ t 2 ∗ v e c . x + ( Y i − P 0 y t 1 − P 0 y t 2 − P 3 y t 4 ) ∗ t 2 ∗ v e c . y ∑ i = 1 N ( X i − P 0 x t 1 − P 0 x t 2 − P 3 x t 4 ) ∗ t 3 ∑ i = 1 N ( Y i − P 0 y t 1 − P 0 y t 2 − P 3 y t 4 ) ∗ t 3 ] \begin{bmatrix} \sum_{i=1}^N{t_2^2(vec.x^2+vec.y^2)} & \sum_{i=1}^N{t_3*t_2*vec.x} &\sum_{i=1}^N{t_3*t_2*vec.y} \\\\ \sum_{i=1}^N{vec.x*t_2*t_3} & \sum_{i=1}^N{t_3^2} & 0 \\\\ \sum_{i=1}^N{vec.y*t_2*t_3} & 0 & \sum_{i=1}^N{t_3^2} \end{bmatrix} \begin{bmatrix} k\\\\ P_{2x}\\\\ P_{2y} \end{bmatrix} =\begin{bmatrix} \sum_{i=1}^N{(X_i-P_{0x}t_1-P_{0x}t_2-P_{3x}t_4)*t_2*vec.x+(Y_i-P_{0y}t_1-P_{0y}t_2-P_{3y}t_4)*t_2*vec.y}\\\\ \sum_{i=1}^N{(X_i-P_{0x}t_1-P_{0x}t_2-P_{3x}t_4)*t_3}\\\\ \sum_{i=1}^N{(Y_i-P_{0y}t_1-P_{0y}t_2-P_{3y}t_4)*t_3} \end{bmatrix} i=1Nt22(vec.x2+vec.y2)i=1Nvec.xt2t3i=1Nvec.yt2t3i=1Nt3t2vec.xi=1Nt320i=1Nt3t2vec.y0i=1Nt32kP2xP2y=i=1N(XiP0xt1P0xt2P3xt4)t2vec.x+(YiP0yt1P0yt2P3yt4)t2vec.yi=1N(XiP0xt1P0xt2P3xt4)t3i=1N(YiP0yt1P0yt2P3yt4)t3

同上一种拟合,利用opencv里的矩阵估计函数进行计算

两端切向都约束

两端切向都约束的情况下,就变成了两个变量需要确定,即k1和k2;
读者可以试试自行推导。

本文纯属个人见解,欢迎指正错误。

转载请标明出处!

### 贝塞尔曲线最小二乘法拟合 对于给定的一系列离散点,利用贝塞尔曲线进行拟合可以通过定义适当的控制点来实现平滑过渡。然而,在实际应用中直接由一系列点反向计算出合适的贝塞尔曲线控制点并非易事[^2]。 当涉及到通过最小二乘法对这些点进行贝塞尔曲线拟合时,主要思在于构建一个优化问题框架,其中目标是最小化所选数据点到理论贝塞尔曲线上对应位置的距离平方和。具体来说: - **建立模型**:假设已知一组二维平面内的点集 \((x_i, y_i)\),目的是找到能够最好描述这组点分布规律的贝塞尔曲线方程。 - **参数估计**:采用数值方法调整贝塞尔曲线的各个控制顶点的位置,直到满足一定的误差标准为止。此过程通常涉及迭代运算,不断更新控制点直至达到最优解。 #### Python 实现示例 下面给出一段基于Python语言编写的代码片段用于展示如何运用scipy库中的optimize模块完成上述任务: ```python import numpy as np from scipy.optimize import least_squares from matplotlib.path import Path import matplotlib.pyplot as plt def bezier_curve(control_points, t): """ 计算t时刻下二次贝塞尔曲线上的坐标 """ n = len(control_points)-1 p0, p1, p2 = control_points[:n+1] B = (1-t)**2*p0 + 2*(1-t)*t*p1 + t**2*p2 return B def residuals(params, points): """ 定义残差函数 """ P0, P1, P2 = params.reshape((-1, 2)) errors = [] for point in points: def distance(t): curve_point = bezier_curve([P0, P1, P2], t) dist = ((curve_point[0]-point[0])**2+(curve_point[1]-point[1])**2)**0.5 return dist min_dist = min(distance(ti) for ti in np.linspace(0., 1., num=100)) errors.append(min_dist) return np.array(errors) if __name__ == '__main__': # 假设有一串随机生成的数据点作为输入 data_x = [-0.789, -0.643, -0.376, 0.000, 0.376, 0.643, 0.789] data_y = [0.789, 0.643, 0.376, 0.000, -0.376, -0.643, -0.789] initial_guess = [[data_x[0], data_y[0]], [(max(data_x)+min(data_x))/2, max(data_y)], [data_x[-1], data_y[-1]]].flatten() result = least_squares(residuals, initial_guess, args=(list(zip(data_x,data_y)), )) fitted_control_points = result.x.reshape(-1, 2) fig, ax = plt.subplots() path_data = [ (Path.MOVETO, tuple(fitted_control_points[0])), (Path.CURVE3, tuple(fitted_control_points[1])), (Path.CURVE3, tuple(fitted_control_points[2])) ] codes, verts = zip(*path_data) path = Path(verts, codes) patch = patches.PathPatch(path, facecolor='none', lw=2) ax.add_patch(patch) xs, ys = zip(*path.vertices) ax.plot(xs, ys, 'r-', lw=2, label='Fitted Bezier Curve') ax.scatter(data_x, data_y, color="blue", marker="o", s=50, zorder=3, label='Data Points') plt.legend(loc='best') plt.show() ``` 这段程序展示了怎样使用`least_squares()`函数去寻找最接近于给定点集合的最佳匹配贝塞尔曲线,并绘制结果图形以便直观理解效果。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猿声载道

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值