2009-08-07 11 views
5

Ich versuche eine Transformation von einem Koordinatensystem zu einem anderen anzupassen.Lösung der kleinsten Quadrate für simultane Gleichungen

Es gibt eine wohlbekannte "von Hand" Formel für die Anpassung von P, Q, R, S an eine Menge entsprechender Punkte. Aber ich muss eine Fehlerschätzung für die Anpassung haben - also brauche ich eine Kleinste-Quadrate-Lösung.

Lesen Sie "Numerische Rezepte", aber ich habe Probleme herauszufinden, wie dies für Datensätze mit x und y in ihnen zu tun.

Kann jemand auf ein Beispiel/Tutorial/Codebeispiel zeigen, wie man das macht?
Nicht zu stören über die Sprache.
Aber - nur eingebaute Feature von Matlab/Lapack/numpy/R wahrscheinlich nicht hilfreich!

bearbeiten: Ich habe eine große Reihe von alten (x, y) neu (x, y) zu passen. Das Problem ist überbestimmt (mehr Datenpunkte als Unbekannte), so dass eine einfache Matrixinversion nicht ausreicht - und wie gesagt, ich brauche den Fehler bei der Anpassung.

+3

Haben Sie eine Menge von (x_i, y_i, x'_i, y'_i) s oder x +/- dx, y +/- dy ... oder was? Wenn Sie jeweils genau eine von x, y, x ', y' haben, können Sie * nur * eine exakte Lösung erstellen, und es gibt keine Möglichkeit, eine Fehlerschätzung zu extrahieren ... – dmckee

+0

Keine der Funktionen vom Minimierungstyp LMA/Gauss- Newton gibt einen direkten Fehler. Ich nehme an, ich könnte die beste Anpassung berechnen und dann den Fehler von jedem Punkt aus berechnen. Ich dachte, es wäre viel einfacher als das (dh. Ein einfacher Modus eines linerar LSquers) und ich war nur dumm –

+0

Interessantes Problem! Ich postete einen Code, der den Trick machen sollte, aber der spaßige Teil bestand darin, meine rostigen alten mathematischen Fähigkeiten wieder auszubrechen :) –

Antwort

3

Der folgende Code sollte den Trick tun. I verwendet, um die folgende Formel für das Residuen:

residual[i] = (computed_x[i] - actual_x[i])^2 
       + (computed_y[i] - actual_y[i])^2 

und abgeleitete dann die Least-Squares-Formeln auf der Grundlage der bei general procedure Wolframs MathWorld beschrieben.

Ich habe diesen Algorithmus in Excel getestet und es funktioniert wie erwartet. Ich verwendete eine Sammlung von zehn zufälligen Punkten, die dann rotiert, übersetzt und skaliert wurden durch eine zufällig erzeugte Transformationsmatrix.

Ohne zufälligem Rauschen auf die Ausgangsdaten angewendet wird, erzeugt dieses Programm vier Parameter (P, Q, R und S), die mit den Eingangsparametern identisch sind, und einen Wert von Null rSquared.

Da mehr und mehr zufälliges Rauschen auf die Ausgangspunkte angewendet wird, beginnen die Konstanten von den korrekten Werten abzuweichen, und der Wert rSquared erhöht sich entsprechend. Hier

ist der Code:

// test data 
const int N = 1000; 
float oldPoints_x[N] = { ... }; 
float oldPoints_y[N] = { ... }; 
float newPoints_x[N] = { ... }; 
float newPoints_y[N] = { ... }; 

// compute various sums and sums of products 
// across the entire set of test data 
float Ex = Sum(oldPoints_x, N); 
float Ey = Sum(oldPoints_y, N); 
float Exn = Sum(newPoints_x, N); 
float Eyn = Sum(newPoints_y, N); 
float Ex2 = SumProduct(oldPoints_x, oldPoints_x, N); 
float Ey2 = SumProduct(oldPoints_y, oldPoints_y, N); 
float Exxn = SumProduct(oldPoints_x, newPoints_x, N); 
float Exyn = SumProduct(oldPoints_x, newPoints_y, N); 
float Eyxn = SumProduct(oldPoints_y, newPoints_x, N); 
float Eyyn = SumProduct(oldPoints_y, newPoints_y, N); 

// compute the transformation constants 
// using least-squares regression 
float divisor = Ex*Ex + Ey*Ey - N*(Ex2 + Ey2); 
float P = (Exn*Ex + Eyn*Ey - N*(Exxn + Eyyn))/divisor; 
float Q = (Exn*Ey + Eyn*Ex + N*(Exyn - Eyxn))/divisor; 
float R = (Exn - P*Ex - Q*Ey)/N; 
float S = (Eyn - P*Ey + Q*Ex)/N; 

// compute the rSquared error value 
// low values represent a good fit 
float rSquared = 0; 
float x; 
float y; 
for (int i = 0; i < N; i++) 
{ 
    x = R + P*oldPoints_x[i] + Q*oldPoints_y[i]; 
    y = S - Q*oldPoints_x[i] + P*oldPoints_y[i]; 
    rSquared += (x - newPoints_x[i])^2; 
    rSquared += (y - newPoints_y[i])^2; 
} 
+0

Ich würde normalerweise mehr beschreibende Variablennamen verwenden, aber in diesem Fall denke ich, dass lange Namen wie 'sumOfNewXValues ​​'tatsächlich alles * schwerer * zum Lesen machen würden. Mathematische Formeln scheinen ein Spezialfall zu sein. –

0

Ein Problem ist, dass numerische Sachen wie diese oft knifflig sind. Selbst wenn die Algorithmen einfach sind, gibt es oft Probleme, die sich bei der tatsächlichen Berechnung ergeben.

Aus diesem Grund, wenn es ein System gibt, das Sie leicht erhalten können, das eine eingebaute Eigenschaft hat, ist es vielleicht am besten, das zu verwenden.

4

Um P, Q, R und S zu finden, können Sie die kleinsten Quadrate verwenden. Ich denke, das Verwirrende ist, dass die übliche Beschreibung der kleinsten Quadrate x und y verwendet, aber sie stimmen nicht mit dem x und y in Ihrem Problem überein. Sie müssen nur Ihr Problem sorgfältig in das Framework der kleinsten Quadrate übersetzen. In Ihrem Fall sind die unabhängigen Variablen die nicht transformierten Koordinaten x und y, die abhängigen Variablen sind die transformierten Koordinaten x 'und y' und die einstellbaren Parameter sind P, Q, R und S. (Wenn dies nicht klar genug ist, lass es mich wissen und ich werde mehr Details veröffentlichen.)

Sobald Sie P, Q, R und S gefunden haben, dann skalieren Sie = sqrt (P^2 + Q^2) und Sie können dann die Rotation finden von Sin Rotation = Q/Skala und Cos Rotation = P/Skala.

+0

Ja, die übliche Darstellung der linearen kleinsten Quadrate ist für die Anpassung der Skalargleichung y = F (x) = \ sum_i c_i f_i (x); Dieses Problem passt zu der Vektorgleichung r '= F (r) = \ sum_i c_i f_i (r). – las3rjock

+0

Das Problem ist, dass lineare LSF nur in einer Variablen + 2 Unbekannten ist. Ich habe 2 Variablen und 4 Unbekannte (gut drei, wenn Sie davon ausgehen, dass die Skalierung gleich ist) –

+0

Linear kleinste Quadrate (in der üblichen Darstellung) funktioniert tatsächlich für eine Variable und n Unbekannten. Siehe http://en.wikipedia.org/wiki/Linear_least_squares, wobei das erste grafische Beispiel zum Anpassen eines Polynoms zweiter Ordnung (n = 3) dient. – las3rjock

1

Definieren Sie die 3x3 Matrix T (P, Q, R, S) so, dass (x',y',1) = T (x,y,1). Dann berechne

und minimiere A gegen (P, Q, R, S).

Das selbst zu kodieren ist ein mittelgroßes bis großes Projekt, es sei denn, Sie können garantieren, dass die Daten gut konditioniert sind, besonders wenn Sie gute Fehlerschätzungen außerhalb des Verfahrens wünschen. Sie sind wahrscheinlich am besten aus einem bestehenden minimizer verwenden, die Fehlerabschätzung unterstützt ..

Teilchenphysik Typ minuit entweder direkt von CERNLIB (mit der Codierung am einfachsten in FORTRAN77) verwenden würde, oder von ROOT (mit der Codierung in C++ , oder es sollte über die Python-Bindungen zugänglich sein). Aber das ist eine große Installation, wenn Sie eines dieser Tools noch nicht haben.

Ich bin sicher, dass andere andere Minimizer vorschlagen können.

1

Sie können das Programm levmar verwenden, um dies zu berechnen. Es ist getestet und in mehrere Produkte einschließlich meiner integriert.Es ist lizenziert unter der GPL, aber wenn dies ein Open Source-Projekt ist, wird er die Lizenz für Sie ändern (gegen Gebühr)

+0

Danke, es gibt viele kostenlose LMA Implementations. Ich hatte nicht gewusst, dass es ein notwendiger Ansatz für etwas war, das wie ein einfacher Anfall aussah. –

+0

Es ist die Fehlerschätzung, die schwer ist.das erfordert die Jacobi der Lösungsmatrix (IIRC). Denken Sie daran, dass LS-Fehler keine Fehler in dem Sinne sind, dass die Welt über Fehler nachdenkt. Sie sind ein Maß für die numerische Stabilität der Antwort. Also könnte etwas die richtige Lösung sein, aber nicht besonders stabil (d. H. Das Ändern eines Wertes führt leicht zu einer großen Änderung der Zielfunktionen). – Steve

+0

Ja Ich denke, der beste Ansatz für den Fehler aus der Sicht des Benutzers ist es, die beste Position und dann das Residuum an jedem Punkt zu berechnen und die Standardabweichung von diesen zu nehmen. –

1

Dank eJames, das ist fast exaclty, was ich habe. Ich habe es aus einem alten Vermessungshandbuch der Armee abgeleitet, das auf einer früheren "Instructions to Surveyors" -Note basierte, die 100 Jahre alt sein muss! (Es verwendet N und E für Nord und Ost anstelle von x/y)

Die Güte der Fit-Parameter wird sehr nützlich sein - ich kann ausgewählte Punkte interaktiv auswerfen, wenn sie die Passform schlechter machen.

FindTransformation(vector<Point2D> known,vector<Point2D> unknown) { 
{ 
    // sums 
    for (unsigned int ii=0;ii<known.size();ii++) { 
     sum_e += unknown[ii].x; 
     sum_n += unknown[ii].y; 
     sum_E += known[ii].x; 
     sum_N += known[ii].y;        
     ++n;   
    } 

    // mean position 
    me = sum_e/(double)n; 
    mn = sum_n/(double)n; 
    mE = sum_E/(double)n; 
    mN = sum_N/(double)n; 

    // differences 
    for (unsigned int ii=0;ii<known.size();ii++) { 

     de = unknown[ii].x - me; 
     dn = unknown[ii].y - mn; 

     // for P 
     sum_deE += (de*known[ii].x); 
     sum_dnN += (dn*known[ii].y); 
     sum_dee += (de*unknown[ii].x); 
     sum_dnn += (dn*unknown[ii].y); 

     // for Q 
     sum_dnE += (dn*known[ii].x); 
     sum_deN += (de*known[ii].y);      
    } 

double P = (sum_deE + sum_dnN)/(sum_dee + sum_dnn); 
double Q = (sum_dnE - sum_deN)/(sum_dee + sum_dnn); 

double R = mE - (P*me) - (Q*mn); 
double S = mN + (Q*me) - (P*mn); 
} 
+0

Kühl. Ich schaudere, wie sie es vor 100 Jahren berechnet hätten :) –

Verwandte Themen