离散点拟合贝塞尔曲线(MATLAB实现)

MATLAB实现,用于离散点拟合贝塞尔曲线,支持任意阶数,计算控制点并评估拟合误差:

classdef BezierCurveFitter
    properties
        controlPoints % 控制点坐标 [x, y]
        order         % 贝塞尔曲线阶数
        error         % 拟合误差
        points        % 原始离散点 [x, y]
    end
    
    methods
        % 构造函数
        function obj = BezierCurveFitter(points, order)
            obj.points = points;
            obj.order = order;
            obj = obj.fitCurve();
        end
        
        % 拟合贝塞尔曲线
        function obj = fitCurve(obj)
            % 获取点数和维度
            [n, dim] = size(obj.points);
            
            % 检查阶数是否有效
            if obj.order >= n
                error('阶数必须小于点数');
            end
            
            % 固定首尾点
            start_point = obj.points(1, :);
            end_point = obj.points(end, :);
            
            % 创建线性方程组 A*x = b
            A = zeros(n-2, obj.order-1);
            b = zeros(n-2, dim);
            
            % 计算伯恩斯坦基函数
            for i = 1:n-2
                t = i/(n-1);  % 参数化
                
                % 计算伯恩斯坦基函数值
                for j = 1:obj.order-1
                    binom = nchoosek(obj.order-1, j-1);
                    bernstein = binom * t^(j-1) * (1-t)^(obj.order-j-1);
                    A(i, j) = bernstein;
                end
                
                % 计算目标值
                b(i, :) = obj.points(i+1, :) - ...
                          start_point * bernstein(1) - ...
                          end_point * bernstein(end);
            end
            
            % 求解线性方程组
            x = zeros(obj.order-1, dim);
            for d = 1:dim
                x(:, d) = A \ b(:, d);
            end
            
            % 组合控制点
            obj.controlPoints = [start_point; x; end_point];
            
            % 计算拟合误差
            obj = obj.calculateError();
        end
        
        % 计算拟合误差
        function obj = calculateError(obj)
            % 生成曲线上的点
            t = linspace(0, 1, 100)';
            curve_points = obj.evaluateBezier(t);
            
            % 计算点到曲线的距离
            distances = zeros(size(obj.points, 1), 1);
            for i = 1:size(obj.points, 1)
                % 计算点到曲线上最近点的距离
                diff = curve_points - obj.points(i, :);
                distances(i) = min(sqrt(sum(diff.^2, 2)));
            end
            
            % 计算均方根误差
            obj.error = sqrt(mean(distances.^2));
        end
        
        % 计算贝塞尔曲线上的点
        function points = evaluateBezier(obj, t)
            n = obj.order - 1;
            num_points = length(t);
            dim = size(obj.controlPoints, 2);
            points = zeros(num_points, dim);
            
            % 计算伯恩斯坦基函数
            for k = 0:n
                binom = nchoosek(n, k);
                bernstein = binom * t.^k .* (1-t).^(n-k);
                
                % 累加控制点贡献
                for d = 1:dim
                    points(:, d) = points(:, d) + obj.controlPoints(k+1, d) * bernstein;
                end
            end
        end
        
        % 绘制结果
        function plotResult(obj)
            figure;
            hold on;
            
            % 绘制原始点
            scatter(obj.points(:, 1), obj.points(:, 2), 70, 'filled', 'MarkerFaceColor', [0.8 0.2 0.2]);
            
            % 绘制拟合曲线
            t = linspace(0, 1, 200)';
            curve_points = obj.evaluateBezier(t);
            plot(curve_points(:, 1), curve_points(:, 2), 'b-', 'LineWidth', 2);
            
            % 绘制控制点
            plot(obj.controlPoints(:, 1), obj.controlPoints(:, 2), 'go-', 'LineWidth', 1.5, 'MarkerFaceColor', 'g');
            
            % 绘制控制多边形
            plot(obj.controlPoints(:, 1), obj.controlPoints(:, 2), 'g--', 'LineWidth', 1);
            
            title(sprintf('贝塞尔曲线拟合 (阶数 = %d, 误差 = %.4f)', obj.order, obj.error));
            xlabel('X');
            ylabel('Y');
            legend('原始点', '拟合曲线', '控制点', 'Location', 'best');
            grid on;
            axis equal;
            hold off;
        end
    end
end

使用

% 生成测试数据(圆形近似)
theta = linspace(0, 2*pi, 20)';
x = 2 * cos(theta) + 0.1 * randn(size(theta));
y = 2 * sin(theta) + 0.1 * randn(size(theta));
points = [x, y];

% 尝试不同阶数的拟合
orders = [3, 5, 8];
figure;
sgtitle('不同阶数贝塞尔曲线拟合比较');

for i = 1:length(orders)
    % 创建拟合器并拟合曲线
    fitter = BezierCurveFitter(points, orders(i));
    
    % 绘制结果
    subplot(2, 2, i);
    fitter.plotResult();
    
    % 显示控制点信息
    fprintf('阶数 %d:\n', orders(i));
    fprintf('  控制点数量: %d\n', size(fitter.controlPoints, 1));
    fprintf('  拟合误差: %.6f\n\n', fitter.error);
end

% 高阶拟合示例
figure;
high_order_fitter = BezierCurveFitter(points, 10);
high_order_fitter.plotResult();
fprintf('高阶拟合 (阶数=10):\n');
fprintf('  控制点数量: %d\n', size(high_order_fitter.controlPoints, 1));
fprintf('  拟合误差: %.6f\n', high_order_fitter.error);

功能说明

  1. 贝塞尔曲线拟合: 支持任意阶数的贝塞尔曲线拟合 自动固定首尾控制点为数据集的首尾点 使用最小二乘法求解中间控制点
  2. 控制点计算: 基于伯恩斯坦基函数构建线性方程组 求解中间控制点坐标 返回所有控制点坐标
  3. 误差评估: 计算原始点到拟合曲线的最小距离 返回均方根误差(RMSE)作为拟合质量指标
  4. 可视化: 绘制原始离散点 绘制拟合的贝塞尔曲线 标记控制点和控制多边形

算法原理

  1. 贝塞尔曲线定义

    其中 \(P_i\)是控制点,\(n\)是阶数

  2. 最小二乘拟合

    • 固定首尾控制点 \(P_0\)\(P_n\)
    • 对于中间点 \(P_1\)\(P_{n−1}\),求解:

    其中 \(Q_j\)是原始数据点

  3. 伯恩斯坦基函数

应用场景

  1. 计算机图形学:平滑路径生成
  2. 计算机辅助设计(CAD):曲线建模
  3. 数据可视化:平滑散点图
  4. 机器人路径规划:生成平滑轨迹
  5. 字体设计:轮廓曲线拟合

参考代码 离散点拟合贝塞尔曲线 www.youwenfan.com/contentcsk/78514.html

性能优化

  1. 大规模数据处理

    % 使用并行计算求解方程组
    parfor i = 1:size(A, 1)
        x(:, i) = A(i,:) \ b(i,:);
    end
    
  2. 高阶曲线优化

    % 使用重心坐标算法加速计算
    function points = evaluateBezierFast(obj, t)
        n = obj.order - 1;
        points = zeros(size(t, 1), size(obj.controlPoints, 2));
    
        for i = 1:size(t, 1)
            % 使用重心坐标算法
            coeffs = obj.computeBernsteinCoefficients(t(i));
            points(i, :) = coeffs * obj.controlPoints;
        end
    end
    
  3. 参数化优化

    % 使用弦长参数化代替均匀参数化
    distances = sqrt(sum(diff(points).^2, 2));
    t = [0; cumsum(distances) / sum(distances)];
    

该实现提供了完整的贝塞尔曲线拟合解决方案,包括控制点计算和误差评估,可直接应用于各种曲线拟合场景。

posted @ 2025-11-03 11:38  别说我的眼泪有点咸  阅读(14)  评论(0)    收藏  举报