sábado, 8 de mayo de 2010

Detección de fichas en el tablero

    Para detectar las fichas en el tablero, hay dos opciones:

    1ª) Partir de una posición inicial conocida. Detectamos los cambios en la imagen después de que se produzca movimiento. En la imagen diferencia, comprobamos si hay fichas.

    2ª) No partimos de posición inicial. Detectamos todas las fichas después de cada movimiento.

 

1ª IMPLEMENTANCIÓN

En un principio, nosotros escogimos la 1ª opción. ¿Qué es más fácil, detectar en una “imagen diferencia” 2 fichas, o detectar todo el rato todas las fichas en la imagen general?

Siguiendo este principio, desarrollamos el programa detectando los movimientos de fichas. Cuando terminamos de implementarla, encontramos 2 problemas serios.

1) Teníamos que empezar el juego con el tablero vacío, e ir colocando las fichas. No se podía comenzar con el tablero vacío.

2) La imagen diferencia, pese a umbralizarla (pasarle un cvThreshold), tenía ruido.

Para detectar las fichas en la imagen diferencia, utilizamos una trasformada de Hough (cvHoughCircles). Al haber ruido, la diferencia de imagenes no era perfecta, y por lo tanto los círculos no eran perfectos. La detección de círculos aplicando la transformada de Hough, a pesar del ajuste de parámetros, tenía falsos positivos y un porcentaje considerable de fichas no detectadas.

El resultado de esta implementación fue un modelo funcional, pero que no cumplía con los objetivos del proyecto. Tener que repetir jugadas y que se detectaran trampas cuando no las había, era aspectos que no podíamos permitirnos.

Voy a poner sólo la parte del código de detección de círculos, ya que el resto no merece la pena, entre otras cosas porque hay una implementación mucho más eficaz que se expondrá a continuación.

 

2ª IMPLEMENTANCIÓN

Visto los problemas del modelo anterior, teníamos que conseguir varios objetivos:

1) Poder arrancar el programa con las fichas en cualquier posición. La partida no empezaría hasta que las fichas estuvieran colocadas como corresponde en el juego de damas.

2) Detección de fichas con una fiabilidad del 100%. Si no se detecta una ficha, el programa no puede seguir funcionando, por lo que hay que detectar las fichas siempre.

Para cumplir el primer objetivo, estaba claro que había que tener una imagen del tablero vacía para poder hacer una diferencia entre imágenes, y sacar las fichas. El problema era tener esa imagen. No nos valía sacar una imagen del tablero vacío y guardarla para comprar, ya que la imagen del tablero va a variar en cada ejecución del programa. Además, volveríamos a tener el problema del ruido de antes.

Y entonces se nos ocurrió: ¿por qué no nos dibujamos, en tiempo de ejecución, el tablero, ya que tenemos las coordenadas de cada casilla? Así compararíamos con un tablero ideal vacío y nos quitaríamos el problema del ruido.

 

Cumplido el primer objetivo, nos quedaba el segundo. Juancho, nuestro tutor, nos dio una idea que sería vital: ¿por qué no buscáis las fichas casilla por casilla? Si tenéis donde están las casillas, buscar dentro de cada casilla la ficha. El problema era que aún así, la transformada de Hough no era 100% fiable. Pero, ¿de verdad necesitábamos la transformada de Hough? Es decir, ¿de verdad vamos a querer distinguir si lo que hay dentro es una ficha redonda y tenerla en cuenta, de una ficha de cuadrada o triangular? Nosotros jugaremos con fichas redondas, pero puede que alguien juegue con fichas triangulares o cuadradas.

Así que el problema que teníamos, quedó solucionado de una manera muy sencilla. Recorremos todas las casillas donde pueda haber una ficha (recuerdo que en las damas solo se utilizan las casillas de un color, en nuestro caso las de color blanco), y comprobamos el porcentaje de color negro que hay. Para establecer el radio minimo y maximo tenemos en cuenta lo siguiente: la imagen sobre la que trabajamos es de 480x480 (la webcam las coge de 640x480, aunque podría ser de cualquier tamaño, pero luego nosotros la recortamos a 480x480), y el tablero como tiene 8x8 casillas iguales, tenemos que la dimensión de cada casilla es de 60x60. Luego el radio máximo será de 30 px. Pero como las fichas suele ocupar la mitad de la casilla, tenemos un radio aproximado de 15px. Los límites que establecimos fue un radio minimo de 5px y uno máximo de 25px. ¿Por qué el radio máximo? Si la casilla supera un porcentaje de negro mayor a una ficha de 25 px de radio, es que la casilla es toda negra, y eso será una detección errónea (seguramente hayamos detectado mal el movimiento, y haya un objeto encima de esa casilla).

Por tanto, estableciendo los límites de negro entre  pi r_min^2 y pi r_max^2 para r_min = 5 y r_max = 25, establecemos si hay una ficha o no en la casilla.

Esta implementación nos ha dado unos resultado de fiabilidad bastante sorprendentes, ya que la fiabilidad podemos calificarla como del 100%.

 

DISTINGUIR FICHA BLANCAS Y NEGRAS

Para distinguir fichas blancas y negras (en nuestro caso, de momento, azules y negras), lo que hacemos es:

- Umbralizamos la imagen diferencia con un threshold alto para que solo queden las fichas negras.

- Detecamos las fichas negras.

- Hacemos una sustitución de color de azul a negro en la imagen diferencia.

- Eliminamos las fichas negras (que hemos detectado anteriormente)

- Detectamos fichas negras (que serán las azules que hemos convertido a negro).

 

 

** Tengo que subir las imágenes y el código, que lo haré el próximo día reeditando el post.

No hay comentarios:

Publicar un comentario