Páginas

viernes, 3 de abril de 2015

Reconocimiento de Patrones en Java (II)

Si recordamos la entrada anterior estuvimos buscando en un primer momento cómo reducir la información de una imagen que estaba en color, convirtiéndola a una imagen binaria (blanco y negro puros) basándonos en una función umbral.

Ahora, ha llegado el momento de ver de qué maneras podemos identificar figuras en una imagen. En nuestro caso, por simplicidad y dado que está muy bien explicada la idea en este videotutorial vamos a tratar de identificar números.

Para ello, vamos a partir de una serie de patrones de cada número:


Para este ejemplo no vamos a entrar en técnicas complicadas y vamos a presuponer dos supuestos:
  • La imagen a identificar tiene el mismo tamaño que cada imagen que usamos como patrón (8x8)
  • La imagen a identificar ya está en formato binario (podemos aplicar lo mostrado en la entrada anterior para lograrlo).
¿Cuál es la manera más simple de conseguir esto? Comparando pixel por pixel.

El algoritmo en pasos sería el siguiente:
  • Primero recogemos todos los patrones de cada número (hay 9 imágenes de cada patrón) y almacenamos el array de pixels de cada patrón. Ya comentamos que al ser binaria la imagen solo nos encontraremos dos posibles valores en cada pixel.
  • Luego convertimos a un array de pixels la imagen binaria de la que queremos averiguar el número que se oculta tras de ella.
  • Comparamos los patrones de cada número con la imagen a averiguar, y almacenamos el número total de pixels que coinciden. Es decir, del número 0 tenemos 9 patrones, comparamos los pixels de cada uno de esos 9 patrones uno a uno con la imagen y si coincide aumentamos el contador. Al final de esa iteración tendremos el número de pixels que coincide con los patrones del número 0, y lo hacemos con el resto de números.
  • Luego analizamos qué número tiene más coincidencias y ese es nuestro ganador.

El código de la implementación en Java lo podéis descargar de aquí:

Si ejecutamos el código tal cual lo subí, veremos como a partir de la imagen:


Obtenemos:


El problema nos lo vamos a encontrar, en que a veces los patrones nos van a dar un resultado equivocado, porque el método no deja de ser demasiado arcaico (aunque podéis probar y veréis que muchas veces acierta).

Si por ejemplo empleo esta imagen:


Obtenemos:


En lugar de un 8, nos ha detectado un 0. Por lo general, para asegurar un buen resultado las coincidencias tienen que superar las 400 coincidencias. (Estamos hablando que 9 imágenes de 8x8, son 8x8x9 = 576 pixels) lo que sería sobre un 69% de coincidencia, teniendo en cuenta que el 100% es imposible.

Problemas de este método:
  • Se requieren numerosos patrones para comenzar a poder comparar, con uno o dos patrones solo, probablemente los resultados serían muy malos. Cuantos más patrones tenemos mejores resultados obtenemos, pero si son muy diferentes entre sí, nos pueden llegar a falsear los resultados.
  • El algoritmo en su estado actual no permite ni escalado ni rotación, es decir no podemos comparar nada que no tenga el tamaño de los patrones, para eso tendríamos que hacer una función que nos escale y adapte el tamaño de la imagen, al tamaño de los patrones.
  • El algoritmo no soporta centrado. Es decir si en vuestros patrones habéis pintado el 9 muy a la izquierda de la matriz de los 8x8 px, y yo pinto en mi imagen el 9 pegado a la derecha, probablemente nos va a encontrar otro número que no sea el 9. Esto se podría solucionar empleando algún tipo de función de centrado.
En general por lo que he visto investigando un poco hasta ahora, es que ya hay algoritmos que se basan en uso de redes neuronales u otras maneras de aprendizaje, en la que el algoritmo está constantemente aprendiendo. También se emplea mucho la libraría OpenCV para estos menesteres. Pero de esto ya hablaremos en alguna de la siguientes entradas ;)


No hay comentarios:

Publicar un comentario