2013-02-12 9 views
8

Nun, die Annäherung eines Kreises mit einem Polygon und die Geschichte von Pythagoras sind wohlbekannt. Aber was ist umgekehrt?Approximieren eines Polygons mit einem Kreis

Ich habe einige Polygone, die eigentlich Kreise sein sollten. Dies ist jedoch aufgrund von Messfehlern nicht der Fall. Also, was ich suche, ist der Kreis, der das gegebene Polygon am besten "approximiert".

In der folgenden Abbildung sehen wir zwei verschiedene Beispiele.

enter image description here

Mein erster Ansatz war die maximale Entfernung der Punkte zum Zentrum sowie das Minimum zu finden. Der Kreis, nach dem wir suchen, liegt vielleicht irgendwo dazwischen.

Gibt es einen Algorithmus für dieses Problem?

+1

Vielleicht können Sie die Methode der kleinsten Quadrate verwenden. [Hier ist eine PDF-Datei] (http://www.emis.de/journals/BBMS/Bulletin/sup962/gander.pdf) eines Papiers über die Suche nach einem Kreis nach der Methode der kleinsten Quadrate. Es könnte ein bisschen komplex sein für das, was Sie tun, obwohl. Wenn die Punkte ungefähr einen Kreis bilden, können Sie wahrscheinlich eine elementarere Methode finden, die gut funktioniert. – William

+0

Kleinste Quadrate scheint der Weg zu gehen, wenn Sie das Zentrum bereits kennen. Es wird im Wesentlichen ein Kurvenanpassungsproblem mit Polarkoordinaten. – Kevin

+0

Überprüfen Sie die [Hough-Transformation] (http://en.wikipedia.org/wiki/Hough_transform). Es führt zu einer einfachen Kreisdetektionslösung. – Simon

Antwort

5

Ich würde scipy verwenden, um Best- „fit“ einen Kreis auf meine Punkte. Sie können einen Ausgangspunkt für den Mittelpunkt und den Radius durch eine einfache Schwerpunktsberechnung erhalten. Dies funktioniert gut, wenn die Punkte gleichmäßig über den Kreis verteilt sind. Wenn nicht, wie im Beispiel unten, ist es immer noch besser als nichts!

Die Anpassungsfunktion ist einfach, weil ein Kreis einfach ist. Sie müssen nur den radialen Abstand von Ihrem Fit-Kreis zu Ihren Punkten finden, da die tangentiale (radiale) Fläche immer die beste Anpassung ist.

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

Das funktioniert nur, wenn keine Ausreißer vorhanden sind, siehe http://i.imgur.com/pki3Nn7.png für ein Ergebnis nach dem Hinzufügen eines Ausreißers. Wenn die Messfehler diese Art von Fehler nicht enthalten, ist dieser Ansatz in der Tat in Ordnung. – mmgp

+0

@mmgp Einverstanden. Ich ging mit der Annahme aus dem OP, "Ich habe einige Polygone, die eigentlich Kreise sein sollten", dass die zugrundeliegenden Punkte gestörte Kreise sind. Das Schöne ist, dass Sie leicht einen Anpassungsfehler daraus bekommen können, und Sie können die Passungen wiederholen, indem Sie einen fehlerhaften Punkt oder zwei entfernen und erneut prüfen. Ich denke auch, dass Sie gegen Ausreißer vorgehen können, indem Sie die Err-Strafe von^2 auf^4 erhöhen. – Hooked

+0

Das ist genau das, was ich gemacht habe. Ich mag die zusätzliche Idee, die beste Passform zu optimieren. Dank dafür. – Tengis

0

Es gibt zwei verschiedene O (n) -Algorithmen zur Bestimmung des kleinsten gezeichneten Kreises, der eine Reihe von Punkten auf der Wikipedia-Seite smallest-circle problem umfasst. Von hier aus sollte es ziemlich einfach sein, den zweiten Kreis zu zeichnen, einfach den Mittelpunkt des zuvor gefundenen Kreises zu bestimmen und den Punkt zu finden, der diesem Punkt am nächsten liegt. Der Radius des zweiten Kreises ist der.

Dies kann nicht genau, was Sie wollen, aber das ist, wie ich anfangen würde.

0

Das Problem könnte die gleiche wie die Smallest-circle problem sein.

Aber da Sie Messfehler haben die Ausreißer enthalten könnte, dann ist RANSAC eine gute Option, statt. Einen Überblick über die Methode (auch andere grundlegende Techniken) finden Sie unter http://cs.gmu.edu/~kosecka/cs482/lect-fitting.pdf, in http://www.asl.ethz.ch/education/master/info-process-rob/Hough-Ransac.pdf gibt es weitere Informationen zur Kreisanpassung.

+3

Ich bin mir nicht sicher, ob ich dem zustimme. Angenommen, er fand die Position von Punkten auf einem Kreis und es gibt einen Fehler in der Messung, der dazu führt, dass die Punkte nicht mehr auf einen perfekten Kreis fallen, sein Ziel ist es nicht, den kleinsten Kreis zu finden, der sie alle umfasst, sondern den wahrscheinlichsten Kreis das würde zu seinen besonderen Punkten führen. – Matt

+0

Ich habe die Anforderungen vielleicht falsch verstanden, ja. – mmgp

+0

+1 Für die Einführung in RANSAC und die schönen Refs! Es scheint, dass es spezifische Kenntnisse über die Art von Fehlern und Ausreißern erfordert, die Sie in Ihrem Problem finden können. – Hooked

1

Vielleicht ein einfacher Algorithmus wäre zunächst den Schwerpunkt der Punkte zu berechnen (vorausgesetzt, sie sind in der Regel grob regelmäßigen Abstand). Dies ist das Kreiszentrum. Sobald Sie das haben, können Sie den mittleren Radius der Punkte berechnen, indem Sie den Radius des Kreises angeben.

Eine anspruchsvollere Antwort wäre eine einfache Minimierung zu tun, in dem Sie die Summe der Abstände der Punkte an den Rand des Kreises (oder Abstand zum Quadrat) minimieren.

-1

Es ist ganz einfach eine gewisse Annäherung zu finden:

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 

Erklärt: die Mitte des Kreises auf den Mittelwert x gesetzt und y Ihrer Punkte bedeuten. Bestimmen Sie dann für jeden Punkt den Abstand zum Mittelpunkt und nehmen Sie den Mittelwert über alle Punkte. Das ist dein Radius.

Das komplette Skript:

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() 

produziert dieses Grundstück:

enter image description here

Diese gute Arbeit, wie Sie Polygone mit Messfehler haben. Wenn Ihre Punkte nicht annähernd gleichmäßig über die Winkel [0,2pi[ verteilt sind, wird die Leistung schlecht.

Allgemeiner könnten Sie Optimierung verwenden.

+0

Keine Respektlosigkeit beabsichtigt, aber wie unterscheidet sich das von dem, was ich mache, außer ohne Optimierung? Es wird auch leiden, wie mmgp Notizen von Ausreißern _and_, wie Sie bemerken, schlägt fehl, wenn die Punkte nicht einheitlich über den Kreis gewählt werden. – Hooked

+0

In der Tat, nur um die Dinge fair zu machen: http://i.imgur.com/4f5Ip42.png, Ausreißer bei (50, 50). RANSAC wird den passenden Kreis finden (ja, ich verkaufe meine Antwort). – mmgp

+0

Ich schrieb meine Antwort, bevor Ihre Antwort auf SO sichtbar war. Es war nur ein Ausgangspunkt für die Optimierung. Ich plante, Code aus meinem Paket 'eegpy' hier einzubauen, wo ich fast dasselbe mache, aber für die Elektrodenkoordinaten in 3d und eine Kugel: https://github.com/thorstenkranz/eegpy/blob/master/eegpy/plot /topo.py –

Verwandte Themen