几何尺寸与公差论坛

 找回密码
 注册
查看: 1017|回复: 11

用c++编写拟合样条曲线?

[复制链接]
发表于 2023-2-19 19:14:12 | 显示全部楼层 |阅读模式
用c++编写拟合样条曲线?
 楼主| 发表于 2023-2-19 19:14:50 | 显示全部楼层
#include <iostream>
#include <vector>
#include <boost/interpolate/interpolate.hpp>

int main() {
    // 生成一组样本数据
    std::vector<double> x = {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5};
    std::vector<double> y;
    for (auto xi : x) {
        y.push_back(sin(xi) + ((double)rand() / RAND_MAX - 0.5) * 0.2);
    }

    // 用样条曲线拟合数据
    boost::interpolators::cubic_b_spline<double> spl;
    spl.set_points(x, y);

    // 在原始数据范围内生成更密集的点
    std::vector<double> x2;
    for (double xi = -5; xi <= 5; xi += 0.1) {
        x2.push_back(xi);
    }
    std::vector<double> y2 = spl(x2);

    // 绘制拟合结果
    for (int i = 0; i < x.size(); ++i) {
        std::cout << x[i] << ", " << y[i] << std::endl;
    }
    for (int i = 0; i < x2.size(); ++i) {
        std::cout << x2[i] << ", " << y2[i] << std::endl;
    }
    return 0;
}
这段代码使用了 STL 的 vector 类型存储数据,使用 rand() 函数生成噪声数据,然后使用 boost::interpolators::cubic_b_spline 类对数据进行样条曲线拟合。最后,生成更密集的点,并输出拟合结果。需要注意的是,这段代码使用了 C++11 标准,编译时需要添加 -std=c++11 参数。
 楼主| 发表于 2023-2-19 19:15:18 | 显示全部楼层
如果是三维点呢?
 楼主| 发表于 2023-2-19 19:15:35 | 显示全部楼层
#include <iostream>
#include <vector>
#include <Eigen/Dense>
#include <unsupported/Eigen/Splines>

using namespace std;
using namespace Eigen;

int main()
{
    // 构造输入点
    vector<Vector3d> points;
    points.push_back(Vector3d(0.0, 0.0, 0.0));
    points.push_back(Vector3d(1.0, 0.0, 0.0));
    points.push_back(Vector3d(1.0, 1.0, 0.0));
    points.push_back(Vector3d(0.0, 1.0, 0.0));
    points.push_back(Vector3d(0.0, 0.0, 1.0));
    points.push_back(Vector3d(1.0, 0.0, 1.0));
    points.push_back(Vector3d(1.0, 1.0, 1.0));
    points.push_back(Vector3d(0.0, 1.0, 1.0));

    // 构造样条曲线
    int degree = 3;
    int dim = 3;
    int num_points = points.size();
    int num_segments = num_points - degree - 1;
    VectorXd knots(num_points + degree + 1);
    for (int i = 0; i < num_points + degree + 1; i++) {
        knots(i) = i;
    }
    MatrixXd points_mat(num_points, dim);
    for (int i = 0; i < num_points; i++) {
        points_mat.row(i) = points[i];
    }
    Spline<Vector3d, degree> spline = SplineFitting<Spline<Vector3d, degree> >::Interpolate(points, degree, knots);

    // 输出样条曲线控制点和节点
    cout << "Control points: " << endl << spline.control_points() << endl;
    cout << "Knots: " << endl << spline.knots() << endl;

    return 0;
}
此示例代码构造了一个包含八个三维点的点集,并通过 Eigen 的 SplineFitting 模块拟合了一个三次样条曲线。在构造样条曲线时,先构造了样条曲线的节点向量,并将点集转换为矩阵形式,然后通过 SplineFitting 模块的 Interpolate 方法拟合样条曲线。最后输出了样条曲线的控制点和节点向量。您可以根据需要进行修改和扩展。
 楼主| 发表于 2023-2-19 19:17:31 | 显示全部楼层
用boost编写和Eigen编写拟合三维点的样条曲线,哪个运算速度更快?
 楼主| 发表于 2023-2-19 19:17:43 | 显示全部楼层
无法直接回答哪个库的运算速度更快,因为这取决于许多因素,如数据集大小,硬件和软件配置,算法参数等。但是,可以就两个库的特点进行比较。

Boost库提供了一个名为Boost.Math的库,其中包括用于多项式,有理函数和B样条的工具。Boost.Math中的B样条工具仅支持一维B样条,因此在进行三维B样条拟合时,您需要实现自己的多元B样条插值。

Eigen库提供了一个名为Spline的子模块,可以用于拟合一维和多维B样条曲线。它可以自动计算B样条系数,并提供不同阶数的B样条曲线。因此,Eigen可能更适合拟合三维点的B样条曲线。

总的来说,Eigen库可能更适合拟合三维点的B样条曲线,因为它提供了更完整的工具集和更好的支持。但是,具体情况可能会有所不同,具体取决于您的需求和具体情况。
 楼主| 发表于 2023-2-19 19:21:20 | 显示全部楼层
用eigen拟合1万个点大致需要多长时间?
 楼主| 发表于 2023-2-19 19:21:43 | 显示全部楼层
拟合1万个点所需的时间取决于许多因素,如计算机的硬件配置、算法的参数设置、数据集的特征等等。因此,很难给出一个准确的时间估计。

但是,Eigen是一个非常高效的线性代数库,因此它通常能够快速处理大型数据集。如果您的数据集是稠密的(即大部分元素都是非零的),并且您正确地配置了Eigen的参数,那么它应该能够在几秒钟或更短的时间内完成1万个点的拟合。

然而,如果您的数据集是稀疏的(即大部分元素都是零的),或者您的算法需要更复杂的计算,那么处理时间可能会更长。此外,如果您的计算机配置较低,如CPU、内存、硬盘等,也可能会导致运行时间变长。

因此,为了获得更准确的时间估计,最好在您的计算机上运行一个简单的测试程序,以便在实际情况下确定所需的时间。
 楼主| 发表于 2023-2-19 19:21:54 | 显示全部楼层
继续,普通计算机大致需要多少秒?
 楼主| 发表于 2023-2-19 19:22:04 | 显示全部楼层
由于计算机的硬件配置和运行环境等因素不同,因此很难给出一个准确的时间估计。拟合1万个点的运行时间可能在数百毫秒至数秒之间,具体取决于计算机的硬件配置、算法的参数设置以及数据集的特征。

通常情况下,如果您的计算机有一个高性能的CPU、充足的内存和一个快速的硬盘(如SSD),则运行时间应该相对较短。另外,如果您正确地配置了Eigen库的参数,例如使用OpenMP进行并行计算,那么也可以加速运行时间。

总之,很难给出一个确切的时间估计,因为它取决于太多因素。最好在您的计算机上运行一个简单的测试程序,以便在实际情况下确定所需的时间。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|Archiver|小黑屋|几何尺寸与公差论坛

GMT+8, 2024-3-29 16:01 , Processed in 0.042830 second(s), 21 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表