c++ - learn - perspective correction opencv
findHomography, getPerspectiveTransform, y getAffineTransform (4)
Esta pregunta es sobre las funciones de OpenCV findHomography
, getPerspectiveTransform
y getAffineTransform
¿Cuál es la diferencia entre
findHomography
ygetPerspectiveTransform
? Mi comprensión de la documentación es quegetPerspectiveTransform
calcula la transformación usando 4 correspondencias (que es el mínimo requerido para calcular una transformación de homografía / perspectiva) dondefindHomography
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 que OpenCV aún continúa admitiendo getPerspectiveTransform debería ser heredado?)Mi siguiente preocupación es que quiero saber si hay un equivalente a
findHomography
para computar una transformación Affine. 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. De acuerdo con la documentacióngetAffineTransform
toma en solo 3 correspondencias (que es el mínimo requerido para calcular una transformación afín).
Mejor,
Estoy de acuerdo con todo lo que @vasile ha escrito. Solo quiero agregar algunas observaciones:
getPerspectiveTransform()
y getAffineTransform()
están diseñados para trabajar en 4 o 3 puntos (respectivamente), que se sabe que son correspondencias correctas . En las imágenes de la vida real tomadas con una cámara real, nunca se pueden obtener correspondencias tan precisas, ni con el marcado automático ni manual de los puntos correspondientes.
Siempre hay valores atípicos. Basta con mirar el simple caso de querer ajustar una curva a través de los 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 una buena función 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á muy seguro de que la transformación afín es la correcta, le ofrecemos una sugerencia:
- utilice
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 la imagen - seleccione 3 coincidencias correctas-correspondencias (que encajan con la homografía encontrada), o reproyecte 3 puntos desde la 1ra. imagen hasta la 2da (usando la homografía)
- use esas 3 coincidencias (que son lo más cercano a lo correcto que puede obtener) en
getAffineTransform()
- envuelve todo eso en tu propio
findAffine()
si quieres, ¡y listo!
Existe una solución fácil para encontrar la transformación Affine para el sistema de ecuaciones sobre-determinadas.
- Tenga en cuenta que, en general, una transformación Affine encuentra una solución para el sistema excesivamente determinado de ecuaciones lineales Ax = B utilizando una técnica pseudoinversa o similar, por lo que
x = (AA t ) -1 A t B
Además, esto se maneja en la funcionalidad core openCV mediante una simple llamada a resolver (A, B, X).
Familiarícese con el código de la transformación Affine en opencv / modules / imgproc / src / imgwarp.cpp: realmente solo hace dos cosas:
a. reorganiza las entradas para crear un sistema Ax = B;
segundo. luego llama a resolver (A, B, X);
NOTA: ignore los comentarios de la función en el código openCV; son confusos y no reflejan el orden real de los elementos en las matrices. Si resuelve [u, v] ''= Affine * [x, y, 1] la reorganización es:
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 necesitas hacer es agregar 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 aún no está seguro de cómo agregar más puntos, consulte mi código a continuación:
// 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;
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.
Q # 1 : Bien, el findHomography intenta encontrar la mejor transformación 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 para findHomography, y es útil en muchas situaciones en las que solo tienes 4 puntos, y sabes 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.