2012-06-28 11 views
20

Esta pregunta es sobre las funciones de OpenCV findHomography, getPerspectiveTransform & getAffineTransformfindHomography, getPerspectiveTransform, y getAffineTransform

  1. ¿Cuál es la diferencia entre findHomography y getPerspectiveTransform?. Mi comprensión de la documentación es que getPerspectiveTransform calcula la transformación usando 4 correspondencias (que es el mínimo requerido para calcular una transformación de homografía/perspectiva) donde findHomography calcula la transformación incluso si proporciona más de 4 correspondencias (presumiblemente utilizando algo así como un mínimo cuadrados ¿método?). ¿Es esto correcto? (en cuyo caso la única razón por la OpenCV todavía sigue apoyando getPerspectiveTransform debe ser legado?)

  2. Mi siguiente preocupación es que me gustaría saber si hay un equivalente a findHomography para calcular una transformación afín? es decir, una función que utiliza un método de mínimos cuadrados o un método robusto equivalente para calcular y afinar la transformación. Según la documentación, getAffineTransform admite solo 3 correspondencias (que es el mínimo requerido para calcular una transformación afín).

mejor,

+1

Tal [estimateRigidTransform] (http://docs.opencv.org/modules/video/doc/motion_analysis_and_object_tracking.html # estimaterigidtransform) se ajustaría a sus necesidades. – cgat

Respuesta

24

Q # 1: Derecho, la findHomography trata de encontrar la mejor transformar entre dos conjuntos de puntos. Utiliza algo más inteligente que los cuadrados mínimos, llamado RANSAC, que tiene la capacidad de rechazar valores atípicos: si al menos el 50% + 1 de tus datos son correctos, RANSAC hará todo lo posible para encontrarlos y crear una transformación confiable.

El getPerspectiveTransform tiene muchas razones útiles para quedarse: es la base de la búsqueda de imágenes, y es útil en muchas situaciones en las que solo tiene 4 puntos, y sabe que son los correctos. La función FindHomography se usa generalmente con conjuntos de puntos detectados automáticamente; puede encontrar muchos de ellos, pero con poca confianza. getPerspectiveTransform es bueno cuando sabes con seguridad 4 esquinas, como el marcado manual o la detección automática de un rectángulo.

Q # 2 No hay equivalente para las transformaciones afines. Puede usar findHomography, porque las transformaciones afines son un subconjunto de homografías.

8

Estoy de acuerdo con todo lo que @vasile ha escrito. Sólo quiero añadir algunas observaciones:

getPerspectiveTransform() y getAffineTransform() están destinados a trabajar en o 3 puntos (respectivamente), que son conocidos por ser correspondencias correctas. En las imágenes de la vida real tomadas con una cámara real, puede nunca obtener correspondencias que sean precisas, no con marcado automático ni manual de los puntos correspondientes.

Siempre hay valores atípicos. Basta con mirar el caso simple de querer ajustar una curva a través de puntos (por ejemplo, tomar una ecuación generativa con ruido y1 = f(x) = 3.12x + gauss_noise o y2 = g(x) = 0.1x^2 + 3.1x + gauss_noise): será mucho más fácil encontrar una buena función cuadrática para estimar los puntos en ambos casos, que un buen lineal. Cuadrática puede ser una exageración, pero en la mayoría de los casos no lo será (después de eliminar valores atípicos), y si quiere encajar en línea recta, es mejor que esté seguro de que es el modelo correcto, de lo contrario obtendrá resultados inservibles.

Dicho esto, si está poderosamente seguro que transformación afín es la correcta, he aquí una sugerencia:

  • uso findHomography, que tiene RANSAC incorporado en la funcionalidad, para deshacerse de los valores atípicos y obtener una estimación inicial de la transformación de imagen
  • seleccionar 3 correspondencias correctas (que se ajustan a la homografía encontrada), o reproyectar 3 puntos de la 1 a 2 (usando la homografía)
  • use esas 3 coincidencias (que son lo más cercano a lo correcto que puede obtener) en getAffineTransform()
  • envuelva todo eso en su propio findAffine() si lo desea - ¡y listo!
+0

¿Hay alguna forma de encontrar la mejor matriz "Afín"? Quiero forzar que la última fila de la homografía sea [0, 0, 1]. – Royi

+1

@Drazick El "algoritmo" que he escrito hace casi eso: utiliza findHomography para deshacerse de los valores atípicos y para que no tenga que codificar su propio RANSAC, y que puede usar getAffineTransform() en 3 puntos para obtener una mejor afinidad cercana. Alternatevley, podría codificar su propio algoritmo RANSAC con getAffineTransform() en lugar de getPerspectiveTransform() como una función central. – penelope

+0

@penleope, encontré una solución para encontrar la mejor transformada afín (12 sabios) usando SVD de una manera similar a como se calcula la mejor homografía. – Royi

3

Re Q # 2, estimateRigidTransform es el equivalente sobremuestreado de getAffineTransform. No sé si fue en OCV cuando se publicó por primera vez, pero está disponible en 2.4.

1

Hay una solución fácil para encontrar la transformación Affine para el sistema de ecuaciones sobre-determinadas.

  1. Tenga en cuenta que, en general, una transformación afín encuentra una solución al sistema sobredeterminado de ecuaciones lineales Ax = B mediante el uso de un pseudo-inversa o una técnica similar, por lo

x = (AA t) -1 a t B

por otra parte, esto se maneja en la funcionalidad central OpenCV por una llamada simple de resolver (a, B, X).

  1. Familiarícese con el código de transformación afín en OpenCV/módulos/imgproc/src/imgwarp.cpp: lo que realmente hace sólo dos cosas:

    a. reorganiza las entradas para crear un sistema Ax = B;

    b. luego llama a resolver (A, B, X);

NOTA: ignorar los comentarios de función en el código OPENCV - que son confusas y no reflejan el orden real de los elementos de las matrices. Si está resolviendo [u, v]’= Afín * [x, y, 1] es el reordenamiento:

  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 

Todo lo que necesita hacer es añadir más puntos. Para hacer que Solve (A, B, X) funcione en un sistema excesivamente determinado, agregue el parámetro DECOMP_SVD. Para ver las diapositivas de PowerPoint sobre el tema, use este link. Si desea obtener más información sobre el pseudoinverso en el contexto de la visión artificial, la mejor fuente es: ComputerVision, consulte el capítulo 15 y el apéndice C.

Si todavía no está seguro de cómo agregar más puntos, consulte mi código de abajo:

// 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; 
Cuestiones relacionadas