2009-08-07 24 views
5

Sto cercando di adattare una trasformazione da un insieme di coordinate a un altro.Soluzione dei minimi quadrati alle equazioni simultanee

x' = R + Px + Qy 
y' = S - Qx + Py 
Where P,Q,R,S are constants, P = scale*cos(rotation). Q=scale*sin(rotation) 

C'è una ben nota formula "per mano" per il montaggio di P, Q, R, S su un insieme di punti corrispondenti. Ma ho bisogno di avere una stima dell'errore sulla misura - quindi ho bisogno di una soluzione dei minimi quadrati.

Leggi 'Numerical Recipes', ma sto avendo problemi a lavorare fuori come fare questo per i set di dati con xey in loro.

può puntare a chiunque di un campione di esempio/tutorial/codice di come fare questo?
Non troppo preoccupato per la lingua.
Ma - usa solo la funzione incorporata di Matlab/Lapack/numpy/R probabilmente non utile!

modifica: Ho un ampio set di vecchi (x, y) nuovi (x, y) per adattarli. Il problema è sovradeterminato (più punti di dati che incognite), quindi l'inversione di matrice non è sufficiente e, come ho detto, ho davvero bisogno dell'errore sull'adattamento.

+3

Avete un set di (x_i, y_i, x'_i, y'_i) s oppure x +/- dx, y +/- dy ... o cosa? Se hai esattamente uno ciascuno di x, y, x ', y' puoi * solo * fare una soluzione esatta, e non c'è modo di estrarre una stima dell'errore ... – dmckee

+0

Nessuna delle funzioni minimizza tipo LMA/Gauss- Newton dà un errore diretto. Suppongo che potrei calcolare la misura migliore e poi solo calcolare l'errore da ogni punto. Avevo pensato che fosse molto più semplice di questo (cioè una semplice modalità di un linerar LSquers) e mi stavo solo stupendo –

+0

Interessante problema! Ho postato un codice che dovrebbe fare il trucco, ma la parte divertente è stata di nuovo le mie vecchie abilità matematiche arrugginite :) –

risposta

3

Il seguente codice dovrebbe fare il trucco. Ho usato la seguente formula per i residui:

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

E poi derivato il formule minimi quadrati in base alla general procedure descritto in MathWorld di Wolfram.

Ho testato questo algoritmo in Excel e funziona come previsto. Ho usato una raccolta di dieci punti casuali che sono stati poi ruotati, tradotti e ridimensionati da una matrice di trasformazione generata in modo casuale.

Senza rumore casuale applicato ai dati di uscita, questo programma produce quattro parametri (P, Q, R, e S) che sono identici ai parametri di ingresso, e un valore rSquared zero.

Poiché sempre più rumore casuale viene applicato ai punti di uscita, le costanti iniziano ad allontanarsi dai valori corretti e il valore rSquared aumenta di conseguenza.

Ecco il codice: eJames

// 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

Normalmente utilizzerei nomi di variabili più descrittivi, ma in questo caso penso che nomi lunghi come 'sumOfNewXValues' renderebbero tutto * più difficile * leggere. Le formule matematiche sembrano essere un caso speciale. –

0

Un problema è che le cose numeriche come questa sono spesso complicate. Anche quando gli algoritmi sono semplici, spesso ci sono problemi che appaiono nel calcolo reale.

Per questo motivo, se c'è un sistema si può ottenere facilmente che ha un built-in funzione, potrebbe essere meglio usare quella.

4

Per trovare P, Q, R, S e, quindi è possibile utilizzare dei minimi quadrati. Penso che la cosa confusa sia che la solita descrizione dei minimi quadrati usa x e y, ma non corrispondono alla xey nel tuo problema. Hai solo bisogno di tradurre il tuo problema attentamente nel quadro dei minimi quadrati. Nel tuo caso le variabili indipendenti sono le coordinate non trasformate x e y, le variabili dipendenti sono le coordinate trasformate x 'e y', ei parametri regolabili sono P, Q, R e S. (Se questo non è abbastanza chiaro, fammi sapere e posterò maggiori dettagli.)

Una volta trovato P, Q, R e S, quindi ridimensiona = sqrt (P^2 + Q^2) e puoi trovare la rotazione dalla rotazione sin = Q/scala e cos rotazione = P/scala.

+0

Sì, la solita presentazione dei minimi quadrati lineari è per il montaggio dell'equazione scalare y = F (x) = \ sum_i c_i f_i (x); questo problema si adatta all'equazione vettoriale r '= F (r) = \ sum_i c_i f_i (r). – las3rjock

+0

Il problema è che LSF lineare è solo in una variabile + 2 incognite. Ho 2 variabili e 4 incognite (beh tre se si assume che la scala sia la stessa) –

+0

I minimi quadrati lineari (nella solita presentazione) funzionano effettivamente per una variabile e n incognite. Vedi http://en.wikipedia.org/wiki/Linear_least_squares, dove il primo esempio grafico è per il montaggio di un polinomio di secondo ordine (n = 3). – las3rjock

1

definire la matrice 3x3 T (P, Q, R, S) tale che (x',y',1) = T (x,y,1). Poi calcolare

A = \sum_i |(T (x_i,y_i,1)) - (x'_i,y'_i,1)|^2 

e minimizzare A contro (P, Q, R, S).

codifica da soli è un mezzo al progetto di grandi dimensioni a meno che non si può guarntee che i dati sono ben condizionati, soprattutto quando si vogliono ottenere buoni stime di errore fuori della procedura. Sei probabilmente meglio fuori utilizzando un Minimizer esistente che supporta le stime di errore ..

particelle tipo di fisica userebbe minuit sia direttamente dal CERNLIB (con la codifica più facilmente realizzabile in Fortran77), o da ROOT (con la codifica in C++ , o dovrebbe essere accessibile attraverso i collegamenti Python). Ma questa è una grande installazione se non si dispone già di uno di questi strumenti.

sono sicuro che gli altri possono suggerire altre minimi.

1

È possibile utilizzare il programma levmar per calcolare questo. È testato e integrato in più prodotti, incluso il mio.La sua licenza sotto licenza GPL, ma se questo è un progetto non-opensource, cambierà la licenza per te (a pagamento)

+0

Grazie, ci sono molte impiantazioni LMA gratuite. Non avevo apprezzato il fatto che fosse un approccio necessario per quello che sembrava un semplice adattamento. –

+0

La stima dell'errore è difficile.che richiede la Jacobian della soluzione solution (IIRC). Tieni presente che gli errori LS non sono errori nel senso che il mondo pensa agli errori. Sono una misura della stabilità numerica della risposta. Quindi, qualcosa potrebbe essere la soluzione corretta, ma non particolarmente stabile (cioè cambiare un valore porta leggermente a un grande cambiamento nelle funzioni obiettivo). – Steve

+0

Sì, penso che il miglior approccio all'errore dal punto di vista dell'utente sia quello di calcolare la posizione migliore e quindi il residuo su ciascun punto e prendere la deviazione standard di questi. –

1

Grazie, questo è quasi exaclty quello che ho. L'ho codificato da un vecchio manuale di rilevamento dell'esercito basato su una precedente "Istruzioni per Geometri", nota che deve essere vecchia di 100 anni! (Usa N ed E per Nord e Est piuttosto che x/y)

Il parametro di bontà dell'adattamento sarà molto utile: posso eliminare i punti selezionati in modo interattivo se peggiorano la misura.

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

Freddo. Rabbrividisco a pensare a come l'avrebbero calcolato 100 anni fa :) –

Problemi correlati