findHomography, getPerspectiveTransform, & getAffineTransform

cette question Est sur les fonctions OpenCV findHomography,getPerspectiveTransform&getAffineTransform

  1. Quelle est la différence entre findHomography et getPerspectiveTransform?. Ma compréhension de la documentation est que getPerspectiveTransform calcule la transformation en utilisant 4 correspondances (ce qui est le minimum requis pour calculer une transformation homographie/perspective) où comme findHomography calcule la transformation même si vous fournissez plus de 4 correspondances (probablement en utilisant quelque chose comme les moindres carrés méthode?). Est-ce correct? (Dans ce cas, la seule raison pour laquelle OpenCV continue à soutenir getPerspectiveTransform devrait être legacy? )

  2. ma prochaine préoccupation est que je veux savoir s'il y a un équivalent à findHomography pour calculer une transformation Affine? c'est-à-dire une fonction qui utilise une méthode des moindres carrés ou une méthode robuste équivalente pour calculer et affiner la transformation. Selon la documentation getAffineTransform prend en seulement 3 correspondances (ce qui est le minimum requis pour calculer une transformation affine).

,

23
demandé sur Angie Quijano 2012-06-28 08:08:43

4 réponses

Q #1: à droite, la findhomographie tente de trouver la meilleure transformation entre deux ensembles de points. Il utilise quelque chose de plus intelligent que les moindres carrés, appelé RANSAC, qui a la capacité de rejeter les valeurs aberrantes - si au moins 50% + 1 de vos points de données sont OK, RANSAC fera de son mieux pour les trouver, et construire une transformation fiable.

le getPerspectiveTransform a beaucoup de raisons utiles pour rester - il est la base pour la findHomography, et il est utile dans de nombreuses situations où vous n'avez que 4 points, et vous savez que ce sont les bons. La findhomographie est habituellement utilisée avec des ensembles de points détectés automatiquement - vous pouvez trouver beaucoup d'entre eux, mais avec une faible confiance. getPerspectiveTransform est bon quand vous savez à coup sûr 4 coins-comme le marquage manuel, ou la détection automatique d'un rectangle.

Q #2

28
répondu Sam 2012-06-28 05:58:17

je suis d'accord avec tout ce que @vasile a écrit. Je veux juste ajouter quelques observations:

getPerspectiveTransform() et getAffineTransform() sont destinés à travailler sur 4 ou 3 points (respectivement), qui sont connu pour être correct correspondances. Sur des images réelles prises avec un vrai appareil photo, vous pouvez jamais obtenir des correspondances aussi précises, pas avec marquage automatique ou manuel des points correspondants.

il y a toujours les valeurs aberrantes. il suffit de regarder le cas simple de vouloir ajuster une courbe à travers des points (par exemple prendre une équation générative avec le bruit y1 = f(x) = 3.12x + gauss_noise ou y2 = g(x) = 0.1x^2 + 3.1x + gauss_noise): il sera beaucoup plus facile de trouver une bonne fonction quadratique pour estimer les points dans les deux cas, qu'une bonne linéaire. Quadratique peut être un surmenage, mais dans la plupart des cas ne le sera pas (après avoir enlevé les valeurs aberrantes), et si vous voulez mettre une ligne droite là-bas, vous avez intérêt à être sûr que c'est le bon modèle, sinon vous êtes allez obtenir inutilisable résultats.

cela dit, si vous sont puissamment bien sûr que la transformation affine est la bonne, voici une suggestion:

  • utiliser findHomography, a RANSAC incorporé à la fonctionnalité, pour se débarrasser des valeurs aberrantes et obtenir une estimation initiale de la transformation de l'image
  • choisir 3 correspondances correctes-correspondances (qui correspondent à l'homographie trouvée), ou reprojecter 3 points de la 1ère image pour la 2ème (en utilisant l'homographie)
  • utilisez ces 3 correspondances (qui sont aussi près de corriger que vous pouvez obtenir) dans getAffineTransform()
  • envelopper tout cela dans votre propre findAffine() si vous le souhaitez et le tour est joué!
8
répondu penelope 2017-11-01 06:12:05

Re Q#2, estimateRigidTransform est l'équivalent suréchantillonné de getAffineTransform. Je ne sais pas si C'était dans OCV quand ça a été posté, mais c'est disponible en 2.4.

3
répondu Ben 2014-08-17 23:44:08
  1. notez qu'en général une transformation Affine trouve une solution au système sur-déterminé D'équations linéaires Ax=B en utilisant un pseudo-inverse ou une technique similaire, donc

x = (A A t) -1 t B

de plus, ceci est traité dans l'openCV de base fonctionnalité par un simple appel à résoudre(A, B, X).

  1. familiarisez-vous avec le code de transformation Affine dans opencv/modules/imgproc/src/imgwarp.rpc: il n'a vraiment juste deux choses:

    b. ensuite, les appels solve(A, B, X);

NOTE: ignorer les commentaires de fonction dans le code openCV-ils sont confus et ne reflètent pas l'ordre réel des éléments dans le matrice. Si vous résolvez [u, v]’= Affine * [x, y, 1] le réarrangement est:

         x1 y1 1 0  0  1
         0  0  0 x1 y1 1
         x2 y2 1 0  0  1
    A =  0  0  0 x2 y2 1
         x3 y3 1 0  0  1
         0  0  0 x3 y3 1

    X = [Affine11, Affine12, Affine13, Affine21, Affine22, Affine23]’

         u1 v1
    B =  u2 v2
         u3 v3 

Tout ce que vous devez faire est d'ajouter plus de points. Pour faire fonctionner Solve(A, B, X) sur un système sur-déterminé, ajoutez le paramètre DECOMP_SVD. Pour voir les diapositives powerpoint sur le sujet, utilisez ce lien. Si vous souhaitez en savoir plus sur le pseudo-inverse dans le contexte de la vision informatique, la meilleure source est: ComputerVision, voir le chapitre 15 et l'annexe C.

si vous ne savez toujours pas comment ajouter plus de points voir mon code ci-dessous:

// extension for n points;
cv::Mat getAffineTransformOverdetermined( const Point2f src[], const Point2f dst[], int n )
{
    Mat M(2, 3, CV_64F), X(6, 1, CV_64F, M.data); // output
    double* a = (double*)malloc(12*n*sizeof(double));
    double* b = (double*)malloc(2*n*sizeof(double));
    Mat A(2*n, 6, CV_64F, a), B(2*n, 1, CV_64F, b); // input

    for( int i = 0; i < n; i++ )
    {
        int j = i*12;   // 2 equations (in x, y) with 6 members: skip 12 elements
        int k = i*12+6; // second equation: skip extra 6 elements
        a[j] = a[k+3] = src[i].x;
        a[j+1] = a[k+4] = src[i].y;
        a[j+2] = a[k+5] = 1;
        a[j+3] = a[j+4] = a[j+5] = 0;
        a[k] = a[k+1] = a[k+2] = 0;
        b[i*2] = dst[i].x;
        b[i*2+1] = dst[i].y;
    }

    solve( A, B, X, DECOMP_SVD );
    delete a;
    delete b;
    return M;
}

// call original transform
vector<Point2f> src(3);
vector<Point2f> dst(3);
src[0] = Point2f(0.0, 0.0);src[1] = Point2f(1.0, 0.0);src[2] = Point2f(0.0, 1.0);
dst[0] = Point2f(0.0, 0.0);dst[1] = Point2f(1.0, 0.0);dst[2] = Point2f(0.0, 1.0);
Mat M = getAffineTransform(Mat(src), Mat(dst));
cout<<M<<endl;
// call new transform
src.resize(4); src[3] = Point2f(22, 2);
dst.resize(4); dst[3] = Point2f(22, 2);
Mat M2 = getAffineTransformOverdetermined(src.data(), dst.data(), src.size());
cout<<M2<<endl;
1
répondu Vlad 2015-01-17 00:30:25