2013-02-12 4 views
8

ポリゴンとピタゴラスの物語で円​​を近似することはよく知られているかもしれません。 しかし、それ以外の方法はどうですか?円でポリゴンを近似する

私はいくつかのポリゴンを持っていますが、実際には円でなければなりません。しかし、測定誤差のためにそうではありません。だから、私が探しているのは、与えられたポリゴンを最も近似するサークルです。

次の図では、2つの異なる例を見ることができます。

enter image description here

私の最初Ansatzは、中心に点の最大距離、ならびに最小値を見出すことでした。私たちが探しているサークルは、おそらくその中間にあります。

この問題のアルゴリズムはありますか?

+1

おそらく、最小二乗法を使用できます。最小二乗法を用いて円を見つけることについて書かれた論文の[ここはPDFファイルです](http://www.emis.de/journalals/BBMS/Bulletin/sup962/gander.pdf) あなたがやっていることのためには、それは少し複雑かもしれません。ポイントがおおよそ円であれば、おそらくもっとうまくいくより基本的な方法を見つけることができます。 – William

+0

あなたがすでに中心を知っていれば、最小の四角形が行く方法のようです。これは本質的に極座標の曲線適合問題になります。 – Kevin

+0

[ハフ変換](http://ja.wikipedia.org/wiki/Hough_transform)を確認してください。それは簡単な円検出ソリューションにつながります。 – Simon

答えて

5

を使用して、円を自分のポイントに最適にフィットさせます。簡単な質量中心計算によって、中心と半径の出発点を得ることができます。点が円の上に均一に分布している場合は、これがうまくいきます。下の例のようにそうでない場合、それは何もないよりも優れています!

円が簡単なのでフィッティング機能は簡単です。接線(放射状)サーフェスが常に最適になるので、フィットサークルからポイントまでの半径距離を求める必要があります。

import numpy as np 
from scipy.spatial.distance import cdist 
from scipy.optimize import fmin 
import scipy 

# Draw a fuzzy circle to test 
N = 15 
THETA = np.random.random(15)*2*np.pi 
R  = 1.5 + (.1*np.random.random(15) - .05) 
X = R*np.cos(THETA) + 5 
Y = R*np.sin(THETA) - 2 

# Choose the inital center of fit circle as the CM 
xm = X.mean() 
ym = Y.mean() 

# Choose the inital radius as the average distance to the CM 
cm = np.array([xm,ym]).reshape(1,2) 
rm = cdist(cm, np.array([X,Y]).T).mean() 

# Best fit a circle to these points 
def err((w,v,r)): 
    pts = [np.linalg.norm([x-w,y-v])-r for x,y in zip(X,Y)] 
    return (np.array(pts)**2).sum() 

xf,yf,rf = scipy.optimize.fmin(err,[xm,ym,rm]) 

# Viszualize the results 
import pylab as plt 
fig = plt.figure() 
ax = fig.add_subplot(1, 1, 1) 

# Show the inital guess circle 
circ = plt.Circle((xm, ym), radius=rm, color='y',lw=2,alpha=.5) 
ax.add_patch(circ) 

# Show the fit circle 
circ = plt.Circle((xf, yf), radius=rf, color='b',lw=2,alpha=.5) 
ax.add_patch(circ) 

plt.axis('equal') 
plt.scatter(X,Y) 
plt.show() 

enter image description here

+0

実際の異常値がない場合にのみ正常に動作します.1つの異常値を追加した後の結果については、http://i.imgur.com/pki3Nn7.pngを参照してください。測定誤差にこのタイプの誤差が含まれていない場合、この方法は実際にはほとんどうまくいきません。 – mmgp

+0

@ mmgp合意。私はOPの前提について、「実際には円であるべきポリゴンがいくつかあります」という根本的な点が乱れた円であることに気付きました。いいことは、あなたが簡単にこれからフィットエラーを得ることができ、あなたは誤ったポイントまたは2を削除し、再チェックすることによってフィットを繰り返すことができるということです。また、^ 2から^ 4に誤ったペナルティを増やすことでアウトライアーに偏っていると思う。 – Hooked

+0

基本的にこれはまさに私がやったことです。私は最適なフィット感を最適化するという追加の考え方が好きです。ありがとうございました。 – Tengis

0

wikipediaページsmallest-circle problemの一連の点を含む、描く最小円を決定するための2つの異なるO(n)アルゴリズムがあります。ここから、2番目の円を描き、以前に見つかった円の中心を決定し、その点に最も近い点を見つけることはかなり簡単です。 2番目の円の半径はそれです。

これはまさにあなたが望むものではないかもしれませんが、これが私のやり方です。

0

この問題はSmallest-circle problemと同じ場合があります。

しかし、測定値に異常値が含まれている可能性があるため、代わりにRANSACは良いオプションです。方法の概要についてはhttp://cs.gmu.edu/~kosecka/cs482/lect-fitting.pdf(他の基本的な技術と同様)を参照してください。http://www.asl.ethz.ch/education/master/info-process-rob/Hough-Ransac.pdfには、円フィッティング専用の情報があります。

+3

私は同意できないと思います。彼が円上の点の位置を見つけていて、測定に誤差があり、点が完全な円にならなくなったとすれば、彼の目標はそれらをすべて包含する最小の円を見つけることではなく、最も可能性の高い円彼の特定の点につながるだろう。 – Matt

+0

私は要件を誤解している可能性があります。 – mmgp

+0

+1私をRANSACと素敵なヒントに紹介してくれた!それはあなたがあなたの問題で遭遇するかもしれないエラーと異常値のタイプの特定の知識を必要としているようです。 – Hooked

1

おそらく、簡単なアルゴリズムは、まず点の重心を計算することです(通常は、ほぼ規則的に間隔を置いています)。これは円の中心です。いったんそれを持っていれば、円の半径を与えて、点の平均半径を計算することができます。

もっと洗練された答えは、点の円の端までの距離の和(または距離の二乗)を最小にする簡単な最小化を行うことです。

-1

これは、いくつかの近似を見つけることは非常に簡単です:

def find_circle_deterministically(x,y): 
    center = x.mean(), y.mean() 
    radius = np.sqrt((x-center[0])**2 + (y-center[1])**2).mean() 
    return center, radius 

を説明:平均xに円の中心を置き、あなたのポイントのy座標を意味します。次に、各点について、中心までの距離を決定し、すべての点にわたって平均をとる。それはあなたの半径です。

この完全なスクリプト:

import numpy as np 
import matplotlib.pyplot as plt 

n_points = 10 
radius = 4 
noise_std = 0.3 

angles = np.linspace(0,2*np.pi,n_points,False) 
x = np.cos(angles) * radius 
y = np.sin(angles) * radius 
x += np.random.normal(0,noise_std,x.shape) 
y += np.random.normal(0,noise_std,y.shape) 

plt.axes(aspect="equal") 
plt.plot(x,y,"bx") 

def find_circle_deterministically(x,y): 
    center = x.mean(), y.mean() 
    radius = np.sqrt((x-center[0])**2 + (y-center[1])**2).mean() 
    return center, radius 

center, radius2 = find_circle_deterministically(x,y) 
angles2 = np.linspace(0,2*np.pi,100,True) 
x2 = center[0] + np.cos(angles2) * radius2 
y2 = center[1] + np.sin(angles2) * radius2 
plt.plot(x2,y2,"r-") 

plt.show() 

はこのプロットを生成します。

enter image description here

あなたは測定誤差とポリゴンを持っているので、これは良い動作します。あなたのポイントが角度[0,2pi[にほぼ均等に分配されていないと、パフォーマンスが悪くなります。

さらに一般的には、最適化を使用できます。

+0

無礼を意図していませんが、これは私が最適化しない限り何をしているのですか?また、外れ値_and_からのmmgpノートは、ポイントがサークル上で一様に選択されていないと失敗することになります。 – Hooked

+0

確かに、物事を公正にするために:http://i.imgur.com/4f5Ip42.png、外れ値は(50、50)。 RANSACは適切な円を見つけます(はい、私は私の答えを売っています)。 – mmgp

+0

答えがあなたの目の前に表示される前に私は自分の答えを書いた。それは最適化を行うための出発点としてのものでした。私は私のパッケージ 'eegpy'からいくつかのコードをここに置くことを計画しました。ここで私はほぼ同じですが、3dと球の電極座標はhttps://github.com/thorstenkranz/eegpy/blob/master/eegpy/plot /topo.py –

関連する問題