jueves, 18 de julio de 2013

Reporte de Proyecto Final

En esta entrada hablaré sobre el proyecto final que mostré en la clase de visión computacional.

El proyecto que elegí fue el reconocimiento de gestos de las manos usando Python y OpenCV en Ubuntu 12.04. Lo más relevante del proyecto se encuentra en la presentación que di en clase, la cual adjunto a continuación:




FORTALEZAS
Con el programa se logra mover el cursor de la computadora y hacer click's derecho e izquierdo.

Lo que descubrí fue que se necesitó menos código del que esperaba. Con relativamente pocas líneas de código, gracias a OpenCV se logra hacer el procesamiento de las imagenes de la mano. En este procesamiento se aplican algunos filtros para lograr obtener una mejor imagen con la cual trabajar y además se realiza el convex hull para, en pocas palabras, rastrear los dedos de la mano.

Para el movimiento del cursor se utilizó xdotool, que como lo dice la página de ubuntu manuals permite simular actividad del mouse, entre otras cosas (http://manpages.ubuntu.com/manpages/lucid/man1/xdotool.1.html)

La combinación del procesamiento en Python+OpenCV y xdotool dió un buen resultado que permite mover el mouse mediante las coordenadas que se obtienen del procesamiento de las imagenes.

DEBILIDADES
Lo que se notó, y se planea mejorar, es la identificación de la mano, ya que el código procesa todos los objetos que se le pongan en frente. Debido a esto, el cursor puede descontrolarse un poco, o se puede dificultar un poco la realización de las demás acciones.

Para esto, así como lo sugirió la Dra. Elisa Schaeffer, sería útil aplicar un filtrado usando el método de medidas de similitud que se usó en las tareas de laboratorio de visión computacional. De esta forma se podría crear una "plantilla" que le diga al programa qué forma debería tener una mano, y así al procesar una imagen, descarte todo aquello que no tenga forma de mano.

PLANES A FUTURO
Mi deseo es entender y aprender más sobre reconocimiento en visión computacional. Esta es un área que me interesa mucho y quisiera poder trabajar más con cosas relacionadas en un futuro.

En cuanto a lo hecho en este proyecto, me gustaría añadir más funcionalidades y me gustaría ver que tuviera un uso provechoso con personas que lo necesiten.

jueves, 11 de julio de 2013

Detección de Agujeros

Para esta tarea lo que hicimos fue detectar agujeros en una imagen. Como van a ver, es algo bastante simple.

TEORÍA
El método para saber si en una imagen hay un agujero (o agujeros) es el siguiente:

1) Realizar la sumatoria de todos los valores de cada fila y cada columna (por separado cada fila y columna) de la matriz de pixeles. Se podrán presentar dos casos:

  • Si hay agujeros oscuros, la suma de la columna y la suma de la fila donde se encuentra el agujero será un valor bajo (colores relativamente más oscuros)
  • Si hay agujeros claros, la suma de la columna y la suma de la fila donde se encuentra el agujero será un valor alto (colores relativamente más claros)
Por si es confuso, la siguiente imagen puede ayudar a entender de qué hablo al decir que se deben realizar las sumatorias de las filas y columnas:



aquí además podemos suponer que hay un posible agujero claro en la intersección de la última fila y la última columna, ya que la sumatoria de la última fila es 30 y la sumatoria de la última columna es 16, ambas son las mayores en relación a todas las demás.

El número de fila y columna se tomarán como coordenadas de referencia para saber en qué pixel hay un posible agujero.

2) Después de tener las coordenadas donde posiblemente hay un agujero, debemos ubicarnos en el pixel con esas coordenadas y usando una máscara definida por nosotros mismos, realizar una convolución como también lo hicimos en el post anterior. La diferencia aquí es que debemos hacer un promedio de los pixeles vecinos. Este promedio se va a comparar contra un umbral establecido por nosotros mismos:

  • En el caso de agujeros oscuros, el umbral debe ser relativamente bajo. Esto porque si se detecta un agujero, el promedio de la vecindad debe ser oscuro.
  • En el caso de agujeros claros, el umbral debe ser relativamente alto. Esto porque si se detecta un agujero, el promedio de la vecindad debe ser claro.
Para fines de simplicidad, se usará una máscara de 3x3 cuyos valores son únicamente 1's


Como vemos, el promedio del pixel y sus vecinos es relativamente alto (mayor a los demás pixeles).
De aquí podemos deducir que encontramos un agujero. ( Cabe remarcar que en los casos donde el agujero es oscuro las sumatorias y los promedios dan valores relativamente bajos).


CÓDIGO
Lo primero es pasar la imagen a escala de grises tal como sucedió en el post anterior. Lo añadido para este programa es que utilizó una matriz de numpy para almacenar los valores de la imagen para poder trabajar más cómodamente.

Sobre esta matriz, podemos usar el método sum, para obtener las sumatorias de filas y columnas.

Para saber qué pixeles son candidatos a ser agujeros se hace lo siguiente para ambos casos:

  • Para agujeros oscuros, se busca un pixel que se MENOR al pixel anterior a él, y al pixel próximo a él.
  • Para agujeros claros, se busca un pixel que sea MAYOR al pixel anterior a él, y al pixel próximo a él.
Esto nos ayuda a quedarnos sólo con los pixeles más oscuros de la imagen.

El código es el siguiente:
///
///

Cuando hay posibles agujeros, dibujo una línea en la columna y otra línea en la fila del candidato.

//

//
Dentro de este mismo ciclo, me aseguro de que el candidato sea en realidad un agujero mediante el promedio de los vecinos. La subrutina que usé para esto es la siguiente:

//

//

Y es todo. Si el método anterior encuentra un agujero, pinta un pequeño cuadrado sobre él.

Los resultados son los siguientes:

Agujeros oscuros:









Agujeros claros:



Aquí el código completo:

jueves, 27 de junio de 2013

Detección de Bordes

Para la primera tarea del curso de verano de Visión Computacional, se nos encargó la detección de bordes de una imagen.

Para llegar a esto primero estuvimos viendo operaciones básicas sobre las imagenes, para lo cual usamos la librería PIL (Python Image Library)

Para instalar esta librería en ubuntu debería ser suficiente la siguiente línea en la consola:

sudo apt-get install python-imaging

________________________________________________________________________
Cabe mencionar que una de las dificultades que se me presentó al trabajar con esta librería fue que el método show() no funcionaba. Esto era porque por default estaba configurado el visor de imagenes xv y hasta donde entendí había algunos conflictos con la instalación. De hecho el archivo Image.py de la librería PIL te menciona que xv ya está obsoleto y que los sistemas más modernos usan imagemagick (en mi computadora este archivo se encuentra en /usr/share/pyshared/PIL/Image.py ).

De ahí fue donde encontré la solución a mi problema: instalar otro visor de imagenes - imagemagick (otra opción era trabajar con pygame o tkinter para abrir las imagenes, pero me ahorré líneas de código al arreglar el método show() ). Para instalarlo solo basta escribir esta línea en consola:

sudo apt-get install imagemagick

Y listo, sin necesidad de mover más archivos, imagemagick abrirá tus imagenes cuando uses el método show().
_______________________________________________________________________

Para lograr la detección de bordes primero fue necesario hacer la imagen a escala de grises. Aquí el código para lograr esto:

-----
----
El método es simple:

Cada pixel de la imagen tiene tres canales: R,G,B. Estos canales tienen valores que van desde 0 a 255. Al recorrer cada pixel se suman estos tres valores y se dividen entre 3 (sacamos promedio). Despues el valor de cada canal se sustituye por este promedio. Eso hace que la imagen se convierta a escala de grises.

Ahora con la imagen en escala de grises es posible hacer la convolucion.

El método de convolución es algo simple. Se crea una matriz (máscara de convolución) de valores que se irá recorriendo por toda la matriz de pixeles.  Esta máscara coloca su centro en cada pixel recorrido.

El pixel en el que estamos colocados, toma el valor de la suma de las multiplicaciones de los valores de la máscara por los valores de los vecinos del pixel donde estamos colocados (y de él mismo).



Este es el código para la convolución:
----

----

El resultado es el siguiente:

Imagen original, gris, y bordes (la imagen random que hicimos en el salón):

Tiempo para esta imagen:



Otra imagen más:





Tiempo para esta imagen:




Y una más (ridículamente grande):



Tiempo para esta imagen:



Y aquí el código completo: