2011-06-09 391 views
20

我有一套數據點(我可以精簡),我需要適應Bézier curve。我需要速度超過準確性,但適合度應足夠體面以便可識別。我還在尋找一種我可以使用的算法,它不會大量使用庫(特別是NumPy)。如何將貝塞爾曲線擬合成一組數據?

我讀過幾篇研究論文,但都沒有足夠的細節來完全實現。有沒有開源的例子?

回答

16

我有類似的問題,我發現Graphics Gems(1990)關於貝塞爾曲線擬合的「自動擬合數字化曲線的算法」。 此外,我發現該文章source code

不幸的是它是用C編寫的,我不太清楚。此外,算法很難理解(至少對我而言)。我正試圖將它翻譯成C#代碼。如果我能成功,我會盡力分享。

文件GGVecLib.cFitCurves.c位於相同的文件夾中包含基本矢量操作函數。

我找到了一個類似的堆棧 溢出問題,Smoothing a hand-drawn curve。經批准的答案提供了來自Graphic Gems的曲線擬合算法的C#代碼。

+0

它看起來很複雜。任何人都可以驗證此代碼的作品? – user791684 2011-06-24 03:21:48

+0

@Archibald你是否已經成功將該代碼翻譯成C#? – Spook 2013-06-21 10:02:08

+0

_An自動擬合數字化curve_的算法的鏈接被破壞。 – 2014-12-01 03:28:40

2

如果大部分數據都符合您的模型,您可以試試RANSAC。從中選擇4個點並隨機選擇一條貝塞爾曲線就足夠簡單了。我並不確定,要評估曲線與其他所有點(RANSAC算法的一部分)是多麼昂貴。但這將是一個線性解決方案,RANSAC非常容易編寫(並且可能有開源算法)。

+0

RANSAC的每次迭代都需要評估曲線並找出到所有點的距離。如果這是在1D中,那麼它很簡單,在二維或三維中變得很困難,因爲您需要找到曲線上最近的點並計算出誤差(歐幾里得距離)。這將至少每次迭代O(n)。迭代次數由內部比率和模型大小給出。所以如果你想要適合一個4分弧線,這可能是可行的。弧中點數越多,獲得點的機會就越小。 – 2017-03-03 11:14:15

+0

因此,這將適用於單弧的簡單情況,但對於更長的樣條將會無限緩慢。更重要的是,請注意,對於貝塞爾曲線*,曲線*沒有通過點*,所以即使您選擇了正確的點,也會給您一條錯誤的曲線。你最好用例如通過控制點的Catmull-Rom樣條曲線。 – 2017-03-03 11:44:42

+0

但是,這並不意味着貝塞爾曲線不適合一組點。這意味着這條曲線的至少一些控制點不會與數據點重合。但是,如果使用最小二乘等技術,那幾乎不重要。 – 2017-03-05 14:02:34

0

首先,確保你要求的是實際上你想要的。將點擬合到貝塞爾曲線將它們放置在點的殼體中。使用樣條曲線將確保曲線貫穿所有點。

也就是說,創建繪製的函數根本不復雜。維基百科有一篇不錯的文章,將解釋基本知識,Bézier curve

+4

Downvoted,因爲這根本不回答這個問題。在維基百科鏈接到貝塞爾曲線只是說明顯而易見的,另外維基百科文章不解決曲線擬合 – 2015-11-02 03:00:14

5

您可以將問題設置爲適合噪音數據的最小二乘法。

http://nbviewer.ipython.org/5688579

注意,一旦你找出方程中的實際計算是相當簡單。實際的計算是對數據進行求和,然後反轉並乘以一個4x4矩陣。

我知道這個線程現在已經很長時間了,但是我發現這是一個有趣的問題,以防其他人絆倒它。

請參閱http://www.embedded.com/electrical-engineer-community/industry-blog/4027019/1/Why-all-the-math-關於最小二乘的優秀教程。

+1

您可否請將許可證添加到您的IPython筆記本電腦代碼中以便重複使用?謝謝。 – karenyng 2016-10-20 18:14:02

+0

@ karenyng我聯繫了作者,並回復說:「請使用你想要的代碼」。 – leavez 2017-03-18 07:38:00

0

我有這個問題的MATLAB解決方案。 我遇到了同樣的問題,但我的代碼是用MATLAB編寫的。 我希望它不太難將其翻譯成Python。

您可以通過這個代碼FindBezierControlPointsND.m 出於某種原因,找到控制點,它沒有功能「ChordLengthNormND」其檔案, 但它被稱爲在第45行

我通過以下幾行取代了它:

[arclen,seglen] = arclength(p(:,1),p(:,2),'sp'); 
t = zeros(size(p,1),1); 
sums = seglen(1); 
for i = 2:size(p,1)-1 
    t(i) = sums/arclen; 
    sums = sums + seglen(i); 
end 
t(end) = 1; 

arclength的MATLAB代碼可以在這裏獲得。

之後,我們有了貝塞爾曲線的控制點,並且網絡上的控制點有很多實現構建貝塞爾曲線。

7

許多這些答案中缺少的是您可能不想爲您的數據擬合單個三次Bézier曲線。更一般地,您想要將一系列三次貝塞爾曲線(即分段三次貝塞爾擬合)擬合到任意一組數據。

有一個很好的論文追溯到1995年,完成與MATLAB代碼,這是否:

% Lane, Edward J. Fitting Data Using Piecewise G1 Cubic Bezier Curves. 
% Thesis, NAVAL POSTGRADUATE SCHOOL MONTEREY CA, 1995 

http://www.dtic.mil/dtic/tr/fulltext/u2/a298091.pdf

要使用此功能,你必須,至少,指定結點的數量,即優化程序將使用的數字數據點來使其適合。或者,您可以自己指定結點,這會提高擬合的可靠性。論文顯示了一些非常艱難的例子。注意,Lane的方法保證了三次Bézier段之間的G1連續性(相鄰切向量的方向相同),即平滑的關節。但是,曲率會有不連續性(二階導數方向的變化)。

我重新實現了代碼,將其更新到現代MATLAB(R2015b)。如果你願意,請聯繫我。

下面是一個僅使用三個結點(通過代碼自動選擇)將一個立方貝塞爾曲線擬合到利薩如圖的例子。

(StackOverflow上!!!!不會讓我在我的聲望等級張貼圖片)

+1

如果您可以在[GitHub gist](https://gist.github.com/)上發佈您的代碼重新實現代碼到MATLAB R2015b並鏈接到此處,我將不勝感激。謝謝! – 2017-03-16 11:14:19