N 階貝塞爾曲線生成


博客轉自:https://blog.csdn.net/aimeimeits/article/details/72809382

首先貝塞爾曲線簡介,了解了基本的貝塞爾曲線知識之后,展開N階貝塞爾曲線的生成方式。

N階貝塞爾曲線的公式

百度百科上給出的一般參數公式是這樣的:給定點 P0,P1,P2, … ,Pn,其貝塞爾曲線公式如下(即貝塞爾曲線上的點 B(t) 可由如下公式計算得到)

可以看出其公式是由一個格式固定的表達式之和來表示,這個表達式就是關鍵:

 該表達式可分為四個部分看:

  • 從 i 遞增到 n 的常數部分
  • Pi 坐標部分
  • (1 - t)^(n - i)
  • t^i

 可以看出這四部分都與 i 的值相關,此外 t 值的計算方式為:i/(n+1)

可以從具體的例子中找到抽象規律

設 Bt 為要計算的貝塞爾曲線上的坐標,N 為控制點個數,P0,P1,P2..Pn 為貝塞爾曲線控制點的坐標,當 N 值不同時有如下計算公式: 如 N 為 3 表示貝塞爾曲線的控制點有 3 個點,這時 n 為 2 ,這三個點分別用 P0,P1,P2 表示。

  • N = 3: P = (1-t)^2*P0 + 2*(1-t)*t*P1 + t^2*P2
  • N = 4: P = (1-t)^3*P0 + 3*(1-t)^2*t*P1 + 3(1-t)*t^2*P2 + t^3*P3
  • N = 5: P = (1-t)^4*P0 + 4*(1-t)^3*t*P1 + 6(1-t)^2*t^2*P2 + 4*(1-t)*t^3*P3 + t^4*P4

將貝塞爾曲線一般參數公式中的表達式用如下方式表示:設有常數 a,b 和 c,則該表達式可統一表示為如下形式

a * (1 - t)^b * t^c * Pn

分析當 N 分別為3,4,5 時對應 a,b,c 的值:如 N = 3 時,公式有三個表達式,第一個表達式為 (1-t)^2*P0,其對應 a,b,c 值分別為:1,2,0

N = 3:   1,2,0   2,1,1   1,0,2
a: 1 2 1
b: 2 1 0
c: 0 1 2
N = 4:   1,3,0   3,2,1   3,1,2   1,0,3
a: 1 3 3 1
b: 3 2 1 0
c: 0 1 2 3
N = 5:   1,4,0   4,3,1   6,2,2   4,1,3   1,0,4
a: 1 4 6 4 1
b: 4 3 2 1 0
c: 0 1 2 3 4

根據上面的分析就可以總結出 a,b,c 對應的取值規則:

  • b: (N - 1) 遞減到 0 (b 為 1-t 的冪)
  • c: 0 遞增到 (N - 1) (c 為 t 的冪)
  • a: 在 N 分別為 1,2,3,4,5 時將其值用如下形式表示:

N=1:———1
N=2:——–1  1
N=3:——1  2  1
N=4:—–1  3  3  1
N=5:—1  4  6  4  1
a 值的改變規則為: 楊輝三角

C++實現代碼

void n_bezier(int resolution)
{
    int number = waypoints.size();
    if (number < 2)
    {
        return;
    }
    int dimension = waypoints[0].size();
    if (dimension < 2)
    {
        return;
    }

    std::vector<std::vector<double>> n_bezier_tmp_pts;

    //計算楊輝三角
    std::vector<int> a_para; a_para.resize(number);
    a_para[0] = a_para[1] = 1;

    for (int i = 3; i <= number; i++)
    {
        std::vector<int> tmp;
        tmp.resize(i - 1);
        for (int j = 0; j < tmp.size(); j++)
        {
            tmp[j] = a_para[j];
        }

        a_para[0] = a_para[i - 1] = 1;
        for (int j = 0; j < i - 2; j++)
        {
            a_para[j + 1] = tmp[j] + tmp[j + 1];
        }
    }

    n_bezier_tmp_pts.resize(resolution);
    cv::Mat img_out; img.copyTo(img_out);

    //計算坐標點
    for (int i = 0; i < resolution; i++)
    {
        float t = (float)i / resolution;

        n_bezier_tmp_pts[i].resize(dimension);
        for (int j = 0; j < dimension; j++)
        {
            float temp = 0.0f;
            for (int k = 0; k < number; k++)
            {
                temp += std::pow(1 - t, number - k - 1) * waypoints[k][j] * std::pow(t, k) * a_para[k];
            }

            n_bezier_tmp_pts[i][j] = temp;
        }

        cv::circle(img_out, cv::Point2d(n_bezier_tmp_pts[i][0], n_bezier_tmp_pts[i][1]), 2, cv::Scalar(255, 0, 255), -1);
    }
    
    cv::imshow("spline", img_out);
}

顯示效果如下

等有時間,整理完備,會更新到Githu


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM