web-dev-qa-db-fra.com

Pose de caméra informatique avec matrice d'homographie basée sur 4 points coplanaires

J'ai 4 points coplanaires dans une vidéo (ou image) représentant un quadruple (pas nécessairement un carré ou un rectangle) et je voudrais pouvoir afficher un cube virtuel au-dessus d'eux où les coins du cube se trouvent exactement sur les coins du quadruple vidéo.

Comme les points sont coplanaires, je peux calculer l'homographie entre les coins d'un carré unitaire (c'est-à-dire [0,0] [0,1] [1,0] [1,1]) et les coordonnées vidéo du quad.

À partir de cette homographie, je devrais être capable de calculer une pose de caméra correcte, c'est-à-dire [R | t] où R est une matrice de rotation 3x3 et t est un vecteur de translation 3x1 de sorte que le cube virtuel se trouve sur le quadruple vidéo.

J'ai lu de nombreuses solutions (certaines d'entre elles sur SO) et j'ai essayé de les mettre en œuvre mais elles semblent fonctionner uniquement dans certains cas "simples" (comme lorsque le quadruple vidéo est un carré) mais ne fonctionnent pas dans la plupart des cas.

Voici les méthodes que j'ai essayées (la plupart sont basées sur les mêmes principes, seuls les calculs de traduction sont légèrement différents). Soit K la matrice intrinsèque de la caméra et H l'homographie. Nous calculons:

A = K-1 * H

Soit a1, a2, a3 les vecteurs colonnes de A et r1, r2, r3 les vecteurs colonnes de la matrice de rotation R.

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

Le problème est que cela ne fonctionne pas dans la plupart des cas. Afin de vérifier mes résultats, j'ai comparé R et t avec ceux obtenus par la méthode resolPnP d'OpenCV (en utilisant les points 3D suivants [0,0,0] [0,1,0] [1,0,0] [1,1 , 0]).

Comme j'affiche le cube de la même manière, j'ai remarqué que, dans tous les cas, resolPnP fournit des résultats corrects, tandis que la pose obtenue à partir de l'homographie est généralement fausse.

En théorie, puisque mes points sont coplanaires, il est possible de calculer la pose à partir d'une homographie, mais je n'ai pas trouvé la bonne façon de calculer la pose à partir de H.

Des idées sur ce que je fais mal?

Modifier après avoir essayé la méthode de @ Jav_Rock

Salut Jav_Rock, merci beaucoup pour votre réponse, j'ai essayé votre approche (et bien d'autres aussi) qui semble plus ou moins OK. Néanmoins, il m'arrive d'avoir des problèmes lors du calcul de la pose sur la base de 4 points coplanaires. Afin de vérifier les résultats, je compare avec les résultats de resolPnP (qui seront bien meilleurs en raison de l'approche de minimisation des erreurs de reprojection itérative).

Voici un exemple:

cube

  • Cube jaune: Résoudre PNP
  • Black Cube: la technique de Jav_Rock
  • Cube (s) cyan (et violet): certaines autres techniques donnent exactement les mêmes résultats

Comme vous pouvez le voir, le cube noir est plus ou moins OK mais ne semble pas bien proportionné, bien que les vecteurs semblent orthonormés.

EDIT2: J'ai normalisé la v3 après l'avoir calculée (afin d'imposer l'orthonormalité) et cela semble aussi résoudre certains problèmes.

44
JimN

Si vous avez votre homographie, vous pouvez calculer la pose de la caméra avec quelque chose comme ceci:

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
}

Cette méthode fonctionne à partir de moi. Bonne chance.

30
Jav_Rock

La réponse proposée par Jav_Rock ne fournit pas de solution valable pour les poses de caméras dans un espace tridimensionnel.

Pour estimer une transformation et une rotation arborescentes induites par une homographie, il existe plusieurs approches. L'un d'eux fournit des formules fermées pour décomposer l'homographie, mais elles sont très complexes. De plus, les solutions ne sont jamais uniques.

Heureusement, OpenCV 3 implémente déjà cette décomposition ( decomposeHomographyMat ). Étant donné une homographie et une matrice intrinsèque correctement mise à l'échelle, la fonction fournit un ensemble de quatre rotations et traductions possibles.

9
Emiswelt

Juste au cas où quelqu'un aurait besoin de python portage de la fonction écrite par @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])

Fonctionne bien dans mes tâches.

8
Dmytriy Voloshyn

Le calcul de [R | T] à partir de la matrice d'homographie est un peu plus compliqué que la réponse de Jav_Rock.

Dans OpenCV 3.0, il existe une méthode appelée cv :: decomposeHomographyMat qui renvoie quatre solutions potentielles, l'une d'entre elles est correcte. Cependant, OpenCV n'a pas fourni de méthode pour choisir la bonne.

J'y travaille maintenant et je posterai peut-être mes codes ici plus tard ce mois-ci.

6
Yang Kui

Le plan qui contient votre carré sur l'image a des agents de voie de fuite sur votre appareil photo. L'équation de cette ligne est A x + B y + C = 0.

La normale de votre avion est (A, B, C)!

Soit p00, p01, p10, p11 sont les coordonnées du point après l'application des paramètres intrinsèques de la caméra et sous une forme homogène, par exemple, p00 = (x00, y00,1)

La ligne de fuite peut être calculée comme suit:

  • bas = p00 croisé p01;
  • gauche = croix p00 p10;
  • à droite = croix p01 p11;
  • up = p10 croise p11;
  • v1 = croix gauche à droite;
  • v2 = haut en bas;
  • vanish_line = v1 cross v2;

croix dans le produit vectoriel vectoriel standard

0
DejanM