2012-01-19 15 views
38

Ho 4 punti complanari in un video (o immagine) che rappresenta un quad (non necessariamente un quadrato o un rettangolo) e vorrei poter visualizzare un cubo virtuale su sopra di loro dove gli angoli del cubo si trovano esattamente agli angoli del video quad.Posa telecamera di calcolo con matrice di omografia basata su 4 punti complanari

Poiché i punti sono complanari, posso calcolare l'omografia tra gli angoli di un quadrato unitario (cioè [0,0] [0,1] [1,0] [1,1]) e le coordinate video del quad.

Da questa omografia dovrei essere in grado di calcolare una posa corretta della telecamera, cioè [R | t] dove R è una matrice di rotazione 3x3 e t è un vettore di traduzione 3x1 in modo che il cubo virtuale si trovi sul quad video.

Ho letto molte soluzioni (alcune su SO) e ho provato a implementarle ma sembrano funzionare solo in alcuni casi "semplici" (come quando il video quad è un quadrato) ma nella maggior parte dei casi non funzionano.

Ecco i metodi che ho provato (molti di questi sono basati sugli stessi principi, solo il calcolo della traduzione è leggermente diverso). Sia K la matrice intrinseca della telecamera e H l'omografia. Calcoliamo:

A = K-1 * H 

Let a1, a2, a3 essere i vettori colonna di A e r1, r2, r3 i vettori colonna della matrice di rotazione R.

r1 = a1/||a1|| 
r2 = a2/||a2|| 
r3 = r1 x r2 
t = a3/sqrt(||a1||*||a2||) 

Il problema è che questo non funziona nella maggior parte dei casi. Per verificare i miei risultati, ho confrontato R e t con quelli ottenuti con il metodo solvePnP di OpenCV (utilizzando i seguenti punti 3D [0,0,0] [0,1,0] [1,0,0] [1,1 , 0]).

Poiché visualizzo il cubo allo stesso modo, ho notato che in ogni caso solvePnP fornisce risultati corretti, mentre la posa ottenuta dall'omografia è per lo più errata.

In teoria dal momento che i miei punti sono complanari, è possibile calcolare la posizione da un omografia, ma non riuscivo a trovare il modo corretto per calcolare la posizione da H.

Eventuali approfondimenti su ciò che sto facendo male ?

Modifica dopo aver provato @ metodo di Jav_Rock

Ciao Jav_Rock, grazie mille per la risposta, ho cercato il tuo approccio (e molti altri) che sembra essere più o meno OK. Tuttavia, ho ancora problemi con il calcolo della posa basato su 4 punti complanari. Per verificare i risultati, mi confronto con i risultati di solvePnP (che sarà molto meglio a causa dell'approccio di minimizzazione dell'errore di riproiezione iterativo).

Ecco un esempio:

cube

  • Cubo giallo: risolvere PNP
  • Black Cube: la tecnica di Jav_Rock
  • Ciano (e viola) cubo (s): alcune altre tecniche indicate lo stesso identico risultato

Come potete vedere, il cubo nero è più o meno OK, ma non sembra ben proporzionato, anche se i vettori sembrano ortonormali.

EDIT2: Ho normalizzato v3 dopo aver calcolato che (al fine di far rispettare ortonormalità) e sembra per risolvere alcuni problemi pure.

+2

Così solvepnp di OpenCV fornisce risultati corretti, mentre l'implementazione è sbagliato? – nav

+1

Sì solvePnP fornisce risultati corretti mentre la mia implementazione usando solo omografie non fornisce i corretti vettori di rotazione/traduzione. – JimN

+1

Se condividi il tuo codice, possiamo esaminarlo e vedere come può essere risolto. Una cosa che potresti aver dimenticato è applicare l'ortonormalità della matrice di rotazione. – fireant

risposta

25

Se avete il vostro omografia, è possibile calcolare la fotocamera posa con qualcosa di simile:

void cameraPoseFromHomography(const Mat& H, Mat& pose) 
{ 
    pose = Mat::eye(3, 4, CV_32FC1);  // 3x4 matrix, the camera pose 
    float norm1 = (float)norm(H.col(0)); 
    float norm2 = (float)norm(H.col(1)); 
    float tnorm = (norm1 + norm2)/2.0f; // Normalization value 

    Mat p1 = H.col(0);  // Pointer to first column of H 
    Mat p2 = pose.col(0); // Pointer to first column of pose (empty) 

    cv::normalize(p1, p2); // Normalize the rotation, and copies the column to pose 

    p1 = H.col(1);   // Pointer to second column of H 
    p2 = pose.col(1);  // Pointer to second column of pose (empty) 

    cv::normalize(p1, p2); // Normalize the rotation and copies the column to pose 

    p1 = pose.col(0); 
    p2 = pose.col(1); 

    Mat p3 = p1.cross(p2); // Computes the cross-product of p1 and p2 
    Mat c2 = pose.col(2); // Pointer to third column of pose 
    p3.copyTo(c2);  // Third column is the crossproduct of columns one and two 

    pose.col(3) = H.col(2)/tnorm; //vector t [R|t] is the last column of pose 
} 

questo metodo funziona mi formano. In bocca al lupo.

+1

Puoi commentare cosa sta accadendo nel codice? –

+7

Ciao Jav_Rock, grazie mille per la tua risposta, ho provato il tuo metodo e modificato il post in modo che tu possa vedere i risultati ottenuti. Grazie ancora. – JimN

+3

Penso che l'immagine non sia visibile. Ad ogni modo, se vuoi approfondire la teoria puoi leggere questa domanda dal dsp.stackexchange http://dsp.stackexchange.com/q/2736/1473 –

4

Solo nel caso qualcuno ha bisogno di pitone porting della funzione scritto da @Jav_Rock:

def cameraPoseFromHomography(H): 
    H1 = H[:, 0] 
    H2 = H[:, 1] 
    H3 = np.cross(H1, H2) 

    norm1 = np.linalg.norm(H1) 
    norm2 = np.linalg.norm(H2) 
    tnorm = (norm1 + norm2)/2.0; 

    T = H[:, 2]/tnorm 
    return np.mat([H1, H2, H3, T]) 

funziona bene nei miei compiti.

+0

come funziona senza parametri della fotocamera intrinseca? – Mehdi

+0

@Mehdi Suppongo che l'omografia si presume funzioni su coordinate normalizzate: p '= K^(- 1) [p; 1]. –

-1

Ecco una versione pitone, basata su quella presentata da Dmitriy Voloshyn che normalizza la matrice di rotazione e traspone il risultato sia 3x4.

def cameraPoseFromHomography(H): 
    norm1 = np.linalg.norm(H[:, 0]) 
    norm2 = np.linalg.norm(H[:, 1]) 
    tnorm = (norm1 + norm2)/2.0; 

    H1 = H[:, 0]/norm1 
    H2 = H[:, 1]/norm2 
    H3 = np.cross(H1, H2) 
    T = H[:, 2]/tnorm 

    return np.array([H1, H2, H3, T]).transpose() 
5

Computing [R | T] dalla matrice omografia è un po 'più complicato di risposta di Jav_Rock.

In OpenCV 3.0, c'è un metodo chiamato cv :: decomposeHomographyMat che restituisce quattro possibili soluzioni, uno di loro è corretta. Tuttavia, OpenCV non ha fornito un metodo per scegliere quello corretto.

Ora ci sto lavorando e forse pubblicherò i miei codici qui a fine mese.

+3

Hai capito come scegliere la soluzione corretta? –

7

La risposta proposta da Jav_Rock non fornisce una soluzione valida per le pose della telecamera nello spazio tridimensionale.

per stimare un albero tridimensionale trasformare e rotazione indotta da un omografia, esistono diversi approcci. One of them fornisce formule chiuse per la scomposizione dell'omografia, ma sono molto complesse. Inoltre, le soluzioni non sono mai uniche.

Fortunatamente, OpenCV 3 implementa già questa decomposizione (decomposeHomographyMat). Data un'omografia e una matrice intrinseca correttamente ridimensionata, la funzione fornisce un insieme di quattro possibili rotazioni e traduzioni.

+0

Il calcolo del prelievo della soluzione corretta dalle ultime due soluzioni possibili è molto complicato. Conoscete qualche implementazione del documento che può restituire una soluzione tra le due soluzioni finali? –

0

L'aereo che contiene il tuo quadrato sull'immagine ha agenti di corsia che scompaiono dalla tua macchina fotografica. L'equazione di questa riga è A x + B y + C = 0.

Normale del piano è (A, B, C)!

Let p00, p01, p10, p11 sono coordinate del punto dopo l'applicazione parametri intrinseci della telecamera e in forma omogenea e.g, P00 = (X00, y00,1)

fuga linea può essere calcolato come:

  • giù = p00 croce p01;
  • sinistra = p00 croce p10;
  • right = p01 cross p11;
  • up = p10 cross p11;
  • v1 = left cross right;
  • v2 = up cross down;
  • vanish_line = v1 cross v2;

Dove croce nel prodotto vettoriale serie vettore

Problemi correlati