miércoles, 27 de mayo de 2015

Fallos en la reconstrucción

Como se observa en la siguiente imagen, en la reconstrucción se cometen algunos fallos a la hora de calcular los puntos 3D del mundo. Los más evidentes son los que están señalados en la imagen:

Después de realizar diferentes pruebas, se ha comprobado que esos puntos erróneos no se producen porque los rayos de retroproyección se encuentren muy alejados unos de otros, sino que son debidos a una mala correspondencia de los puntos. Si nos fijamos en las zonas donde se realiza la correspondencia, se observa que todos los puntos del borde son exactamente iguales, por lo que es imposible realizar una correspondencia correcta.

Por lo tanto, según se van recorriendo los píxeles del borde en la imagen izquierda, siempre le hace corresponder el mismo punto en la imagen derecha, lo que produce esos puntos incorrectos.


lunes, 4 de mayo de 2015

Pica 0

En este último paso de nuestro algoritmo se ha implementado la automatización de seleccionar los puntos de interés en la imagen izquierda y la correspondencia en la otra imagen.

Lo primero que se ha hecho después de hablar con algunos compañeros es modificar los archivos xml de calibración de las cámaras y el pioneer.h para utilizar las imágenes con una resolución de 640 x 480 para evitar estar cambiando de resolución constantemente.

Tomando como punto de partida el código del pica 1 se ha implementado lo siguiente:

- Se ha aplicado el filtro de Canny tanto a la imagen izquierda como a la imagen derecha que se obtienen de las cámaras.

- Se recorre la imagen izquierda y se toman como puntos de interés los píxeles que se encuentran en blanco, que son los puntos de borde de los objetos.

- Tomamos un parche de tamaño 11 x 11 centrado en el píxel del punto que se borde para compararlo posteriormente con los parches de la imagen derecha.

- Una vez seleccionado un punto de la imagen izquierda, se genera el rayo de retroproyección que pasa por ese pixel.

- Se cogen dos puntos del rayo de retroproyección y se proyectan sobre la imagen derecha.

- Estos dos puntos se encuentran en la línea epipolar. Utilizando la ecuación punto pendiente de la recta se calcula dicha línea.

 - Se recorre la línea epipolar teniendo en cuenta solo los puntos que también son borde en esta imagen. Para cada punto que es borde se extrae un parche de 11 x 11 y se compara con el parche de la imagen izquierda utilizando la suma de diferencias cuadradas.

- En caso de que ningún parche de la imagen derecha supere un cierto umbral, ese punto de descarta y no se generará en 3D.

- Para el píxel de la imagen derecha que más de parezca al patrón, se genera el rayo de retroproyección.

- Por último, se calcula el punto de ambos rayos en el que la distancia entre ellos sea mínima. Obtenidos estos puntos, se calcula el punto medio y ese será nuestro punto 3D.

En el siguiente video se muestra la velocidad y la calidad de la reconstrucción obtenida:


domingo, 19 de abril de 2015

Pica 1

El objetivo de esta parte de la reconstrucción es encontrar en la imagen derecha la correspondencia del punto que seleccionamos de forma manual en la imagen izquierda.

Los pasos seguidos para cumplir el objetivo son los siguientes:

- Seleccionar en la imagen de la cámara izquierda el punto que se quiere corresponder.

- Se almacena un parche de 7x7 píxeles centrado en punto seleccionado.

- Retroproyectamos el punto 2D.

- Calculamos dos puntos 3D utilizando la ecuación paramétrica del rayo de retroproyección.

- Se proyectan los puntos calculados en el paso anterior en la imagen de la derecha.

- Se calcula la ecuación de la linea epipolar utilizando los dos puntos proyectados.

- Se comparan los parches que se obtienen a lo largo de la línea epipolar con el parche almacenado. La comparación se realiza mediante diferencia de cuadrados, por lo que el parche más parecido al patrón es el que menor valor devuelva.

- Una vez obtenida la correspondencia en la imagen derecha, se retroproyecta igual que se hizo en el Pica 2 y se obtiene el punto 3D intersecando los rayos.

A continuación se muestra un video con los resultados obtenidos:


sábado, 18 de abril de 2015

Pica 2

Como ya se ha comentado anteriormente, nuestro primer objetivo es conseguir realizar con éxito la tarea Pica 2.

En esta primera iteración de la solución global el usuario tiene que seleccionar de forma manual un punto de una de las imágenes y su correspondencia en la otra. En nuestro caso las imágenes tienen el siguiente aspecto:

Una vez que se han seleccionado el mismo punto en las dos imágenes, se hace la retroproyección de estos puntos. Al hacer esto obtendremos un rayo que pasa por el centro óptico de la cámara y por el punto 3D que estamos buscando.

En la imagen se observan los rayos de retroproyección generados.

Por último, hay que calcular el punto en el que los rayos de retroproyección se cortan, ya que es ese el punto 3D que ha generado ambos rayos. En la práctica, es muy difícil que estos rayos se corten, ya que la calibración de las cámaras no es exacta y tampoco es totalmente precisa la selección de la correspondencia de los puntos en ambas imágenes. Por lo tanto, es necesario obtener los puntos de dichos rayos que minimizan la distancia entre ellos, y una vez obtenidos, calcular el punto medio del vector que los une.

Pic_d2lines
En nuestro caso los rayos serian P y Q; y los puntos que minimizan la distancia entre los rayos serian P(Sc) y Q(Tc).

Para realizar estos calculos se ha utilizado las ecuaciones paramétricas de las rectas y se ha adaptado el algoritmo que se explica en el siguiente enlace: http://geomalgorithms.com/a07-_distance.html

Una vez implementado el cálculo del punto que minimiza la distancia, este es el resultado:
Se observa que donde los rayos "se cortan" se ha dibujado una esfera de color verde.

Práctica 2: Reconstrucción 3D

En esta nueva serie de entradas se explicará el objetivo de la práctica y los pasos que se han seguido para desarrollar la solución.

El objetivo es reconstruir un mundo 3D compuesto por una colección de objetos utilizando un par de cámaras montadas sobre un robot.

Como es un problema complejo, se va a dividir en 3 tareas que se abordarán de forma incremental:

- Pica 2: El objetivo de esta tarea es seleccionar mediante clicks de ratón un píxel en una de las imágenes y su correspondencia en la otra imagen. Una vez conocidas las correspodencias hay que seleccionar el punto de cruce de los rayos retroproyectados, o en su defecto, el punto que minimiza la distancia entre ellos.

- Pica 1: Apoyandonos en el código del punto anterior, el objetivo ahora es seleccionar un punto en una de las imágenes y elegir de forma automática la correspondencia en la otra imagen. Para ello se empleará la restricción epipolar.

- Pica 0: Por último, se implementará el código necesario para realizar la reconstrucción del mundo 3D de forma automática, seleccionando los puntos de interés de ambas imágenes.

jueves, 2 de abril de 2015

Vuelta final

El siguiente paso es adecuar la velocidad de desplazamiento del robot a la carretera que se observa en la imagen.

Para ello se le asigna una velocidad por defecto al robot, que varia de forma fija dependiendo del número de píxeles de carretera que se observan en cada una de las alturas definidas. Para el caso de la línea superior, también se tiene en cuenta la posición del centro observado de la carretera además de eliminar una franja a cada lado de la imagen para que no interfieran las zonas de carretera que se observan que no pertenecen al trazado donde se encuentra el robot.

Debido a que al aumentar la velocidad de desplazamiento el robot adquiere una mayor inercia, se han tenido que ajustar los valores del controlador PID que controla el giro para que el robot se mantenga en la pista. También se ha decidido que si el robot pierde de vista en algún momento la carretera gire en el mismo sentido y velocidad que en el último instante en el que vió la pista.

Con todo esto se ha conseguido dar una vuelta completa al circuito de Montmelo en 2:49 medido con un cronómetro, aunque el vídeo indique que la duración es mayor.


Primera vuelta al circuito

Como se comentó en la entrada anterior, ya tenemos la referencia de dónde se tiene que encontrar la carretera en la imagen en el caso de que nuestro robot se encuentre en la posición correcta.

Para calcular el error lo que se hace es calcular el centro de la carretera en la imagen que recibe el robot en cada una de las alturas que hemos definido y restarle la posición de referencia.

Con el fin de simplificar lo máximo posible el controlador y después de realizar diferentes pruebas, para calcular el giro que tiene que realizar el robot únicamente es necesario utilizar la información que nos proporciona el error de la línea central de la imagen.

El objetivo que se ha fijado en la primera prueba es comprobar que el funcionamiento del controlador encargado del giro se comporta de forma correcta. Para ello se ha fijado la velocidad del robot de forma constante a 20 (para no tener que ocuparnos tanto de la velocidad como del giro en la primera aproximación de la solución), y se ha conseguido completar una vuelta al circuito en unos 9 minutos.




Calculo del error

Después de hacer pruebas, se ha realizado una optimización muy sencilla a la hora de aplicar el filtro HSV a la imagen capturada por el robot.

Dicha optimización consiste en detectar donde se encuentra la línea del horizonte del mundo en la imagen, ya que la parte de la imagen que nos interesa (la carretera) se encuentra en el suelo y no va a encontrarse en ningún píxel superior del horizonte.


Una vez que hemos localizado la altura de esta línea, únicamente aplicamos el filtro HSV a partir de esa altura, lo que nos ahorra aproximadamente la mitad de los píxeles de la imagen.


El siguiente paso consiste en estimar el error que se observa en la imagen de la carretera que observa el robot comparado con algún tipo de referencia. Dicha referencia la encontramos colocando el robot en la recta principal del circuito. En esta posición, el robot se encuentra en la posición ideal, por lo que el error es 0. La referencia la tomamos calculando en que posición se encuentra el centro de la carretera en la imagen.


Debido a que la línea que encontramos nos proporciona más información de la necesaria para nuestro propósito, almacenamos la posición del la línea a 5 alturas diferentes en la imagen. Con esta información ya podemos calcular el error para implementar el controlador PID.


miércoles, 11 de marzo de 2015

Filtro de color

Nuestro primer objetivo es implementar un filtro de color para conseguir segmentar la línea roja del circuito y así conseguir seguirla con éxito.

Partimos de una imagen de entrada como la siguiente:


La primera idea ha sido utilizar el espacio de color RGB para filtrar la imagen. Seleccionando los umbrales adecuadamente se obtiene una imagen bastante limpia, pero en algunas situaciones la línea desaparece:


Por lo tanto, se ha optado por convertir la imagen desde RGB a HSV para hacer el filtro más robusto a cambios de iluminación. El código implementado aplica la siguiente fórmula:


El resultado que obtenemos utilizando el filtro en el espacio HSV es el siguiente:


Se observa que el resultado es mucho mejor que con RGB, por lo que se ha decidido utilizar este método.

domingo, 1 de marzo de 2015

Apertura del Blog

En este blog se irá detallando los pasos seguidos y las dificultades encontradas para conseguir que un robot recorra el circuito de Montmeló siguiendo una línea pintada sobre el mismo.