使用B样条曲线拼接两段曲线

本文主要用于博主的备忘录。

1.原理

三次样条曲线公式:

2.代码实现

/* B样条曲线拟合 */
vector<Point2f> BSplineFit(const vector<Point2f>& controlPnts, double stride = 0.1) {
	vector<Point2f> Outputs;
	for (int i = 0; i < controlPnts.size() - 3; i++) {
		Point2f cof[4];
	    cof[0] = (controlPnts[i] + 4 * controlPnts[(i + 1) % controlPnts.size()] + controlPnts[(i + 2) % controlPnts.size()]) / 6;
	    cof[1] = -(controlPnts[i] - controlPnts[(i + 2) % controlPnts.size()]) / 2;
	    cof[2] = (controlPnts[i] - 2 * controlPnts[(i + 1) % controlPnts.size()] + controlPnts[(i + 2) % controlPnts.size()]) / 2;
	    cof[3] = -(controlPnts[i] - 3 * controlPnts[(i + 1) % controlPnts.size()] + 3 * controlPnts[(i + 2) % controlPnts.size()] - controlPnts[(i + 3) % controlPnts.size()]) / 6;
		for (double t = 0; t <= 1; t += stride) {
			Point2f fittingPoints = Point2f(0, 0);
			for (int j = 0; j < 4; j++) {
				fittingPoints += cof[j] * pow(t, j);
			}
			Outputs.push_back(fittingPoints);
		}
	}
	return Outputs;
}

3.测试

已知两段曲线上的点集,使用三次B样条曲线将其平滑连接。

#include <iostream>
#include <vector>
#include <opencv2\opencv.hpp>
#include <opencv2\opencv_modules.hpp>

using namespace cv;
using namespace std;

int main()
{
	// 曲线点集1
	vector<Point2f> pointpair1 = { Point2f(300, 450), Point2f(300, 440), Point2f(300, 430), Point2f(300, 420), Point2f(300, 410), Point2f(300, 400) };
	// 曲线点集2
	vector<Point2f> pointpair2 = { Point2f(600, 200), Point2f(610, 200), Point2f(620, 200), Point2f(630, 200), Point2f(640, 200), Point2f(650, 200) };
	// 控制点点集
    vector<Point2f> controlPoints = { Point2f(300, 500), Point2f(300, 400), Point2f(300, 300), Point2f(450, 200), Point2f(600, 200), Point2f(750, 200) };

    vector<Point2f> output = BSplineFit(controlPoints);
	// 为连接两曲线的端点,两端点也应为控制点,且位于输出曲线中
	output.push_back(controlPoints[4]);

	Mat img = Mat(800, 800, CV_32FC3, Scalar(0, 0, 0));

	// 曲线点集1,白点
	for (int i = 0; i < pointpair1.size(); i++) {
		circle(img, pointpair1[i], 3, Scalar(255, 255, 255), -1);
	}
	// 曲线点集2,白点
	for (int i = 0; i < pointpair2.size(); i++) {
		circle(img, pointpair2[i], 3, Scalar(255, 255, 255), -1);
	}
	// 样条曲线拟合线,红线
	for (int j = 0; j < output.size() - 1; j++) { 
		line(img, output[j], output[j + 1], Scalar(0, 0, 255), 1);
	}
	// 控制点,绿点
	for (int i = 0; i < controlPoints.size(); i++) {
		circle(img, controlPoints[i], 3, Scalar(0, 255, 0), -1);
	}
	
	imshow("PointsinImage", img);
	waitKey(0);

	return 0;
}

4.运行结果

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值