三次B样条曲线拟合C++

本文介绍了如何使用C++实现三次B样条曲线拟合,通过基函数公式推导出权重系数,并展示了非闭合和闭合曲线的拟合效果。

B样条曲线的方程:P=∑i=0nPiFi,k(t)\sum_{i=0}^nP_iF_{i,k}(t)i=0nPiFi,k(t)
其中Fi,k(t)F_{i,k}(t)Fi,k(t)为基函数,三次B样条的基函数为:
F0,3(t)=16(1−t)3F_{0,3}(t)=\displaystyle{\frac{1}{6}{(1-t)}^3}F0,3(t)=61(1t)3

F1,3(t)=16(3t3−6t2+4)F_{1,3}(t)=\displaystyle{\frac{1}{6}(3t^3-6t^2+4)}F1,3(t)=61(3t36t2+4)

F2,3(t)=16(−3t3+3t2+3t+1)F_{2,3}(t)=\displaystyle{\frac{1}{6}(-3t^3+3t^2+3t+1)}F2,3(t)=61(3t3+3t2+3t+1)

F3,3(t)=16t3F_{3,3}(t)=\displaystyle{\frac{1}{6}t^3}F3,3(t)=61t3

所以,三次B样条的方程式为:
P=P0F0,3(t)+P1F1,3(t)+P2F2,3(t)+P3F3,3(t)P=P_0F_{0,3}(t)+P_1F_{1,3}(t)+P_2F_{2,3}(t)+P_3F_{3,3}(t)P=P0F0,3(t)+P1F1,3(t)+P2F2,3(t)+P3F3,3(t)
把基函数代入可以简化为:
P=w0+w1t+w2t2+w3t3P=w_0+w_1t+w_2t^2+w_3t^3P=w0+w1t+w2t2+w3t3 (0≤t<≤1)
其中,w0=16(P0+4P1+P2)w_0=\displaystyle{\frac{1}{6}(P_0+4P_1+P_2)}w0=61(P0+4P1+P2)

w1=−12(P0−P2)w_1=\displaystyle{-\frac{1}{2}(P_0-P_2)}w1=21(P0P2)

w2=12(P0−2P1+P2)w_2=\displaystyle{\frac{1}{2}(P_0-2P_1+P_2)}w2=21(P02P1+P2)

w3=−16(P0−3P1+3P2−P3)w_3=\displaystyle{-\frac{1}{6}(P_0-3P_1+3P_2-P_3)}w3=61(P03P1+3P2P3)

因此,每四个离散点就可拟合一段曲线,比如P0,P1,P2,P3P_0,P_1,P_2,P_3P0,P1,P2,P3可以拟合一段光滑曲线,P1,P2,P3,P4P_1,P_2,P_3,P_4P1,P2,P3,P4可以拟合下一段,相邻两段曲线是平滑过渡的,以此类推N个点可以拟合出N-3段平滑相接的曲线。
在这里插入图片描述以上是非闭合曲线的拟合,闭合曲线只需离散点集首尾相连,也就是说,还需用PN−1,P0,P1,P2P_{N-1},P_0,P_1,P_2PN1,P0,P1,P2拟合一段曲线。
c++代码如下:

/*B样条曲线拟合
@return 返回拟合得到的曲线
@discretePoints 输入的离散点,至少4个点
@closed 是否拟合闭合曲线,true表示闭合,false不闭合
@stride 拟合精度
*/
vector<Point2f> BSplineFit(vector<Point2f> discretePoints, bool closed, double stride = 0.01) {
	vector<Point2f> fittingPoints;
	for (int i = 0; i < (closed ? discretePoints.size() : discretePoints.size() - 1); i++) {
		Point2f xy[4];
		xy[0] = (discretePoints[i] + 4 * discretePoints[(i + 1) % discretePoints.size()] + discretePoints[(i + 2) % discretePoints.size()]) / 6;
		xy[1] = -(discretePoints[i] - discretePoints[(i + 2) % discretePoints.size()]) / 2;
		xy[2] = (discretePoints[i] - 2 * discretePoints[(i + 1) % discretePoints.size()] + discretePoints[(i + 2) % discretePoints.size()]) / 2;
		xy[3] = -(discretePoints[i] - 3 * discretePoints[(i + 1) % discretePoints.size()] + 3 * discretePoints[(i + 2) % discretePoints.size()] - discretePoints[(i + 3) % discretePoints.size()]) / 6;
		for (double t = 0; t <= 1; t += stride) {
			Point2f totalPoints = Point2f(0, 0);
			for (int j = 0; j < 4; j++) {
				totalPoints += xy[j] * pow(t, j);
			}
			fittingPoints.push_back(totalPoints);
		}
	}
	return fittingPoints;
}

非闭合拟合效果:

在这里插入图片描述
闭合曲线拟合效果:
在这里插入图片描述
在这里插入图片描述

评论 12
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值