Introducción
Plantillas 3D en Tulip
Tulip plantillas de marcadores 3D porque es, sin duda, la forma más precisa de realizar un seguimiento de objetos con alta fidelidad en un entorno muy ruidoso, como el de una planta de producción. Los marcadores de las plantillas son fáciles de pegar a cualquier superficie. Se pueden colocar en un contenedor, una carretilla elevadora, un camión o una pequeña herramienta de relojero: funcionan a cualquier escala, siempre que la cámara sea capaz de detectarlos. Un caso de uso clásico de las plantillas es, naturalmente, el seguimiento de los objetos de la plantilla en los que encaja la pieza de trabajo, pero con las capacidades 3D, estamos añadiendo la posibilidad de realizar el seguimiento de objetos complejos, con marcadores pegados en diferentes superficies del objeto.
Las plantillas se componen de varios marcadores 3D agrupados. Los marcadores 3D señalan una ubicación en el objeto 3D que está fijada en el «sistema de coordenadas» (un sistema de coordenadas es el conjunto de los tres ejes utilizados para definir la posición y la orientación: los ejes X, Y y Z) del objeto, suponiendo que este sea un cuerpo rígido. Siempre que vemos un marcador, sabemos que está fijado en el mismo punto del objeto. El grupo de marcadores de la plantilla define un objeto completo. Las plantillas pueden definir formas 3D complejas, con algunos marcadores visibles y otros ocultos. Los marcadores visibles nos ayudan a determinar la ubicación y la orientación del objeto. Cuando los marcadores ocultos pasan a ser visibles, compensan a los otros marcadores que ahora están ocultos.
Optimización del ajuste de paquetes
Al definir una plantilla a partir de marcadores, capturamos numerosas vistas del objeto marcado desde distintos ángulos con respecto a la cámara. Cada fotograma capturado por la cámara proporciona otra «vista» del objeto con sus marcadores. Y en cada fotograma, calculamos la posición de los marcadores en el objeto y sus relaciones (transformaciones). Tras capturar suficientes vistas, las combinamos para obtener un modelo 3D completo del objeto, lo que se conoce como el proceso de «registro». Sin embargo, debido a varias razones relacionadas con la óptica y la estabilidad numérica de los cálculos, las vistas alrededor del objeto no siempre se alinean perfectamente. De hecho, cuantas más vistas tomamos del objeto, mayor es el error acumulado en el registro, hasta el punto de que el registro final puede resultar inútil. Aquí es donde entra en juego el «ajuste de haces».
El ajuste de haces (BA) es un proceso de optimización numérica que combate el error acumulado derivado del registro de múltiples vistas de cámara para reconstruir una geometría. En el BA tradicional, se someten a optimización prácticamente todos los parámetros de la reconstrucción, incluido el modelo óptico de la cámara. Pero antes de explicar el proceso del BA, debemos definir los parámetros en juego que requieren optimización. Recomendamos encarecidamente consultar el magnífico libro del profesor Richard Szeliski «Computer Vision: Algorithms and Applications, editorial Springer, 2011 (capítulo 7, pág. 320).
Postura de la cámara y el objeto con marcadores 3D
Cuando una cámara enfoca un marcador, que es un objeto plano, es posible calcular la orientación del marcador con respecto al origen de la cámara. Obsérvese el siguiente diagrama:
El marcador es visible en la vista de la cámara y se proyecta sobre el plano de la imagen, un concepto que ayuda a establecer la correspondencia entre las coordenadas de píxeles en 3D y en 2D. Sin embargo, cuando tomamos una fotografía de la escena con el marcador, no conocemos los parámetros del punto 3D, sino que solo podemos detectar dónde se proyectaron esos puntos 3D en la imagen 2D. Esta proyección puede expresarse mediante la siguiente ecuación:
Las coordenadas X, Y y Z corresponden a las coordenadas 3D, por ejemplo, del centro del marcador, mientras que x e y indican la posición en píxeles 2D de las esquinas en la imagen. Esto pone de manifiesto la ambigüedad en los parámetros, es decir, la falta de información, debida al hecho de que un punto 3D en el mundo real puede aparecer en cualquier punto del rayo que une el centro de la cámara y el punto 3D real (véanse los puntos naranjas difuminados en el diagrama). En otras palabras, los objetos de cualquier escala arbitraria pueden aparecer en la imagen con cualquier tamaño arbitrario; todo depende de su distancia a la cámara. En esa ecuación también tenemos la rotación 3D (parámetros r) y la traslación (parámetros t) del objeto o, a la inversa, de la cámara, sin pérdida de generalidad. Los parámetros f y c son los «parámetros intrínsecos» que modelan la óptica de la cámara (de forma muy aproximada en este ejemplo simplificado).
No obstante, existe una relación lineal entre los puntos 3D y los puntos 2D, y si conociéramos todos los parámetros de esta ecuación podríamos calcular: (1) la posición 3D real del marcador a partir de las coordenadas de píxeles 2D, y (2) la rotación ri y la traslación tx, y, z del marcador con respecto a la cámara. Cabe señalar que, para trabajar con coordenadas 2D, no podemos simplemente eliminar el parámetro de nuestra ecuación y, de hecho, para obtener los puntos de píxeles, dividiríamos por el último elemento del vector: x' = λx, x = x'/λ, y' = λy, y = y'/λ.
Si disponemos de suficientes puntos correspondientes de 2D a 3D, podemos reformular la ecuación anterior en un sistema de ecuaciones lineales (homogéneas) que nos permita recuperar R y t. Mediante los marcadores 3D podemos obtener al menos cuatro pares de puntos 2D-3D correspondientes por cada marcador. Los puntos 2D los obtenemos observando la imagen y localizando las esquinas. Los puntos 3D vienen dados por la disposición del marcador, que también está bajo nuestro control (ya que hemos impreso el marcador). El proceso general de recuperación de la pose se conoce como «Perspective-n-Point» y existen muchos enfoques y algoritmos para su resolución. Por ejemplo, así es como se encontraría la pose de la cámara en Python con OpenCV a partir de un conjunto de puntos 2D-3D alineados:
_, R, t = cv2.solvePnP(aligned_3d, aligned_2d, K, dc)
El problema de optimización
Anotemos la última operación de «proyección» de la siguiente manera:
$$P_{2D}=\mathrm{Proj}([R|t], P_{3D})$$
Es decir, obtenemos la posición del píxel en 2D (P2D) a partir de la proyección del punto 3D P3D y de la rotación R y la traslación t entre la cámara y el objeto. El principal problema de este método de proyección es que se basa en cálculos realizados sobre los puntos 2D en coordenadas de píxeles, que no son muy precisos y, además, están cuantificados en la cuadrícula de píxeles. Si reproyectamos los puntos 3D (los proyectamos de nuevo en 2D sobre la imagen) tras hallar la pose del objeto [R|t], a menudo encontramos que las posiciones 2D presentan un desplazamiento respecto a sus posiciones en la imagen. La siguiente imagen muestra estos desplazamientos, que suelen ser más evidentes en situaciones extremas, como un ángulo pronunciado respecto a la cámara o en presencia de desenfoque.
Nuestro objetivo es hallar los parámetros de posición de la cámara de tal forma que todos estos desplazamientos bidimensionales sean lo más pequeños posible. Para expresarlo matemáticamente, queremos resolver el siguiente problema de minimización, que busca el [R|t] óptimo que minimice los residuos:
\hat{[R|t]} = \arg\min_{[R|t]} \sum_i \Vert \mathrm{Proj}([R|t],P_i^{\mathrm{3D}}) - P_i^{\mathrm{2D}} \Vert^2
La diferencia entre el punto 3D reproyectado y el punto 2D se denomina «residuo». Y, en general, denominamos a este problema «problema de mínimos cuadrados», ya que elevamos al cuadrado el residuo. Este caso concreto es un problema de mínimos cuadrados no lineales, ya que el operador Proj(.) es no lineal. Con esta formulación, también podemos introducir en el problema de optimización, por ejemplo, los parámetros intrínsecos de la cámara y hallar los valores óptimos para ellos también:
\hat{[R|t]},\hat{\{P^\mathrm{3D}\}},\hat{K} = \arg\min_{[R|t],\{P^\mathrm{3D}\},K} \sum_i \Vert \mathrm{Proj}([R|t],P_i^{\mathrm{3D}},K) - P_i^{\mathrm{2D}} \Vert^2
Este es un ejemplo de cómo calcular los residuos en Python con OpenCV a partir de los pares de puntos 2D-3D correspondientes y generar una lista de residuos:
def calcResiduals(Rt): projPts2d,_ = cv2.projectPoints(pts3d, Rt[:3], Rt[3:], K, None) return (np.squeeze(projPts2d2) - pts2d21).ravel()
Por suerte, existen muchos algoritmos y paquetes de software para resolver problemas de mínimos cuadrados no lineales, como Ceres Solver, diversos métodos de MATLAB, SciPy de Python y muchos otros. Por ejemplo, con SciPy y OpenCV se podría resolver el problema de la siguiente manera:
res = scipy.optimize.least_squares(calcResiduals, np.hstack([ cv2.Rodrigues(R)[0], t[np.newaxis] ]).ravel())
Resolución de análisis de barras para plantillas 3D
Hasta ahora hemos hablado del BA en términos generales; sin embargo, nuestros objetivos de optimización para las plantillas 3D son un poco diferentes. Cuando creamos nuestras plantillas 3D, en esencia estamos creando un mapa 3D. El mapeo (y la localización) es un problema bien conocido, por ejemplo, en la navegación autónoma y la odometría, donde un vehículo necesita orientarse en el mundo basándose en las observaciones de las cámaras. Nuestra técnica de mapeo de plantillas es similar a los algoritmos SLAM (localización y mapeo simultáneos), en el sentido de que construye un mapa del mundo observado de forma incremental y, ocasionalmente, aplica el BA sobre él para reducir el error residual de los diversos algoritmos de estimación lineal.
Como se mencionó en la primera sección, en un fotograma determinado podemos ver algunos marcadores pero no otros, y a medida que avanza la mapeo disponemos de más pistas sobre la posición de los marcadores entre sí. Comenzamos con los primeros marcadores visibles y tomamos nota de su estructura tridimensional, suponiendo que esta estructura nunca cambiará. Por ejemplo, la transformación entre el marcador 1 y el marcador 2 se denota como T12. En un fotograma posterior, ya no vemos el marcador 1, pero aparece el marcador 3, mientras que el marcador 2 sigue siendo visible. Denotamos la transformación de 2 a 3 como T23, y la de 1 a 3 concatenando las transformaciones: T13 = T12T23.
El proceso de mapeo introduce nuevos errores en el mapa, que se suman al error intrínseco que supone la recuperación de la pose 3D del marcador, tal y como hemos comentado anteriormente. La concatenación de transformaciones agrava los errores, hasta el punto de que pueden darse casos degenerados. Debemos aplicar el método BA para mitigar los errores acumulados; de lo contrario, el proceso de mapeo del plantilla fracasará.
Una opción para la optimización consiste en fijar las transformaciones que obtenemos a partir de la estimación de la pose de la cámara, lo que se parecería a la formulación BA anterior. Buscamos un CamP que minimice los residuos cuando se dan los puntos 3D:
\hat{\mathrm{CamP}} = \arg\min_{\mathrm{CamP}} \sum_i \Vert \mathrm{Proj}(\mathrm{CamP},P_i^{\mathrm{3D}}) - P_i^{\mathrm{2D}} \Vert^2
Sin embargo, observamos que la orientación de la cámara se deriva de los puntos 3D (mediante la correspondencia 2D-3D). Por lo tanto, podríamos optimizar las propias coordenadas de los puntos 3D y volver a calcular la orientación de la cámara a partir de ellas. Fijamos la orientación de la cámara y minimizamos en función de los puntos 3D, buscando los puntos 3D óptimos que minimicen el residuo de la reproyección 2D:
\hat{\{P^{\mathrm{3D}}\}} = \arg\min_{\{P^{\mathrm{3D}}\}} \sum_i \Vert \mathrm{Proj}(\mathrm{CamP},P_i^{\mathrm{3D}}) - P_i^{\mathrm{2D}} \Vert^2
Este truco nos ayuda principalmente a obtener un conjunto óptimo de puntos 3D situados sobre el objeto, de modo que el error respecto a los puntos 2D originales de las imágenes sea mínimo. Mantenemos la relación entre los puntos del mapa 3D y el ID de sus marcadores, de modo que en tiempo de ejecución podamos encontrar correspondencias 2D-3D y recuperar la pose del objeto, con solvePnP. En un nuevo fotograma entrante, localizamos las posiciones 2D de las esquinas de los marcadores y las hacemos coincidir con los puntos 3D del mapa, de modo que, en general, podemos determinar la pose del objeto a partir de muchos puntos 2D-3D juntos, promediando el error.
Se puede ver claramente que, tras aplicar el análisis de balance (BA) al mapa de la plantilla 3D, las desviaciones en 2D se reducen y la estimación de la postura del objeto mejora considerablemente.
Conclusiones
Las plantillas de Tulip ofrecen una amplia gama de aplicaciones para operaciones de detección en el taller. Gracias a las nuevas funciones de plantillas 3D, se pueden implementar nuevas aplicaciones, como el seguimiento de herramientas complejas que serán visibles desde diferentes ángulos, como las herramientas manuales. Mediante el mapeo de plantillas y el ajuste de paquetes, podemos generar mapas de objetos complejos con un error mínimo y una geometría optimizada. Las plantillas Tulip están disponibles para su uso en Tulip , con la optimización integrada. Úsalas para realizar el seguimiento de tus herramientas, el equipamiento de tu puesto de trabajo e incluso los materiales.