Showing posts with label Visión Computacional. Show all posts
Showing posts with label Visión Computacional. Show all posts

May 23, 2013

Proyecto Final.

Reconocimiento de caracteres

Link al proyecto en github: Link

Presentación.



 

Reporte

  • Propósito

El propósito del proyecto es el reconocimiento de caracteres en imágenes en base a técnicas de visión computacional. Los caracteres o texto son grabados por una cámara o cargados desde una carpeta si es que ya han sido previamente escaneados.

  • Justificación

La justificación del proyecto son las aplicaciones que tiene, una de ellas la digitalización de documentos.

La digitalización documentos ayuda a preservar documentos importantes (libros, revistas, notas), ahorra el tiempo de tener que transcribir el documento entero.


Esta idea de proyecto la tuve en base al proyecto Gutenberg (Project Gutenberg) el cual digitaliza libros, en su mayoría clásicos, en distintos formatos (txt, html, epub, pdf, etc) y los distribuye de forma gratuita.

Google también tiene en Google books un proyecto de digitalización de libros, solo que aquí si cobran por las descargas.

  • Descripción textual

Básicamente lo que el programa hace es:
  • Obtener los datos de entrada.
  • Un pequeño preprocesamiento.
  • Reconocimiento de caracteres con ayuda de Tesseract.
  • Obtener la salida en forma de un archivo de extensión txt.
  • Convertir ese archivo .txt en un archivo epub.
A continuación se presenta un diagrama para explicar de forma más sencilla el funcionamiento del programa:

ó

La entrada del sistema se puede hacer de dos formas distintas: mediante la cámara web ó cargando imágenes escaneadas previamente desde la carpeta "imagenes" que se encuentra en la misma carpeta que el script. Si se utiliza la opción de la cámara, se abre una ventana que muestra la toma hecha por la cámara web; donde el usuario debe poner a la vista de la cámara el documento que se va a digitalizar, una vez puesto el documento frente a la cámara se debe presionar la tecla "enter" para tomar captura a la imagen, cuando se tengan tomas de las imágenes necesarias se presiona la tecla "esc" para continuar con el proceso.

Captura desde cámara web
En el caso de la cámara web todos los frames o imágenes tomadas se cargan y se recortan de manera de que solamente quede la región de interés, que en este caso es el texto.
Región de interés

Después a las imágenes recortadas o escaneadas se les aplican unos filtros (escala de grises y binarización) esto con el fin de que el motor de reconocimiento tenga imágenes más sencillas de reconocer. Cabe aclarar que obtuve mejores resultados cuando solamente cambiaba a escala de grises que cuando aplicaba ambos filtros.

Imagen procesada

Una vez procesada la imagen actual se llama a Tessaract OCR para que realice el reconocimiento de caracteres con la función image_to_string. Al final el texto que se alcanzó a reconocer (cabe aclarar que un motor de reconocimiento de caracteres no es perfecto) se guarda en un archivo .txt y por último se llama a un módulo que cree, el cual utiliza el módulo ez_epub y epub, los cuales al recibir un archivo de texto lo convierten en un archivo .epub que se puede visualizar desde un dispositivo móvil.

          


Hice distintas pruebas y como es ovbio cuando se capturan imágenes de la cámara entre más grande este la letra se realiza una mejor detección lo cual no es bueno si se considera que los libros tienen un tamaño de letra de 10 o 12.


  • Librerías utilizadas

OpenCV: El módulo de OpenCV para python lo utilicé para usar cámara web, cargar imágenes y para aplicar los filtros de escala de grises y binarización a las imágenes.

os: proporciona una manera de emplear funciones del sistema operativo. Este módulo lo utilicé para crear y remover carpetas y el archivo .txt.


glob: este módulo permite buscar todos los nombres de las rutas que coincidan con un patrón especificado de acuerdo con las reglas utilizadas por el shell de Unix. Lo utilicé para cargar todas las imágenes que se almacenaban en las distintas carpetas.

Pytesser: PyTesser es un módulo de reconocimiento óptico de caracteres de Python. Toma como entrada un archivo de imagen o la imagen y da salida a una cadena. De este módulo utilicé la función image_to_string a la cual se le proporciona una imagen y retorna la cadena de texto que pudo reconocer.

Image: es un módulo para procesamiento de imágenes para el intérprete de Python. Este módulo lo utilicé solamente para cargar las imágenes que se pasan al motor Tesseract.

ez_epub y epub: son una pequeña biblioteca de python para generar libros en formato EPUB.

 
Llegué a utilizar el motor Tesseract debido a que mis primeras aproximaciones fueron detectando caracter por caracter en una imagen. En un entrenamiento se detectaban todos los caracteres:

Detección caracter por caracter

Al momento de detectar cada caracter aumentaba su tamaño, se detectaban los contornos de cada detección (fuese una sola letra o más) y tanto las coordenadas de los contornos como la letra a la que pertenecen los contornos se se almacenaban en dos archivos de texto distintos pero en orden de manera que coincidieran. Después utilizando el algoritmo K-nearest neighbors implementado en OpenCv se le proporcionaba los contornos y las letras y se guardaba un modelo. Pero esta implementación no daba como resultado ni un 10% del texto debido a que en muchas ocasiones no se detectaban letras solas sino en un conjunto y además cuando se pasaba a obtener el texto el algoritmo K-nearest obtiene el más parecido a los contornos que se le pasen como parámetro por lo que no es muy preciso sino se ha entrenado bien el modelo.
Imagen de entrenamiento

También hice una implementación utilizando un método de correlación pero de igual manera no obtuve resultados satisfactorios.
Entrada: SERIF, salida obtenida:flflo

Después de esto también noté que influye mucho el tipo de letra, el espaciado y el tamaño de letra por lo que crear un motor propio iba a requerir mucho tiempo de entrenamiento.

Una implementación extra que intenté realizar fue corregir el ángulo de las imágenes cuándo éstas estuvieran inclinadas pero no pude realizarlo correctamente, el script que realicé se encuentra también en el git del proyecto con el nombre de "ocrprep". Estas son algunas de las pruebas:
Imagen original

Imagen procesada


Prueba utilizando cámara:


Prueba utilizando imágenes escaneadas

Imagen original
Imagen procesada



Archivo .epub:




Evaluación de desempeño

Como mencione anteriormente al utilizar el reconocimiento con la cámara entre más pequeña la letra el reconocimiento era peor, por lo que mi evaluación de desempeño se basó en eso.

Realicé una gráfica que compara los errores y aciertos durante la detección de caracteres. Utilicé 6 pruebas con el mismo tipo de letra ("Arial") pero distinto tamaño (10, 12, 14, 18, 24, 30).

Estos fueron los resultados:

Tamaño de letra Aciertos Errores Total
10 5 15 20
12 7 13 20
14 7 8 15
18 7 8 15
24 14 6 20
30 17 3 20



Como se puede apreciar en la gráfica entre más grande es la letra la detección fue mejor, pero esto también depende de que tan bien esté enfocada la cámara y cómo termina procesada la imagen con los filtros.

  • Trabajo a futuro 

Ahora mismo mi intención solo es mejorar la parte del proyecto que toma las imágenes escaneadas ya que me parece más sencillo y más útil, además el convertir a .epub me sirve mucho para leer en el teléfono móvil. Algunas de las mejoras o ideas que se pueden aplicar a este proyecto es:
  • Mejorar los filtros para obtener al 100% la detección de caracteres mediante Tesseract OCR.
  • Agregar de manera automática los capítulos de cada libro.
  • Mejorar el módulo para corregir el ángulo de las imágenes escaneadas.

Fuentes.

May 16, 2013

Laboratorio 10. Detección de movimiento

Para esta entrega se nos pidió hacer una implementación de detección de movimiento, sin utilizar librerías de visión, utilizando una secuencia de video.

Para realizar esto hice uso de OpenCV para hacer la captura de video desde mi cámara web con el siguiente script que lo único que hace es tomar un video de 50 frames y guardarlo con el nombre de "video.mp4":

Código


Después volví a utilizar OpenCV para leer este video y hacer la detección de movimiento.

Para realizar la detección de movimiento lo primero es obtener los cambios de posición que ocurrían entre 2 frames consecutivos, calculando la diferencia entre cada frame, esto es, restar ambos frames pixel por pixel para obtener solamente los pixeles que sufrieron cambios.

Después se aplican filtros de escala de grises y binarización pero esta vez estos filtros los manejé con arreglos de numpy para hacer más ágil la detección ya que para mi primera aproximación mi meta era hacer la detección al momento de obtener cada frame de la cámara, pero se me hizo más fácil primero grabar el video y después realizar la detección.

Los filtros siguen los mismos principios, la escala de grises hace un promedio de los valores r,g,b de cada pixel y la binarización tiene como umbral un entero 10 donde cada pixel arriba de este umbral se convierte a blanco.

Como resultado de este procedimiento resulta una imagen con pixeles en color negro donde no hubo ningún cambio y pixeles en color blanco donde existe algún cambio.

Después de esto se toma el frame original y el arreglo con binarización, que es la imagen binarizada, y se comparan, donde existan pixeles blancos (como son arreglos se buscan valores de 255) son cambiados en el frame original por un color azul. Esto para demostrar que existe un cambio de posición en los objetos del video.

Por último de nuevo se toma el frame original y el arreglo con binarización y ahora se recorre el arreglo pero esta vez por regiones para marcar con cuadros de color verde las regiones donde exista movimiento.

Código

Resultados

Video Original


Resta de frames


Detección de movimiento




Video Original



Detección de movimiento 

Fuentes

May 9, 2013

Deteccion de esquinas

Para esta semana el objetivo para laboratorio era detectar las esquinas de imágenes, como parte básica, después unir estos puntos de manera que formen la figura original.

Para la parte de detectar esquinas lo que realicé fue lo siguiente:

  • Convertir la imagen a escala de grises.
  • Aplicar un filtro mediano, esto es recorrer la imagen, para cada pixel guardar sus vecinos en una lista incluyéndolo, ordenar la lista y tomar el pixel que se encuentre en el centro de la lista.
  • Tomar la imagen en escala de grises y la que se le aplicó el filtro mediano y restar ambas imágenes, lo que da como resultado las esquinas de la imagen.


Ya teniendo esto lo que hice fue utilizar bfs tomando como punto de partida cada una de las esquinas para obtener de esta manera los bordes de la imagen, ya que por obvias razones las esquinas están dentro de los bordes.

Después busco cada coordenada de las esquinas en las coordenadas arrojadas por el bfs y calculo su ángulo, así como en la detección de líneas, para de esta manera conocer el orden en que se van a unir las líneas. Obteniendo los ángulos solo falta ordenar el arreglo para que siga el orden correcto.

Código:



Imágenes:






April 25, 2013

Laboratorio 7. Histogramas laterales para detectar agujeros

Para esta entrada se trabajó con un preprocesamiento para detectar agujeros. Se trabajó con las intensidades de color de filas y columnas de una imagen.

Un agujero es un orificio de forma aproximadamente circular, esto quiere decir que cuando existe un agujero hay un cambio de intensidad de luz lo cual facilita detectar utilizando histogramas.

Los histogramas nos permiten reducir el espacio de búsqueda y encontrar donde existen los cambis de intensidad.

Para obtener el histograma horizontal basta con sumar los pixeles de las filas y para el histograma vertical se suman los pixeles de las columnas.

Por ejemplo de la siguiente imagen:


Se obtiene este histograma:



Después de obtener el histograma se tenía que dibujar en las imágenes líneas rectas para cada uno de los picos de cada histograma lateral.

Lo primera idea fue obtener un promedio para establecerlo como rango y todos los puntos que estuvieran debajo de ese rango serían los posibles agujeros pero lo que obtuve fue lo siguiente:


Como se puede apreciar son demasiadas líneas. Por lo que me puse a ver los histogramas y observé que para obtener un pico sólo es comparar el dato actual con el anterior y posterior, si el actual es menor que el anterior y menor que posterior quiere decir que es uno de los mínimos y ya con esto me trajo mejores resultados:



Código



Más pruebas

  




April 22, 2013

Tarea 6. Detección de agujeros

Para esta entrada el objetivo es detectar la posición de agujeros en una imagen y cumplir con las siguientes especificaciones:
  • Los agujeros detectados se marcan con un borde morado oscuro y un relleno de morado claro.
    • Un tono ligeramente diferente en cada agujero.
  • Se marca el centro de cada agujero con un punto amarillo.
  • Al centro de cada agujero se agrega una etiqueta del ID del agujero.
  • El programa imprime un listado que indica para cada ID el tamaño del agujero (como porcentajes del tamaño de la imágen).
Un agujero es un orificio de forma aproximadamente circular, esto quiere decir que cuando existe un agujero hay un cambio de intensidad de luz lo cual facilita detectar utilizando histogramas.

Los histogramas nos permiten reducir el espacio de búsqueda y encontrar donde existen los cambis de intensidad.

Los histogramas nos sirven como preprocesamiento, para más información en la entrada de laboratorio de esta semana se realizó este procesamiento.

Utilizando el código de la entrada de laboratorio, lo siguiente fue buscar las intersecciones de las líneas por lo que modifiqué un poco la función donde obtengo las coordenadas de los posibles agujeros utilizando cada histograma por separado y lo que hice fue manejar los dos histogramas juntos y de esta manera marcar solamente las intersecciones:

  

Conociendo las intersecciones, después binarizé la imagen para de esta manera utilizando bfs conocer las posiciones de los agujeros y descartar aquellos que en realidad no fueran agujeros ya que los agujeros permanecía generalmente en color negro y fué más sencillo buscar las coordenadas de esta manera. Con bfs también me fue posible determinar el tamaño de cada agujero con respecto a la imagen.

Ya por último solamente fue dibujar sobre la imagen el centro, colorear el círculo y etiquetarlo:
 

Código



Pruebas

 



 



 


April 18, 2013

Laboratorio 5. Relleno de elipses

Para esta entrega de laboratorio se pidió detectar elipses y/o círculos utilizando el  con las siguientes tareas:
  • Identifica cada elipse/círculo individual
  • Rellénalo de un color aleatorio
  • Sigue marcando su centro con bolita & ID con etiqueta
  • Imprime un listado de los áreas de los círculos/elipses
  • En porcentaje de la imagen completa
El procedimiento que seguí fue el siguiente:

  • Preprocesar la imagen utilizando el método de convolución con las máscaras de Prewitt, normalizarla y recorrer la imagen con el algoritmo bfs para localizar los bordes de los elipses,
  • Después de esto se escogen dos puntos aleatorios que están en el borde de cada elipse, estos puntos deben ser antiparalelos y con ellos se pasa a calcular las tangentes.
  • Se calculan las intersecciones de estas tangentes y con ellas se calculan los puntos medios.
  • Luego, se dibujan muchas líneas que pasen por los puntos medios para de esta manera encontrar los posibles centros.
Cabe aclarar que para realizar esta entrega tomé como base el código de mi compañero Max.

Código



Pruebas:

Nota: los porcentajes representan lo que ocupan los bordes del elipse del total de la imagen.
Imagen Original
Prosible centro
Detección






Imagen original

Posibles centros
Detección




Imagen Original


Posibles centros


Detección