三次Beizer曲線擬合演算法

1 三次Beizer曲線方程介紹

Beizer曲線的一些特性這裡不再贅述,大家可以去網上檢視一些資料,很詳細。最近用到輪廓擬合,所以用三次Beizer曲線效果還可以,有插值和近似擬合(插值就是曲線過點,近似擬合則不過點),就學習了一下。我是做的Beizer曲線插值,插值和近視擬合無非就是控制點選取不一樣。
Beizer總方程為
∑PiKni(t)\sum P_{i}K_{i}^{n}(t) (1),
三次Beizer曲線方程:
Bn(t)=P0(1−t)3 3P1t(1−t)2 3P2t2(1−t) P3t3,tϵ[0,1]B_{n}(t)=P_{0}(1-t)^{3} 3P_{1}t(1-t)^{2} 3P_{2}t^{2}(1-t) P_{3}t^{3},t\epsilon [0,1] (2),
這裡的P1P_1和P2P_2就是所謂的控制點A、B點。關於控制點AB的求法很多種,我是採用引數設定法構造控制點,思路我是參考百度文庫一篇文章,“確定控制點文章連結”。文章寫的很詳細,對於閉合輪廓的話就想象成一個迴圈,第0個點的前兩個點為n-1和n-2,第n-1個點的後兩個點為0和1,文章很好理解。對於引數a和b,通常都是0.25,但我看別人論文中有a=0.125,b=0.05,擬合出來的效果很接近真實曲線,所以我也是採用這個引數。

2 程式碼實現

上述講了三次Beizer曲線方程,用在輪廓擬閤中怎麼實現呢。當然,你先得找到輪廓中的特徵點,然後根據兩個相鄰的特徵點擬合成一段三次Beizer曲線,控制點AB是藉助周圍幾個點得到的。思路大概就是這樣的。下面講一下具體步驟。
###2.1 得到控制點AB
控制點AB方程在剛才那篇百度文科文章中有,所以直接根據那個方程來編寫程式碼,下面是我求控制點AB的程式碼,很簡單,大家有需要的可以參考。

//求得控制點AB
void ControlAB(double *Xi,double *Yi, double *Ai_x,double *Ai_y, double *Bi_x,double *Bi_y,int n, double a, double b,int boundType)
{
if(boundType==1)
{
Ai_x[0]=Xi[0] (Xi[1]-Xi[n-1])*a;
Ai_y[0]=Yi[0] (Yi[1]-Yi[n-1])*a;
Bi_x[n-2]=Xi[n-1]-(Xi[0]-Xi[n-2])*b;
Bi_y[n-2]=Yi[n-1]-(Yi[0]-Yi[n-2])*b;
Ai_x[n-1]=Xi[n-1] (Xi[0]-Xi[n-2])*a;
Ai_y[n-1]=Yi[n-1] (Yi[0]-Yi[n-2])*a;
Bi_x[n-1]=Xi[0]-(Xi[1]-Xi[n-1])*b;
Bi_y[n-1]=Yi[0]-(Yi[1]-Yi[n-1])*b;
}
for(int i=1;i<n-1;i  )
{
Ai_x[i]=Xi[i] (Xi[i 1]-Xi[i-1])*a;
Ai_y[i]=Yi[i] (Yi[i 1]-Yi[i-1])*a;
}
for(int i=0;i<n-2;i  )
{
Bi_x[i]=Xi[i 1]-(Xi[i 2]-Xi[i])*b;
Bi_y[i]=Yi[i 1]-(Yi[i 2]-Yi[i])*b;
}
}

程式碼注意:程式碼不要瞎貼,這裡有些自定義陣列,Xi、Yi是點的x、y。

###2.2 擬合曲線生成與繪製
求得AB控制點,可以將P1P_1、P2P_2、A和B代入方程(2)中,得到P1P_1和P2P_2中間的一段三次Beizer曲線方程,就擬合出來了。這時需要看到效果。我用的是C 的MFC畫出來的曲線,當然也可以Python,Python一搜有很多例子,網上可以盪到的。我畫二維曲線用的是MFC,大家可以參考我的部落格“MFC繪製二維曲線”,給個我實驗擬合出來的閉合輪廓,其中引數a=0.125,b=0.05。
原輪廓原輪廓
這裡寫圖片描述擬合輪廓

可以看到,擬合效果還是不錯的。圖中的小黑點是我給的特徵點,MFC畫出來就是這個樣子。

3 總結

三次Beizer曲線擬合演算法還是很簡單的,主要是控制點的選取,還有最關鍵的特徵點選取。特徵點是最基本的。當然Beizer也有一些不足之處,對於非閉合輪廓的情況擬合情況不是很理想,這就需要其他的曲線擬合,我會再發一篇B樣條曲線擬合演算法的。