12

¿Cómo recupero la matriz de rotación, el vector de traducción y tal vez algunos factores de escala de cada cámara usando OpenCV cuando tengo imágenes de un objeto desde la vista de cada una de estas cámaras? Para cada imagen tengo las coordenadas de la imagen de varios puntos característicos. No todos los puntos de característica son visibles en todas las imágenes. Quiero asignar las coordenadas 3D calculadas de los puntos característicos del objeto a un objeto ligeramente diferente para alinear la forma del segundo objeto con el primer objeto.Cámara extrínseca OpenCV desde los puntos de característica

he oído que es posible utilizando cv::calibrateCamera(...) pero no puede llegar a ser muy través de él ...

¿Alguien tiene experiencia con este tipo de problema?

+0

No está claro por encima de si se conoce el mundo 3d coordenadas de los puntos que usted observe en las diferentes imágenes. Si este es el caso, este es un problema Perspective-n-point y puede calibrar los parámetros de cada cámara utilizando el algoritmo EPnP disponible aquí: http://cvlab.epfl.ch/software/EPnP/index.php. De lo contrario, vea mi respuesta a continuación. – Rulle

+1

Las coordenadas 3d del objeto fotografiado son desconocidas. –

+0

Si las coordenadas mundiales tridimensionales de los puntos del objeto son 'desconocidas_, no creo que cv :: calibrateCamera funcione, porque parece suponer que los puntos del objeto son _known_. – Rulle

Respuesta

11

Me enfrenté con el mismo problema que usted, en OpenCV. Tenía un par de imágenes estéreo y quería calcular los parámetros externos de las cámaras y las coordenadas mundiales de todos los puntos observados. Este problema se ha tratado aquí:

Berthold K. P. Horn. Orientación relativa revisitada. Berthold K. P. Horn. Laboratorio de Inteligencia Artificial del Instituto de Tecnología de Massachusetts, 545 Tecnología ...

http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.64.4700

Sin embargo, no fue capaz de encontrar una aplicación adecuada de este problema (tal vez se encuentra uno). Debido a limitaciones de tiempo, no tuve tiempo para entender todas las matemáticas en este documento y aplicarlo yo mismo, así que se me ocurrió una solución rápida y sucia que me funciona. Explicaré lo que hice para resolverlo:

Suponiendo que tenemos dos cámaras, donde la primera cámara tiene parámetros externos RT = Matx :: eye(). Ahora adivine sobre la rotación R de la segunda cámara. Para cada par de puntos de imagen observados en ambas imágenes, calculamos las direcciones de sus rayos correspondientes en coordenadas mundiales y los almacenamos en una matriz 2d dirs (EDITAR: Se supone que se conocen los parámetros internos de la cámara). Podemos hacer esto ya que suponemos que sabemos la orientación de cada cámara. Ahora construimos un sistema lineal sobredeterminado AC = 0 donde C es el centro de la segunda cámara. Yo le proporcionará la función para calcular R:

Mat buildA(Matx<double, 3, 3> &R, Array<Vec3d, 2> dirs) 
{ 
    CV_Assert(dirs.size(0) == 2); 
    int pointCount = dirs.size(1); 
    Mat A(pointCount, 3, DataType<double>::type); 
    Vec3d *a = (Vec3d *)A.data; 
    for (int i = 0; i < pointCount; i++) 
    { 
     a[i] = dirs(0, i).cross(toVec(R*dirs(1, i))); 
     double length = norm(a[i]); 
     if (length == 0.0) 
     { 
      CV_Assert(false); 
     } 
     else 
     { 
      a[i] *= (1.0/length); 
     } 
    } 
    return A; 
} 

Entonces llamando cv :: :: SVD solveZ (A) le dará la solución de mínimos cuadrados de la norma 1 de este sistema. De esta forma, obtienes la rotación y la traducción de la segunda cámara. Sin embargo, como acabo de adivinar la rotación de la segunda cámara, hago varias conjeturas sobre su rotación (parametrizada usando un vector 3x1 omega a partir del cual calculo la matriz de rotación usando cv :: Rodrigues) y luego refino esta suposición resolviendo el sistema AC = 0 repetidamente en un optimizador Levenberg-Marquardt con jacobian numérico. Funciona para mí, pero está un poco sucio, así que si tienes tiempo, te animo a implementar lo que se explica en el documento.

EDIT:

Aquí está la rutina en el optimizador de Levenberg-Marquardt para evaluar el vector de residuos:

void Stereo::eval(Mat &X, Mat &residues, Mat &weights) 
{ 

     Matx<double, 3, 3> R2Ref = getRot(X); // Map the 3x1 euler angle to a rotation matrix 
     Mat A = buildA(R2Ref, _dirs); // Compute the A matrix that measures the distance between ray pairs 
     Vec3d c; 
     Mat cMat(c, false); 
     SVD::solveZ(A, cMat); // Find the optimum camera centre of the second camera at distance 1 from the first camera 
     residues = A*cMat; // Compute the output vector whose length we are minimizing 
    weights.setTo(1.0); 
} 

Por cierto, he buscado un poco más en el Internet y encontrar algún otro código que podría ser útil para calcular la orientación relativa entre cámaras. No he probado todavía ningún código, pero parece útil:

http://www9.in.tum.de/praktika/ppbv.WS02/doc/html/reference/cpp/toc_tools_stereo.html

http://lear.inrialpes.fr/people/triggs/src/

http://www.maths.lth.se/vision/downloads/

+0

Muchas gracias por su respuesta. Creo que entiendo lo que escribiste y codificó y me ayudará mucho a encontrar una posible solución para mi problema. Sin embargo, creo que 'cv :: calibrateCamera (...)' funciona bastante similar a lo que usted propuso. Describen el algoritmo de la siguiente manera: –

+0

1. Primero, calcula los parámetros intrínsecos iniciales (la opción solo disponible para patrones de calibración planar) o los lee de los parámetros de entrada. Los coeficientes de distorsión están todos configurados en ceros inicialmente (a menos que se especifique CV_CALIB_FIX_K?). 2. La posición inicial de la cámara se estima como si ya se conocieran los parámetros intrínsecos. Esto se hace usando FindExtrinsicCameraParams2 –

+0

3. Después de eso, se ejecuta el algoritmo de optimización Levenberg-Marquardt para minimizar el error de reproyección, es decir, la suma total de distancias cuadradas entre los puntos característicos observados imagePoints y el proyectado (usando las estimaciones actuales para parámetros de cámara y las poses) object points objectPoints; ver ProjectPoints2. –

2

¿Estas cámaras estáticas que desea calibrar para su uso futuro como un par estéreo? En este caso, querrá usar la función cv::stereoCalibrate(). OpenCV contiene algunos ejemplos de código, uno de los cuales es stereo_calib.cpp, que puede valer la pena investigar.

+0

Gracias por su respuesta, pero no tengo ningún interés en usar un par estéreo. Tengo una cámara, que se usa para ver el mismo objeto desde diferentes lados. Luego, los puntos característicos marcados en cada imagen me ayudarán a calcular nuevas posiciones para los puntos correspondientes de un objeto virtual que se va a deformar levemente. El objeto virtual debería tener la geometría exacta como el objeto real que se fotografió. BTW 'cv :: calibrateCamera (...)' utiliza 'cv :: stereoCalibrate()' en el progreso del cálculo. –

+0

Ok, ¿está calibrada su cámara individual (es decir, conoce los parámetros intrínsecos: distancia focal, inclinación del píxel, punto principal, coeficientes de distorsión)? – Chris

+0

Podría estimarlos pero los valores reales son desconocidos. –

Cuestiones relacionadas