【C++】【Eigen】EigenでBスプライン補間を行う

2024-04-16C++,Eigen

はじめに

Eigenには、unsupportedながらBスプライン補間を行うライブラリが用意されています。今回、これを使用してBスプライン補間を行うプログラムを作成してみます。

Eigen::Splineクラス

Bスプライン補間を行うには、Eigen::Spline<>クラスのオブジェクトを作成する必要があります。基本的な使い方はオブジェクトを作成し、値を得るときにEigen::Spline<>::operator()を呼び出すだけです。

ノットベクトルと制御点がわかっている場合と、補間したい点だけが得られている場合で、初期化のやり方が変わってきます。

ノットベクトルと制御点がわかっている場合

Eigen::Spline<>クラスのコンストラクタでノットベクトルと制御点を設定します。

#include <iostream>
#include <Eigen/Eigen>
#include <unsupported/Eigen/Spline>

int main()
{
    Eigen::VectorXd knots(11);
    Eigen::MatrixXd ctrls(2, 7);

    knots << 0, 0, 0, 0, 0.25, 0.5, 0.75, 1, 1, 1, 1;
    ctrls << 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0,
             0.0, 2.0, 1.5, 3.0, 2.0, 3.0, 4.5;

    Eigen::Spline<double, 2, Eigen::Dynamic> spline(knots, ctrls);

    for(int i = 0; i <= 100; i++){
        auto y = spline(i / 100.0);
        std::cout << y(0) << '\t' << y(1) << std::endl;
    }

    return 0;
}

テンプレート引数の2は2D(平面)であることを示します。Eigen::Dynamicは補間する次数をノットベクトルで指定することを示します(今回は3次です)。

また、Eigen::Spline<>::operator()の引数uは$0 \leqq u \leqq 1$であることに注意します。$x$座標から補間する場合は、適切な変換が必要です。戻り値はArrayで、インデックス0が$x$座標、インデックス1が$y$座標となります。

補間したい点だけが得られている場合

補間するための関数を呼び出す必要があります。これには、Eigen::SplineFitting<>::Interpolate()という関数を使用します。

#include <iostream>
#include <Eigen/Eigen>
#include <unsupported/Eigen/Spline>

int main()
{
    Eigen::Spline<double, 2, Eigen::Dynamic> spline;
    Eigen::MatrixXd points;

    points << 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0,
             0.0, 2.0, 1.5, 3.0, 2.0, 3.0, 4.5;

    spline = Eigen::SplineFitting< Eigen::Spline<double, 2, Eigen::Dynamic> >::Interpolate(points, 3);

    for(int i = 0; i <= 100; i++){
        auto y = spline(i / 100.0);
        std::cout << y(0) << '\t' << y(1) << std::endl;
    }

    return 0;
}

Interpolate()メソッドの3は補間する次数を示します(今回は3次)。Bスプラインはノットベクトルによって、補間曲線の形が変わるため、Interpolate()メソッドでは、ノットベクトルを指定することもできます。その場合は、以下のようにします。

// knotsはノットベクトル(Eigen::VectorXd)とする
spline = Eigen::SplineFitting< Eigen::Spline<double, 2, Eigen::Dynamic> >::Interpolate(points, 3, knots);

ノットベクトルと制御点はEigen::Spline<>::knots()Eigen::Spline<>::ctrls()を使用することで得られます。

std::cout << "knots" << std::endl << spline.knots() << std::endl;
std::cout << "control points" << std::endl << spline.ctrls() << std::endl;

出力結果

knots
       0        0        0        0 0.365991  0.51362 0.671336        1        1        1        1
control points
-2.52966e-17    -0.460933      2.08686      2.83392      4.45454      5.53068            6
-2.63835e-17      4.66037    -0.659575      3.98773     0.175466      4.82719          4.5

まとめ

EigenでBスプライン補間を使う方法をまとめます。

  1. ノットベクトルと制御点がわかっている場合は、Eigen::Spline<>のコンストラクタで指定する。
  2. 補間したい点が与えられた場合は、Eigen::SplineFitting<>::Interpolate()を使う。
  3. 補間する場合は、Eigen::Spline<>::operator()を使う。戻り値は$(x, y)$。引数uは$0 \leqq u \leqq 1$を取る。
  4. ノットベクトルを得る場合は、Eigen::Spline<>::knots()を使う。
  5. 制御点を得る場合は、Eigen::Spline<>::ctrls()を使う。

C++,Eigen

Posted by izadori