Progreso mayo 2024 - RoboticsURJC/tfg-dcampoamor GitHub Wiki
SEMANA 47 (29/04/2024-05/05/2024)
SEMANA 48 (06/05/2024-12/05/2024)
SEMANA 49 (13/05/2024-19/05/2024)
-
Estimación de la distancia para su uso en el script pinhole.py
-
Vídeos de prueba del uso y los resultados del script pinhole.py
SEMANA 50 (20/05/2024-26/05/2024
SEMANA 51 (27/05/2024-02/06/2024
SEMANA 47 (29/04/2024-05/05/2024)
-
Pruebas con otro script para calcular las coordenadas del mundo real a partir de coordenadas de imagen utilizando una única cámara calibrada basada en geometría analítica mediante un visualizador de puntos en vídeo
Dados los resultados, y viendo que a pesar de las pruebas realizadas, no se conseguía sacar nada en claro, y que los resultados experimentales obtenidos aún distaban bastante de los reales, se decidió seguir los pasos del repositorio de Julia López, que basaba sus pruebas en el script pinhole.py.
Se ajustaron los parámetros necesarios para el uso del script con nuestro caso, entre los cuales se encontraban las variables globales, como el ancho y largo de la imagen, o la distancia focal y centro óptico de la cámara, junto con el ángulo que se encuentra rotado para el cálculo de la matriz de rotación y la altura de la cámara sobre la mesa para el cálculo de la matriz de traslación.
También se cambió el rango de detección, para que, al ejecutar el script, se detectase el color amarillo del post-it sobre la cartulina blanca situada encima de la mesa, y que de este modo facilitase la detección.
Se supuso el origen del sistema de coordenadas mundo en la proyección vertical de la cámara sobre la mesa, y a partir de este origen, se intentaron llevar a cabo distintas pruebas, variando tanto el signo del ángulo de rotación de la cámara como el signo de la distancia de la cámara a la mesa, con tal de averiguar la orientación de los ejes para este script, y ver si los resultados obtenidos se asemejaban a la realidad.
Para empezar a tomar resultados, se utilizó una regla sobre la cual se iba variando la posición del post-it amarillo para ver la evolución de los datos obtenidos al respecto, y que se supuso que estaba situada sobre el eje X (dada la rotación de la cámara, se midió desde el origen de coordenadas hasta un punto en el que la regla empezaba a ser visible, de ahí los valores reales de las medidas)
Tras estas pruebas, también se fijo una posición en el que, en un principio, se había supuesto eje X del sistema de coordenadas mundo, para poder comprobar el eje restante.
Con estos resultados, se puede observar, que la distancia (altura) a la que se encuentre la cámara sobre el plano suelo, deberá introducirse en negativo junto con el ángulo de rotación sobre el eje Y de la cámara en positivo, para que los resultados cuadren y que cuanto más se aleje el post-it amarillo, la distancia sea mayor, ya que lo que no puede variar es el origen del sistema de coordenadas, que se supuso en la vertical de la posición de la cámara.
SEMANA 48 (06/05/2024-12/05/2024)
-
Pruebas con otro script para calcular las coordenadas del mundo real a partir de coordenadas de imagen utilizando una única cámara calibrada basada en geometría analítica mediante un visualizador de puntos en vídeo
Habiendo comprobado esto, se puede deducir que la representación del sistema de coordenadas mundo podría ser la siguiente:
Siendo lo que muestra la siguiente imagen lo que se puede ver a través de cámara. Estas diferencias a la hora de percibir las imágenes, ocurren debido a la forma en que la cámara captura y procesa la imagen. Esto sucede porque la cámara registra la escena con una rotación de 180º desde su propia perspectiva, entonces, cuando te mueves hacia la derecha desde tu punto de vista, desde la perspectiva de la cámara, parecerá que te estás moviendo hacia la izquierda.
Sin embargo, a pesar de definir los ejes, los resultados seguían sin ser buenos, por lo que se optó por basarse en los comentarios del script pinhole.py en los que se especificaba junto a los ángulos requeridos para calcular la matriz de rotación, que estos ángulos son representados "considerando que la camara (en vertical) está rotada 90º sobre eje Y" . Tomando esto en cuenta se representó como sería el sistema de coordenadas de la cámara sin esta rotación posterior de 90º.
Rotando sobre el eje Y de la cámara, y utilizando el ángulo que resultaba de restar estos 90º de rotación menos el ángulo que se estaba utilizando hasta ahora (ángulo que forma la horizontal con la dirección de la lente) se volvió a ejecutar el script para ver los resultados que se obtenían al respecto con esta rotación de 65º aproximadamente.
SEMANA 49 (13/05/2024-19/05/2024)
-
Estimación de la distancia para su uso en el script pinhole.py
Estos resultados obtenidos en el apartado anterior se pueden considerar buenos dada su similitud con las medidas reales, por lo que se procedió a incluir el parámetro del cálculo de la distancia en el script a partir de las coordenadas 3D del punto, y a comprobar si esta también se aproximaba a la distancia real.
Para ello se creó la función calcular_distancia_3d, tal y como se muestra a continuación:
# Función para calcular la distancia euclidiana def calcular_distancia_3d(x_cam, y_cam, z_cam, x_punto, y_punto, z_punto): distancia = np.sqrt((x_punto - x_cam)**2 + (y_punto - y_cam)**2 + (z_punto - z_cam)**2) return distancia
Para posteriormente hacer la llamada dentro de la función getPoints y poder mostrar por pantalla junto a las coordenadas 3D esta distancia calculada:
# Coordenadas aproximadas del punto en 3D x_punto = pixelOnGround3D.x y_punto = pixelOnGround3D.y z_punto = pixelOnGround3D.z # Coordenadas aproximadas de la cámara en 3D x_cam = myCamera.position.x y_cam = myCamera.position.y z_cam = myCamera.position.z # Calcular distancia euclidiana distancia = calcular_distancia_3d(x_cam, y_cam, z_cam, x_punto, y_punto, z_punto) # Mostrar la distancia debajo de las coordenadas 3D aproximadas print(f"Distancia al punto: {distancia:.2f} milímetros")
Todo esto puede verse detalladamente en el script completo modificado pinhole.py. Después de llevar a cabo estas modificaciones en el programa, se ejecutó para comprobar su correcto funcionamiento, pudiendo dar por buenos también los resultados debido a la similitud entre los resultados reales y los obtenidos.
-
Vídeos de prueba del uso y los resultados del script pinhole.py
Para probar el uso y los resultados de la última versión modificada del script pinhole.py, se grabaron varios vídeos en los que se muestra su ejecución y cómo se detecta el centroide del post-it, y que si se mueve tanto a lo largo del eje X como muestra el vídeo Detección de puntos en EJE X.mp4 como a lo largo del eje Y o entre los dos ejes combinados (Detección de puntos EJE Y.mp4) , este se detecta, variando en función del cambio las coordenadas en 3D de ese centroide y la distancia desde la cámara a él.
-
Introducción a OpenGL
Con el fin de reproducir una línea recta en 2D en base a una línea real dibujada sobre el plano, coincidente con lo detectado por la cámara web, se realizó el "Hello World" de esta librería que será la utilizada para poder llevar esto a cabo. Previa ejecución de los scripts de introducción a OpenGL, se instalaron los paquetes PyOpenGL y PyOpenGL_accelerate mediante el comando:
pip install PyOpenGL PyOpenGL_accelerate
Como resultado, se obtuvo el dibujo de un polígono blanco (rectángulo) con las esquinas en (0.25, 0.25, 0) y (0.75, 0.75, 0) sobre un fondo negro:
Se pueden encontrar los archivos utilizados para reproducir el "Hello World" en la carpeta openglhw, así como el vídeo en el que se muestra el proceso de ejecución y el resultado de estos en Vídeo Hello World OpenGL.
Tras esta primera aproximación a OpenGL, se modificó el archivo openglhw.py para probar distintas cosas, como el cambio de color de la figura representada así como la forma geométrica de esta, dando como resultado el script introopengl.py, a lo que posteriormente se le añadió la representación de sus vértices y coordenadas de estos en introopengl_vertices.py, para finalmente probar a dibujar una línea recta a partir de dos puntos conocidos en introopengl_linea.py.
Como resultado de esta secuencia de cambios en los scripts para probar distintos aspectos, se obtuvieron los siguientes resultados gráficos:
En estos scripts se cambiaron distintos parámetros de unos a otros, como el ancho de la ventana en la que se mostraban los resultados, pero generalmente, se puede diferenciar la siguiente estructura:
Clase
IntroduccionOpenGL
: Que se encarga de la configuración de la ventana y la inicialización de los parámetros de OpenGL, y que incluye las siguientes funciones, que variarán dependiendo del script:__init__
: Se encarga de inicializar una instancia de esta clase, configurando específicamente la ventana de OpenGL donde se realizarán los dibujos.init_gl
: Que inicializa parámetros básicos de OpenGL como el color de fondo y el test de profundidad.display
: Se encarga de renderizar (dibujar) la escena cada vez que es necesario.draw_vertices
: Dibuja los puntos de los vértices y sus coordenadas como texto.draw_text
: Dibuja texto en la pantalla en la posición especificada, y que en el script introopengl_vertices.py serán las coordenadas de los vértices de las figuras.run
: Inicia el bucle principal de GLUT.
SEMANA 50 (20/05/2024-26/05/2024)
-
Pruebas con otro criterio para ubicar la cámara en el script pinhole.py
Con el fin de averiguar el motivo por el cual la percepción del EJE Y a través de la cámara es la contraria a la real, tal y como se mostraba anteriormente en la SEMANA 48, se probó a rotar la cámara 180º mediante software a través del propio script pinhole.py, tal y como venía predefinido para el script dada la utilización de una Pi Camera para Raspberry Pi como uso inicial de este script.
En esta imagen se muestra como se queda comentado el código utilizado para que esta rotación de 180º no tenga lugar, que es tal y como se ha considerado hasta ahora para toda la toma de datos.
Al ejecutar el script con esta rotación se muestra lo siguiente a través de la ventana para la detección:
Tras comprobar esto, se volvieron a llegar a cabo las pruebas para corroborar si variando este parámetro junto con el criterio seguido para ubicar la cámara (signo de la distancia de la cámara a la mesa y signo del ángulo de rotación de la cámara) se conseguían datos aproximados a los reales.
En primer lugar, se ejecutó el script considerando la distancia de la cámara positiva y el ángulo de rotación negativo, siendo este ángulo el mismo que se había obtenido al restar a 90º de rotación el ángulo que se estaba utilizando hasta ahora (ángulo que forma la horizontal con la dirección de la lente).
Y probando a rotar 180º mediante software la cámara con estas consideraciones:
Posteriormente, basándome de nuevo en los comentarios del script pinhole.py en los que se especificaba junto a los ángulos requeridos para calcular la matriz de rotación, que estos ángulos son representados "considerando que la cámara (en vertical) está rotada 90º sobre eje Y", y tomando en consideración el ángulo de rotación negativo, se consideró utilizar el ángulo en negativo según el esquema:
Y obteniendo los siguientes resultados tanto rotando 180º la cámara como sin esta rotación, sabiendo que el valor de alfa es -25º, y por tanto el valor total del ángulo utilizado con estas suposiciones es de -115º:
CONCLUSIONES: Después de elaborar todos estas pruebas, se puede apreciar que los únicos resultados que se pueden considerar similares a las medidas reales son los obtenidos con un valor positivo de la distancia en el eje Z de la cámara a la mesa y un valor negativo del ángulo total (-115º) utilizado para el cálculo de la matriz de rotación, a pesar de presentar el signo opuesto en las medidas sobre el EJE X, es decir, obteniéndose para este criterio de parámetros un resultado similar en cuanto a valores numéricos en valor absoluto, pero siendo negativos en lugar de positivos como deberían ser, dadas las suposiciones del sistema de coordenadas para este eje, y siendo similares en signo y magnitud para los resultados estudiados a lo largo del EJE Y. Esto supondría que la disposición del sistema de coordenadas para este criterio fuera el mostrado en la siguiente imagen, pero sería distinto al supuesto en un principio, y pese a haber considerado la distancia de en el eje Z de la cámara a la mesa de trabajo positiva, según los ejes de coordenadas, debería ser negativa.
De igual manera, los resultados obtenidos con el criterio de uso del valor positivo de la distancia en el eje Z de la cámara a la mesa y un valor negativo del ángulo (-65º) utilizando el ángulo que resultaba de restar estos 90º de rotación menos el ángulo que se estaba utilizando hasta ahora (ángulo que forma la horizontal con la dirección de la lente) y una rotación de la cámara de 180º impuesta mediante software en el propio script pueden observarse que, pese a guardar la relación en cuanto al sistema de coordenadas, aumentando su valor en el EJE X cuanto más se alejaba en este eje, los valores obtenidos distan de parecerse a los obtenidos con la disposición contraria en cuanto a criterio (Z de la cámara negativa y mismo ángulo pero en positivo), los cuales se consideran más similares a los valores reales.
-
Pruebas con otra inclinación de cámara en el script pinhole.py para calcular las coordenadas del mundo real a partir de coordenadas de imagen utilizando una única cámara calibrada basada en geometría analítica mediante un visualizador de puntos en vídeo
Después de llevar a cabo estas pruebas, se volvió al criterio que se había seguido en semanas anteriores, obteniendo los primeros resultados válidos, pero esta vez se varió la inclinación de la cámara, para comprobar si esta criterio era consistente y con una inclinación distinta.
En esta ocasión, el valor del ángulo alfa, es decir, del ángulo que forman la horizontal con la cámara, era de aproximadamente 16º, lo que daba como resultado un ángulo total para el su uso en la matriz de rotación de 74º (90º - 16º = 74º), y con el cual se obtenían los siguientes resultados:
Lo cuál refleja que el cálculo del ángulo en esta ocasión fue más certero, puesto que los resultados obtenidos se acercaron bastante más a los reales que en la anterior ocasión, con el ángulo de aproximadamente 25º de inclinación de la cámara, y demostrando que los valores obtenidos son buenos tanto a lo largo del EJE X como a lo largo del EJE Y, como se muestra en las tablas y en el vídeo Prueba de pinhole con otro angulo en EJE Y.mp4, que muestra cómo se detecta el post-it a lo largo del EJE Y, y los resultados que se obtienen en las distintas posiciones, que son los reflejados en las tablas.
-
Modificaciones en el script pinhole para mostrar la reconstrucción de la figura geométrica detectada a partir de varios puntos
Para poder unificar los scripts con los cuales se calcula la distancia a los puntos detectados (pinhole.py) y en el cual se utiliza OpenGL para generar figurar geométricas a partir de puntos obtenidos (introopengl_linea.py), se elaboró el scrip pinhole_modificado.py.
Para ello, en primer lugar, se modificó el hecho de que se detectase únicamente un punto simultáneamente y se mostrase por pantalla, para que se detectasen todos aquellos puntos que cumplieran con la premisa del color, modificando la función
detect_color
para que devolviera todos los centroides de los contornos detectados, procesándolos para calcular sus coordenadas 3D y la distancia a la cámara, y dibujando todos los puntos y sus distancias en el frame.Lo siguiente que se llevó a cabo fue diferenciar varias detecciones, de tal manera que al mostrarse a la vez por pantalla, se pudieran identificar con letras y números, siguiendo estas etiquetas la siguiente nomenclatura: P1, P2...
Para combinar el procesamiento de detección de puntos con OpenCV y la visualización de figuras geométricas usando OpenGL, se usó PyOpenGL para manejar la visualización de OpenGL en conjunto con OpenCV para la detección de puntos, quedando el script estructurado de la siguiente manera:
-
Configuración de OpenGL: Se inicializa una ventana OpenGL usando
glutInit
, y se configuran los parámetros de visualización como el color de fondo y las matrices de proyección y modelo. -
Detección y Agrupamiento de Puntos: La función
getPoints
se encarga de detectar los puntos, agruparlos y transformarlos a coordenadas 3D. Estos puntos se almacenan enpoints_to_draw
. -
Visualización con OpenGL: La función
display
se encarga de dibujar los puntos y las líneas que los conectan en la ventana de OpenGL. Los puntos detectados se dibujan como puntos y se conectan con líneas. -
Bucle Principal: En el bucle principal, se capturan los frames de la cámara, se detectan los puntos, se agrupan y se transforman, y se actualiza la ventana de OpenGL.
Sin embargo, al ejecutar el script y probar a poner tres puntos, estos sí que eran detectados y diferenciados, pero no se conseguía dibujar nada en la ventana destinada a esto con OpenGL.
-
SEMANA 51 (27/05/2024-02/06/2024)
-
Pruebas con OpenGL y generación de figuras geométricas mediante puntos
Dado el problema que se daba a la hora de intentar modificar el programa pinhole.py para que en el mismo script también se reprodujeran las formas detectadas de un color definido en OpenGL, se optó por probar a elaborar en primer lugar un script en python que se denominó OpenGL_Unificado.py, que utilizaba OpenGL y en el que se muestran las figuras geométricas que se formaban a partir de una serie de puntos recibidos (simulando los detectados).
Pruebas OpenGL_Unificado.mp4 es el video en el que se muestra el funcionamiento de este script, y en el cual se puede apreciar como en función de los puntos aleatorios que se generen, se genera de igual forma una figura geométrica distinta.