herramienta de reconocimiento de imágenes en python
TRANSCRIPT
Equation Chapter 1 Section 1
Trabajo Fin de Grado
Grado en Ingeniería de las Tecnologías de
Telecomunicación
Herramienta de Reconocimiento de Imágenes en
Python
Autor: Samuel Moreno Fernández
Tutor: Juan José Murillo Fuentes
Dpto. Teoría de la Señal y Comunicaciones
Escuela Técnica Superior de Ingeniería
Universidad de Sevilla
Sevilla, 2020
iii
Proyecto Fin de Carrera
Ingeniería de Telecomunicación
Herramienta de Reconocimiento de Imágenes en
Python
Autor:
Samuel Moreno Fernández
Tutor:
Juan José Murillo Fuentes
Catedrático de Universidad
Dpto. de Teoría de la Señal y Comunicaciones
Escuela Técnica Superior de Ingeniería
Universidad de Sevilla
Sevilla, 2020
v
Trabajo Fin de Grado: Herramienta de Reconocimiento de Imágenes en Python
Autor: Samuel Moreno Fernández
Tutor: Juan José Murillo Fuentes
El tribunal nombrado para juzgar el Proyecto arriba indicado, compuesto por los siguientes miembros:
Presidente:
Vocales:
Secretario:
Acuerdan otorgarle la calificación de:
Sevilla, 2020
El Secretario del Tribunal
vii
A mi familia
A mis amigos y compañeros
ix
Agradecimientos
Quería agradecer a todas las personas que me han acompañado a lo largo de esta bonita etapa y me han
ayudado a alcanzar la meta que me propuse hace tan solo cuatro años.
A mis padres. Mi apoyo incondicional, mi fuente inspiración, quienes confían en mi cuando ni yo mismo soy
capaz, desde el primer momento hasta el último de esta y de cualquier etapa de mi vida solo tuvieron la
intención de ayudarme en no venirme abajo en ningún momento. Se los debo todo. Eternamente agradecido.
A mi hermano, el pequeño de la casa, pero no por ello estoy continuamente aprendiendo de él. Una persona
con un corazón tan grande, que en mis peores momentos incluso lo pasa peor que yo. Siempre estará a mi
lado.
A mis abuelos, se que los que no están aquí estarán profundamente orgullosos de mi desde el cielo, y que sin
su esfuerzo no podría recoger los frutos que ahora estoy recogiendo. Mención especial a mis dos abuelas: una
de ellas nos dejó durante mi etapa como estudiante universitario, y desde aquí le dedico este trabajo por su
tremenda bondad y por ser una abuela ejemplar, Emilia, y a mi otra abuela quien reza cada vez que me
examino para que apruebe, y que ha dado resultado, eres increíble Antonia. Mil gracias.
A mis amigos, no fue fácil el momento en el que cada uno después de Bachillerato cogiera un camino distinto,
pero hoy puedo decir orgulloso que son las personas con las que desconecto de todo, en quienes confio, me río
con ellos y hacen que consiga ese pico de felicidad que hace tanta falta.
A mis compañeros de piso, tantos lo que tuve el primer año como el resto de los años, compartiendo tantos
buenos momentos y remando a contracorriente en las adversidades y épocas de exámenes. Grandes mis
“Bros”.
A mi tutor Juan José, por la atención recibida durante la pandemia vivida durante este curso.
Samuel Moreno Fernández
Sevilla, 2020
xi
Resumen
Este trabajo de fin de grado aporta al lector diferentes funciones para realizarle transformaciones a una imagen
introducida por un usuario. A través de estas transformaciones, el usuario podrá encontrar diferentes objetivos
que se encuentran en este trabajo: Transformada de Fourier, filtrado gaussiano, filtrado de mediana, su propia
visualización 3D… El usuario tendrá una lista con todos los distintos tipos de tratamiento que se puede realizar
sobre la imagen, y es el mismo usuario el que eligirá que transformación que realizará el programa.
Una vez hecha una breve explicación sobre los objetivos, se tratará de explicar el lenguaje de programación en
el que se implementa este trabajo, Python 3.8. Este lenguaje es el elegido para implementar el programa que
llevará a cabo el tratamiento de las imágenes, y se utilizarán distintas librerías como NumPy y Matplotlib, para
conseguir los resultados que queremos.
Tras analizar Python y sus peculariedades, se explicarán las funciones definidas por el programador y todas las
variables utilizadas a lo largo del programa, y el desarrollo de estas en el script GUI_img.py.
Pero todas estas funciones creadas para transformar las imágenes tenemos que configurarlas de alguna manera
para que interactúe con el usuario, y por ello se implementa una GUI (interfaz gráfica de usuario) usando la
librería Tkinter en Python, siempre manteniendo cuidadosamente el tamaño de las imágenes, su relación de
aspecto y sus propiedades para que se plasmen en la GUI sin ningún tipo de alteración.
Finalmente, este programa se compilará para crear un archivo ejecutable .exe que funcione en Windows. Para
ello se utilizará el compilador PyInstaller.
xiii
Abstract
This final degree project provides the reader with different functions to perform transformations on an image
entered by a user. Through these transformations, the user will be able to find different objectives found in this
work: Fourier transform, Gaussian filtering, median filtering, their own 3D visualization… The user will have
a list with all the different types of treatment that can be perform on the image, and it is the same user who will
choose which transformation the program will perform.
Once a brief explanation of the objectives has been made, the aim will be to explain the programming
language in which this work is implemented, Python 3.8. This language is chosen to implement the program
that will carry out the treatment of the images, and different libraries such as NumPy and Matplotlib will be
used to achieve the results we want.
After analyzing Python and its peculiarities, the functions defined by the programmer and all the variables
used throughout the program will be explained, and the development of these in the GUI_img.py script.
But all these functions created to transform the images we have to configure them in some way so that they
interact with the user, and therefore a GUI (graphical user interface) is implemented using the Tkinter library
in Python, always carefully maintaining the size of the images , its aspect ratio and its properties so that they
are reflected in the GUI without any alteration.
Finally, this program will be compiled to create an executable .exe file that works on Windows. For this,
PyInstaller compiler will be used.
Índice
Agradecimientos ix
Resumen xi
Abstract xiii
Índice xiv
Índice de Figuras xvii
1 Introducción 1 1.1 Objetivos 1 1.2 Reconocimiento de imágenes 1
1.2.1 Transformada de Fourier 2 1.2.2 Filtrado de imágenes 2 1.2.3 Visualización 3D y Contorno 2
1.3 Estructura 3
2 Software y diseño 5 2.1 Software 5 2.2 Python 5 2.3 Entorno de Desarrollo Integrado (IDE) 6 2.4 Herramientas de Python 7
2.4.1 NumPy 7 2.4.2 SciPy 8 2.4.3 Os 8
2.5 Herramientas de procesado de imagen 9 2.5.1 OpenCV 9 2.5.2 Matplotlib 9 2.5.3 PIL 9 2.5.4 Imutils 10
2.6 Herramientas GUI 10 2.6.1 Tkinter 10
3 Herramienta y Desarrollo en Python 11 3.1 Objetivo GUI 11 3.2 Variables del programa 12
3.2.1 Definición 12 3.2.2 Variables en Python 12 3.2.3 Variables globales 13 3.2.4 Variables locales 13
3.3 Funciones usadas de librerias 13 3.3.1 Definición 13 3.3.2 Implementación 14
3.4 Diagrama de flujo 18
4 Implementación en Python 19 4.1 Fichero principal GUI_img.py 19 4.2 Variables definidas por usuario 20
xv
4.2.1 Variables globales 20 4.2.2 Variables locales 23
4.3 Módulo principal 23 4.4 Funciones definidas por usuario 26
4.4.1 Get_mouse_posn(event) 26 4.4.2 Update_sel_rect(event) 26 4.4.3 Contour_y_3d() 27 4.4.4 Histograma() 27 4.4.5 NoRecorta() 29 4.4.6 Recorta() 29 4.4.7 Limpiar() 31 4.4.8 ReconocimientoImagen() 31 4.4.9 Choose() 36 4.4.10 Save_file() 38 4.4.11 Imprime_label(event) 40
5 Compilación GUI 43 5.1 Introducción 43 5.2 PyInstaller 44
5.2.1 Compilación programa 45
6 Resultados de la GUI 47
7 Conclusiones y Líneas futuras 63
Referencias 66
Glosario 69
xvii
ÍNDICE DE FIGURAS
Figura 1. Ejecución fichero.py desde Pycharm. 7
Figura 2. Capas GUI. 12
Figura 3. Definición de función en Python. 14
Figura 4. Diagrama de flujos. 18
Figura 5. Fases de la compilación. 43
Figura 6. Análisis léxico. 43
Figura 7. Análisis sintáctico. 44
Figura 8. Instalación PyInstaller. 45
Figura 9. Compilación programa en Python. 45
Figura 10. Inicio de la GUI. 47
Figura 11. Introducción de la imagen a tratar. 48
Figura 12. Inicio con imagen introducida. 49
Figura 13. Inicio con la selección del área recortada sobre la imagen. 50
Figura 14. Inicio con recorte de la imagen. 51
Figura 15. Tratamiento de la imagen, FFT. 52
Figura 16. Tratamiento de la imagen, escala de grises. 53
Figura 17. Tratamiento de la imagen, filtrado gaussiano. 54
Figura 18. Tratamiento de la imagen, imagen ecualizada e histograma. 55
Figura 19. Tratamiento de la imagen, filtrado de mediana. 56
Figura 20. Tratamiento de la imagen, contornos. 57
Figura 21. Guardar imagen tratada seleccionada. 58
Figura 22. Contour y vista preliminar 3D de la FFT. 59
Figura 23. Visualización 3D de la FFT. 60
Figura 24. Inicio, limpieza de imagen. 61
1
1 INTRODUCCIÓN
En nuestro día a día, tanto el ámbito laboral como en el cotidiano, estamos trabajando con imágenes,
visualizando y analizándolas para intentar extraer información de ellas. Además, cualquier persona va
recolectando a lo largo de la jornada imágenes con su cámara o su teléfono móvil, por ejemplo. También estas
personas realizan de manera indirecta una serie de transformaciones a estas imágenes, como un simple cambio
de escala, o un recorte sobre la imagen original.
Los ingenieros de telecomunicaciones se encargan de que este tratamiento de las imágenes sea de la manera
más sencilla posible para la persona que lo necesite. Así, a través de una interfaz gráfica se va a elaborar una
herramienta en la que el cliente podrá realizar transformaciones indirectamente para extraer información de la
imagen. Esta interfaz será sencilla para el público.
Sobre ello trata la Herramienta de Reconocimiento de Imágenes, en la que se hacen una serie de
transformaciones con la imagen que inserta el usuario para conseguir distintos objetivos: FFT, la imagen
ecualizada, su visualización en 3D...
1.1 Objetivos
El objetivo principal del trabajo es implementar un software GUI que pueda ser fácilmente adaptado
para crear un software de procesado de imagen y su posible distribución para uso de terceros. Para
desarrollar esta GUI, utilizaremos la librería Tkinter, y utilizaremos otras librerías como NumPy y
Matplotlib para realizar todas las transformaciones necesarias.
Las transformaciones realizadas han sido estudiadas en el grado, como la Transformada de Fourier, y
plasmaremos los resultados en distintas pestañas de la interfaz gráfica.
Otro de los objetivos será que el usuario pueda interactuar sin ningún tipo de problema con la interfaz, y
que pueda hacerlo entendiendo todo lo que esta manejando sobre el software. Para que esto sea así, el
diseño de la GUI debe estar muy cuidada y ordenada respecto a los widgets (elementos) que la
conforman.
La idea sobre un futuro uso o una posible mejora de la interfaz es aumentar el número operaciones
sobre el procesamiento de imagen (nuevos filtrados, aumento de brillo…) , y que estas imágenes
transformadas imprimirlas o bien en la misma pestaña o tab o crear una nueva pestaña, siempre que
dentro de esta pestaña haya una relación estrecha en el tratamiento de la imagen. De esta manera el
ingeniero que quiera adaptar este software tendrá varias posibilidades de hacerlo.
1.2 Reconocimiento de imágenes
Una vez el usuario introduce la imagen elegida para el tratamiento, la herramienta realiza una serie de
transformaciones a esta imagen, y se obtiene como resultado [10]:
• Escala de grises. Es la misma imagen introducida, pero la gama de colores se reduce a una
escala de grises.
Introducción
2
• FFT. Transformada rápida de Fourier de la imagen que se describe a continuación.
• Filtrado de Mediana. Suaviza la imagen, reduce la cantidad de variaciones de intensidad entre
píxeles vecinos. Consigue que las intensidades de los objetos pequeños se mezclen con el
fondo con el fin de detectar los objetos de mayor tamaño. Elimina ruido.
• Filtrado gausiano. Similar al Filtrado de Mediana, aunque produce un suavizado más uniforme.
• Imagen ecualizada. Eliminación total del ruido.
• Contorno imagen. Líneas que permiten trazar los límites de la imagen.
• Visualización 3D. Representación tridimensional de la figura correspondiente. En este caso, se
realiza una visualización 3D de la FFT de la imagen.
1.2.1 Transformada de Fourier
Es una transformación matemática que transforma señales entre los dominios del tiempo y de la
frecuencia. Hace corresponder a una función f(t) con otra función F(w).
F(w) = ∫ 𝑓(𝑡)𝑒−𝑖𝑤𝑡+∞
−∞𝑑𝑡 , y su transformada inversa
f(t) = 1
2𝜋∫ 𝐹(𝑤)𝑒−𝑖𝑤𝑡+∞
−∞𝑑𝑤,
Las imágenes que conocemos, suelen estar en el dominio del tiempo, y estas la transformaremos para
obtener su resultado en el dominio de la frecuencia a través del uso de distintas librerías.
1.2.2 Filtrado de imágenes
El resultado de cada pixel se obtiene como combinación lineal de sus vecinos. Multiplicamos el entorno
de cada pixel por una mascara, la media ponderada será el nuevo valor del pixel.
Estos filtros operan en el dominio del tiempo.
Dependiendo del tipo de filtrado (mencionados en 1.2), se usarán unas funciones u otras para encontrar
el objetivo.
1.2.3 Visualización 3D y Contorno
Respecto al contorno, consiste en encontrar la silueta o siluetas de todas las figuras distintivas que haya
o se aprecien dentro de la imagen insertada. Estas formas, estarán reproducidas con unas líneas de color
fluorescente.
A través de la visualización 3D, se simula una imagen de dos dimensiones en tres dimensiones. Así,
visualizamos la imagen, que en nuestro caso será la FFT de la imagen insertada por el usuario, desde
3
3 Herramienta de Reconocimiento de Imágenes en Python
diferentes perspectivas.
1.3 Estructura
El resto del presente documento está dividido en 5 capítulos:
• Segundo capítulo: se explicará el lenguaje y la IDE escogida, y todas las librerías usadas para
implementar esta herramienta. Este capítulo tiene una gran importancia para entender la
implementación del programa.
• Tercer capítulo: se hace una introducción general a Python como toma de contacto con el
lenguaje. Este capítulo incluye la explicación del significado de conceptos básicos, tipos de
datos, funciones usadas ya implementadas en las librerías…
• Cuarto capítulo: se combinarán diseño e implementación del funcionamiento del programa. Se
tendrá en cuenta el aspecto de la GUI.
• Quinto capítulo: Compilación en PyInstaller del programa implementado en Python 3.8.
• Líneas futuras y Conclusiones: centradas sobre todo en implementaciones y mejoras que se
pueden realizar a partir de la realización del trabajo. También recapitulará todas las
conclusiones que se hayan podido extraer a lo largo del trabajo y en la implementación del
sistema.
Introducción
4
5
2 SOFTWARE Y DISEÑO
2.1 Software
En la actualidad existen multitud de lenguajes de programación y entornos para desarrollar distintas
aplicaciones y herramientas. Para esta herramienta, vamos a implementar una GUI y hay multiples
lenguajes que nos permiten desarrollar una interfaz gráfica. Entre ellos están Matlab, Java, JavaScript,
C, C++ … y Python. Este ultimo es el elegido para crear nuestra interfaz.
El motivo principal sobre la elección de hacer el problema en Python es porque es un requisito de
partida. Además, es un lenguaje que se focaliza en conseguir una sintaxis fácil de leer, y eso ayudará a
la comprensión total del Código [1].
2.2 Python
Este lenguaje de programación está presente en muchas aplicaciones y sistemas operativos, como iOS,
Windows, Linux, Mac o Android, debido a que tiene una curva de aprendizaje moderada, con un
Código legible.
Es un Código versátil multiplataforma que se destaca por su Código limpio. Su éxito principalmente se
debe a que es un Código abierto, que permite su uso desde cualquier rincón del mundo.
Es importante destacar que en este software se trata con la version Python 3.8 (32 bits), actualmente la
más reciente.
Tiene como características [2]:
• Lenguaje multiplataforma. Se puede usar en distintos sistemas operativos
• Ideal para trabajar con volúmenes de datos muy grandes, favorece el procesamiento, siendo
también el lenguaje utilizado por las empresas de Big Data. Algunas de sus ventajas son:
Sencillez y presteza, selecto, legible, fácil de aprender, organizado, portable y con un gran
número de usuarios que participant activamente en su Desarrollo.
Creo que este es el mejor consejo: piensa
constantemente cómo podrías hacer mejor las cosas.
-Elon Musk-
Software y diseño
6
• Imperativo. Describen el estado del programa y permiten la modificación mediante
instrucciones de Código. Se describe paso a paso un conjunto de instrucciones.
• Funcional. Variación del programa mediante la mutación y el cambio de variables. Así, se
opera con datos de entrada y salida.
• Orientado a Objetos. Los objetos manipulan a otros, para ofrecer una salida específica.
También permite juntar librerías.
• Dinámico. Una variable puede tomar distintos valores de diferentes tipos en distintos
momentos.
Es este el Código que utilizaremos para desarrollar la Herramienta de Reconocimiento de Imágenes,
para poder trabajar con mayor facilidad todos los datos que componen una imagen.
En Python, a los archivos se le coloca la extension .py de forma que se pueden incorporar paquetes.
Esta incorporación de paquetes y librerías se realiza de distintas maneras:
• Mediante el comando import paquete.
• Mediante el comando import paquete.elemento.
• Mediente from paquete import elemento.
• Mediante import elemento as name_elemento, acortando el namespace del element.
2.3 Entorno de Desarrollo Integrado (IDE)
Para que el lenguaje tenga una finalidad final, debemos desarrollarlo en un entorno de Desarrollo
interactivo, que es una aplicación que nos proporciona servicios para facilitar al programador el
Desarrollo software [3].
En este caso, como se ha desarrollado la GUI en Python, se ha escogido el entorno PyCharm. PyCharm
es uno de los entornos de Desarrollo más completos. Cuenta con entornos para construir Código en
distintos lenguajes como PHP o Ruby. Usaremos la versión “Community” que es gratuita. También
para posibles usos futuros, existe el modelo “Professional” de pago, ideal para el Desarrollo web.
El objetivo principal de este IDE es proveer un entorno de programación en Python que se ejecuta de
forma concurrente.
La version utilizada de Pycharm es Pycharm 2019.3.3 (Community Edition).
Pycharm ofrece distintos servicios [3]:
• Asistencia inteligente a Python. Pycharm proporciona una finalización del Código inteligente,
inspecciones del Código, indicación de errores sobre la marcha y arreglos rápidos, así como
refactorización de Código automática y completes funcionalidades de navegación.
• Marcos de trabajo de Desarrollo web. Pycharm ofrece una gran compatibilidad con marcos de
trabajo de Desarrollo web modern como Django, Flask, Google App Engine…
• Herramientas científicas. Cuenta con una consola de Python interactive y es compatible con
Anacando y varios paquetes científicos como matplotlib y NumPy.
• Desarrollo multitecnología. Además de Python, PyCharm es compatible con JavaScript,
HTML/CSS…
• Capacidades para Desarrollo remote. Ejecuta, depura, prueba y desarrolla aplicaciones en
máquinas virtuales
7
7 Herramienta de Reconocimiento de Imágenes en Python
• Herramientas de Desarrollo. Una gran colección de herramientas listas para usar, como un
depurador integrado y ejecutor de pruebas.
• IDE multiplataforma. PyCharm funciona en Windows, Mac OS o Linux. Es posible instalar y
ejecutar PyCharm en tantas máquinas como se tenga, y usar el mismo entorno y la misma
funcionalidad.
• Cabe destacar que PyCharm está diseñado por programadores y para programadores, con el fin
de proporcionarles herramientas que son necesarias para un desarrollo productivo de Python.
En la siguiente figura, hay un ejemplo del aspecto de la IDE que vamos a usar para desarrollar la
aplicación, Pycharm. También la ejecución desde Pycharm de un fichero como ejemplo de
funcionamiento, y las distitas pestañas y opciones que se abren en la IDE para tener una vision global
de la configuración del fichero, que librerías usa, plot, distintas excepciones lanzadas si procede… [17]
2.4 Herramientas de Python
2.4.1 NumPy
Biblioteca de funciones matemáticas que opera con matrices.
Numpy, que significa “Numerical Python”, es la librería principal para la informática científica, que
proporciona grandes estructuras de datos [5].
La versión utilizada de NumPy es NumPy v1.18.0.
Tiene como características [5]:
Figura 1. Ejecución fichero .py desde Pycharm.
Software y diseño
8
• Implementación de matrices N-dimensionales
• Contiene: integrales, generadores de números totalmente aleatorios, transformadas de Fourier…
• Interoperabilidad. Permite plataformas de hardware.
• Fácil de usar. Alto nivel de sintaxis que facilita la accesibilidad a cualquier programador.
• Código abierto. Mantenido por la comunidad diversa GitHub.
• Muy utilizado en el desarrollo de algoritmos de Machine Learning
Esta librería ha tenido gran éxito en el estudio de ciertos casos: gracias a NumPy, junto con el uso de
otras librerías como SciPy y Matplotlib, permitió al Event Horizon Telescope producir la primera
imagen de un agujero negro, también científicos confirmaron la existencia de ondas gravitacionales
que predijo Albert Einstein en 1916 [5].
2.4.2 SciPy
Paquete científico científico. Incluye librerías científicas, basadas para matemáticas, ciencias e
ingeniería. Es una colección con algoritmos numéricos y cajas de herramientas específicas de dominio,
que incluye procesamiento de señales, optimización, estadísticas y mucho más [6].
Se basa en NumPy, y es parte del conjunto NumPy, con herramientas como SymPy o Pandas.
Algunas características son [11]:
• Está programado en Python, C, Fortran, C++, Cython.
• La comunidad de personas pertenecientes a SciPy, son las mismas que desarrollan esta pila.
• Contiene módulos para optimización, álgebra, integración, FFT, procesamiento de imágenes…
• Multiplataforma.
• Software abierto para computación científica.
• Proporciona rutas numéricas.
• Cómputo de datos y experimentación científica e informática.
2.4.3 Os
Este módulo viene incorporado en el sistema Python, y nos permite acceder a funcionalidades
dependientes del sistema operativo. Permite acciones como crear una carpeta, listar contenidos de una
carpeta, conocer acerca de un proceso, finalizar un proceso, etc.
Facilita métodos para conocer el directorio en el que nos encontramos, crear un directorio distinto o
eliminar archivos [9].
Notas sobre la disponibilidad de estas funciones [23]:
• El diseño de los módulos de Python dependientes del sistema operativo incorporado es tal que,
siempre que esté disponible la funcionalidad, utilizará la misma interfaz.
• Las extensiones propias de un sistema operativo en particular también están disponibles en el
módulo Os.
9
9 Herramienta de Reconocimiento de Imágenes en Python
• Todas las funciones que afirman “Disponibilidad: Unix” son también compatibles con Mac OS
X, que se basa en un núcleo de Unix.
2.5 Herramientas de procesado de imagen
2.5.1 OpenCV
Biblioteca de software de código abierto. Proporciona una infraestructura común para aplicaciones de
visión por computadora [4].
La librería OpenCV tiene más de 2500 algoritmos optimizados, que incluyen aprendizaje automático.
Estos algoritmos se suelen utilizar para reconocer caras, identificar objetos, estraer modelos 3D, nubes
de puntos, unir imágenes, recortes con alta resolución, buscador de imágenes parecidas en bases de
datos, eliminación de ojos rojos en fotografías o imágenes con flash, reconocimiento de paisajes,
realidad aumentada…[4]
Tiene interfaces C++, Python, Java y MATLAB y es compatible con Windows, Linux, Android y Mac
OS [4].
Está escrita en C++ y tiene una interfaz con plantilla que funciona a la perfección con contenedores
STL [4].
En este software, se usa la versión 4.2.0 de OpenCV.
2.5.2 Matplotlib
Biblioteca completa para crear visualizaciones estáticas e interactivas en Python. Permite desarrollar
gráficos de calidad de publicación con solo unas pocas líneas de código. Toma el control total de estilos
de línea, propiedades de los ejes [8]…
En este software, se usa la versión 3.2.0 de Matplotlib.
Algunas de sus características son [8]:
• Como función principal genera gráficos a partir de datos en listas.
• Proporciona una pylab, una API implementada para parecerse a MATLAB.
• Amplio juego de herramientas. Incluyen trazado 3d en el kit de herramientas mplot3d.
• Paquetes de terceros. Proyecciones y mapeos de imágenes.
• Código abierto. Mantenido por la comunidad diversa GitHub.
2.5.3 PIL
“Python Imagin Library”, es una biblioteca de imágenes de Python que agrega capacidades de
procesamiento de imágenes. Soporta una variedad de formatos, incluidos GIF, JPEG y PNG. Maneja
imágenes como rectángulos de datos de píxeles [21].
Admite diversos y múltiples formatos y proporciona potentes habilidades de procesamiento de
imágenes y gráficos.
Software y diseño
10
Gracias a PIL, creamos imágenes, las manipulamos, creamos e insertamos textos en ellas, y esto
lanzando un script [21].
En este software se usa la versión 7.0.0 PIL.
Código fuente abierto y mantenido por la comunidad GitHub.
2.5.4 Imutils
Serie de funciones que facilitan algoritmos y funciones de procesamiento de imágenes, como la
traducción, rotación, recortes, ampliaciones de tamaños y visualización de imágenes Matplotlib con
OpenCV.
En este software se usa la versión 0.5.3 Imutils.
2.6 Herramientas GUI
2.6.1 Tkinter
Python tiene multitud de marcos para elaborar una GUI, pero Tkinter es el único marco integrado en la
biblioteca estándar de Python.
Permite crear, colocar y mover una variedad de elementos gráficos para control, información de entrada
y salida (widgets) [7].
En este software se usa la versión 8.6 de Tkinter.
Algunas de sus características son [12]:
• Multiplataforma. El mismo código funciona en Windows, macOS y Linux. Los elementos
visuales pertenecen a la plataforma donde se ejecutan.
• Instalada por defecto en una instalación Microsoft Windows.
• Algunas de sus funciones son: posiciona texto/imagen en cualquier lugar de un widget, indica
colores de fondo de widget, posibilidad de especificar el ancho del borde de un elemento, nos
permite crear un botón y nos asocia un método o función para cuando se pulse ese botón…
• Ideal cuando el principal objetivo es construir algo funcional y multiplataforma.
11
3 HERRAMIENTA Y DESARROLLO EN PYTHON
3.1 Objetivo GUI
La interfaz gráfica de usuario (GUI), es un sistema informático que interviene como interfaz, usando un
conjunto de objetos gráficos para representar información y permitir al usuario realizar una serie de
acciones. Su principal uso consiste en ofrecer al usuario un entorno visual sencillo que permite la
comunicación con el sistema operativo del ordenador [13].
Por citar ejemplos, algunos son [13]:
• Windows
• X-Windows de Linux
• Aqua de Mac OS X
En relación con la interacción con el usuario, es un artefacto tecnológico que posibilita una interacción
con un sistema informático.
En este caso, el sistema informático es la Herramienta que hemos creado para trabajar con imágenes
que el usuario decide introducir en el sistema. A través de esta GUI, programada en Python y basada en
la librería Tkinter, el usuario podrá realizar una serie de operaciones a la imagen, simplemente
clickando un botón. De esta manera tan sencilla, el usuario podrá percibir visualmente los cambios
generados en la imagen (Imagen original en escala de grises, FFT de la imagen…) [13].
Todo este procesado de imagen se comentará con detalles en los capítulos posteriores.
Como se observa en la Figura 2, a través de la manipulación directa del usuario se interactúa con la
interfaz gráfica de usuario. Este artefacto tecnológico posibilita a través de la representación del
lenguaje visual, una interacción interesante con un sistema informático. Algunos ejemplos de interfaz
gráfica son KDE Plasma, los entornos de escritorios de Windows… Esta interfaz gráfica está
directamente relacionada con el servidor de pantalla, programa que coordina y gestiona las entradas y
salidas de sus clientes (X.org, muy conocido en el mundo de Linux). Estos servidores de pantalla están
directamente relacionados con los gestores de ventanas que crean los efectos gráficos y hacen que se
muestren en las ventanas. Otra parte importante a la hora de crear una GUI es tener en cuenta el núcleo,
que es la parte fundamental del sistema operativo, y es el responsable de facilitar a los distintos
programas o interfaces de gestionar un acceso seguro al hardware de la computadora [24].
Sé que parece que el mundo se está desmonorando,
pero en realidad es una gran época para volvernos
locos, seguir nuestra curiosidad y ser ambiciosos. No
abandonéis vuestros sueños. ¡El mundo os necesita!
- Larry Page -
Herramienta y Desarrollo en Python
12
Figura 2. Capas GUI.
3.2 Variables del programa
3.2.1 Definición
En programación está la definición de “variable”, que es similar pero no idéntico al concepto de
variable en las matemáticas.
Las variables están asociadas a “algo” en concreto. Además, cada lenguaje tiene una manera distinta de
implementar tal concepto, por lo que las definiciones siguientes [14]:
• En algunos lenguajes, una variable se puede entender como una caja en la que se guarda un
valor. Esta variable o caja, corresponde a un lugar en la memoria del ordenador.
• Se pueden representar con letras o palabras: x, a, c, variable, edad, ciudad…
• Para asignar un valor a estas variables, se suele hacer con el símbolo de igualdad (=),
entendiéndose como una asignación. Cuando se realizar esta asignación, le pedimos al
programa que calcule lo que existe a la derecha de esta igualdad, y que lo guarde en la variable
lo que haya calculado previamente.
La información que se guarda en estas variables puede ser de varios tipos como, por ejemplo [14]:
• Números, que estos a su vez pueden ser enteros, decimales, imaginarios…
• Cadenas de texto, como una sola letra o un conjunto de juego de caracteres ASCII.
• Conjuntos de números o texto, como matrices.
• Estructuras, como punteros.
3.2.2 Variables en Python
En Python, el concepto de variable cambia. Estas variables, entendidas anteriormente como “cajas” de
13
13 Herramienta de Reconocimiento de Imágenes en Python
información para otros lenguajes de programación, se convierten en “etiquetas” que hacen referencia a
los datos en Python.
Python es un lenguaje de programación orientado a objetos, y su modelo también lo es. Para cada dato
de un programa, Python crea un objeto. Cada objeto tiene [14]:
• Identificador único. Número entero distinto para cada objeto.
• Tipo de datos. Entero, decimal, cadena de caracteres…
• Un valor. Propio del dato.
Volviendo un poco a las variables que existen en Python, distinguimos tres tipos [14]:
• Variables locales. Las variables locales son las que pertenecen al ámbito de la subrutina.
También son accesibles a niveles inferiores. No necesitan identificación.
• Variables globales. Pertenecen al ámbito del programa principal. Necesitan la identificación
global.
• Variables no locales. Pertenecen a un ámbito superior a las locales, pero no son globales.
Necesitan la identificación nonlocal.
En la GUI desarrollada en la Herramienta de reconocimiento de imágenes, distinguiremos
principalmente entre dos tipos de variables: las variables globales y las variables locales.
3.2.3 Variables globales
Si a una variable no se le asigna valor, Python la considerará libre, y busca su valor en niveles por
encima a esa función. Si a la variable se le asigna un valor en el programa principal, se le considerará
global.
Si queremos cambiar el valor de estas variables globales en alguna función o subrutina, debemos
declararla dentro de la función o subrutina como global nombre_variable. Así, en la subrutina se
utilizará la variable con el valor del programa principal, o igualmente se podrá modificar el valor de esta
variable para utilizarla posteriormente en el programa principal [14].
3.2.4 Variables locales
Son las variables a las que se le asigna un valor dentro de una función, y solo existen en la propia
función, incluso cuando en el programa exista otra variable con el mismo nombre.
No son accesibles desde otros niveles superiores.
3.3 Funciones usadas de librerias
3.3.1 Definición
Una función o subrutina es un bloque de código con un nombre, que recibe cero o X argumentos como
entrada, sigue una secuencia de sentencias que tienen alguna finalidad y operación deseada, y
devuelven y/o realizan una tarea en el programa en el que se encuentran [22].
Las funciones son llamadas siempre que se necesiten en el programa principal.
Son esenciales para la programación estructurada, característica de Python. Algunas de las ventajas de
las funciones son [22]:
Herramienta y Desarrollo en Python
14
• Modularización. Segmenta un programa amplio y completo en distintos módulos más simples,
facilitando la programación y el depurado.
• Reutilización. Estos subbloques permiten realizar una función en distintos programas.
Las funciones definidas por usuario son usadas habitualmente. Es una sentencia ejecutable, que
enlaza el nombre de la función a un objeto función.
Estas funciones se definen con la sentencia def, de la siguiente forma que se explica en la figura:
La definición de una función no ejecuta el cuerpo de la función, lo que sucedería solamente con la
llamada de la función en alguna parte del programa principal.
3.3.2 Implementación
La implementación de las funciones definidas por el usuario, necesitan de funciones ya implementadas
en librerías importadas en el programa.
Estas funciones necesitan uno, ninguno o varios argumentos de entrada, para proporcionar una, ninguna
o varias salidas.
Estas funciones pertenecen a librerías, e iremos explicando cada una de las funciones utilizadas según la
librería en la que se describan.
A continuación, están todas las funciones integradas que utilizaremos en la realización de la
Herramienta en Python.
• Librería NumPy. Nos agrega funciones de apoyo para el cálculo de vectores y matrices de alto
nivel.
o Numpy.arange(0, A). Devuelve valores espaciados uniformemente dentro de un
intervalo dado, en este caso de 0 a un número desconocido A.
o Numpy.meshgrid(Y, X). Devuelve dos matrices de coordenadas de vectores de
coordenadas X e Y.
o Numpy.array([A, A, A]). Devuelve una matriz de valor A en cada posición. Si en vez
de introducir como argumento un vector, introducimos una imagen, esta se recoge
como un array y devuelve una matriz.
o Numpy.fft.fft2(image, [256,256]). Calcula la FFT bidimensional. La matriz de entrada
(image) puede ser compleja. Nos devuelve un ndarray.
Figura 3. Definición de función en Python.
15
15 Herramienta de Reconocimiento de Imágenes en Python
o Numpy.fft.fftshift(f). Siendo f la FFT de la anterior sentencia, esta función cambia el
componente de frecuencia cero al centro del espectro.
o Numpy.abs(fshift). Calculamos la amplitud del espectro fshift.
o Numpy.log(k). Realiza el logaritmo a un conjunto de número o número introducido K.
• Librería OpenCV
o Array.shape. Devuelve el tamaño de la cadena de caractéres Array.
o Cv2.imread(ruta,bandera). El método carga una imagen del archivo especificado en la
ruta para llegar hacia él. Con las banderas especificadas, podemos cambiar la forma de
leer la imagen.
o Cv2.calcHist(imagen, rangos). Cálculo de histograma de la imagen insertada. Hay
diferentes opciones a insertar, pero la más importante es el rango en el que se va a
mover el histograma.
o Cv2.cvtColor(). Convierte una imagen de un espacio de color a otro. Hay más de 100
métodos de conversión disponibles en OpenCV. Por ejemplo, están
Cv2.COLOR_BGR2RGB y Cv2.COLOR_BGR2HSV [15].
o Cv2.inRange(imagen, lowB, upB). Donde se introduce una imagen, y nos
encontramos con un umbral donde asignamos un valor particular a la región que se
encuentre entre los dos umbrales “lowB” y “upB”. Al resto de la región se le asigna un
valor distinto.
o Cv2.GaussianBlur(Imagen). Se aplica un suavizado gaussiano en la imagen de origen
de entrada.
o Cv2.medianBlur(Imagen). El elemento central de la imagen se reemplaza por la
mediana de todos los píxeles en el área del núcleo.
o Cv2.findContours(). Ayuda a extraer los contornos de la imagen.
• Librería Matplotlib
o Plt.figure(). Clase personaliza en la interfaz de pyplot. Relacionada con la
visualización de figuras. Devuelve “Fig”.
o Fig.gca(projection=’3d’). La figura “Fig” pasa a representarse en 3 dimensiones. El
resultado lo llamaremos “Ax”.
o Ax.contourf(XX, YY, imagen_array). Dibuja líneas de contorno y rellenos. XX e YY
Herramienta y Desarrollo en Python
16
son matrices que conforman el dimensionamiento de la matriz que compone la
imagen.
o Plt.close(). Cierra una ventana de figura.
o Matplotlib.pyplot.imsave(ruta, matriz). Guarda una matriz como un archivo de
imagen, en una ruta seleccionada previamente.
• Librería PIL
o Imagen.crop(). Metodo usado para recortar una porción rectangular de cualquier
imagen.
o Imagen.resize(A,B). Devuelve una imagen con cuyo alto y ancho se ha pasado como
parámetros A y B.
o Image.fromarray(matriz). Crea una memoria de imagen a partir de un objeto que
exporta la interfaz de matriz.
• Librería Tkinter. Trataremos elementos Canvas, que proporciona funciones de gráficos
estructurados que se puede utilizar para dibujar diagramas.
o Tkinter.Tk(). Instancia de la clase Tk, de Tkinter. Es el administrador de ventanas con
botones de cerrar, maximizar y minimizar en la parte superior como una GUI habitual.
A esta instancia la llamaremos “raíz” para entender las siguientes funciones.
o Raíz.geometry(“AxB”). Establece unas dimensiones AxB a la ventana raíz.
o Raíz.title(“Titulo de la Herramienta”). Titulo del administrador de ventanas.
o Raíz.config(). Aquí se pueden configurar distintos parámetros relacionados con el
administrador de ventanas. Por ejemplo, modificar los bordes, el tipo de cursor, el
color de fondo…
o Raiz.mainloop(). Se ejecuta cuando la aplicación esta lista para realizarse. Bucle
infinito.
o Tkinter.Label(Raíz, text=’ ‘). Etiqueta de texto, que suele ser estático. También puede
ser una etiqueta de imagen. Al resultado devuelto por esta función lo llamaremos
Label.
o Label.place(x=”A”, y=”B”). Posición del label dentro de la ventana en la que está
incluida.
17
17 Herramienta de Reconocimiento de Imágenes en Python
o Tkinter.Frame(Raíz). Funciona como un contenedor, que se encargar de organizar la
posición de los widgets.
o Tkinter.Canvas(Raíz). Crea un widget de propósito general para mostrar gráficos en
raíz. Al resultado de este widget lo llamaremos “Canvas”.
o Canvas.create_rectangle(topx, topy, topx, topy, dash=(2,2), fill=’’, outline=’white’).
Dibuja un rectángulo discontinuo de color blanco en el área seleccionada en este
widget con el ratón. El rectángulo creado lo llamaremos “Rectángulo”.
o Canvas.create_image(0,0,image=Imagen). En este widget se incluye la imagen que se
quiere introducir.
o Canvas.coords(Rectángulo, topx, topy, botx, boty). Si se dan las coordenadas, como en
este caso, estas se reemplazarán por las coordenadas actuales del ítem seleccionado.
o Canvas.bind(‘<Button-1>’, función). Esta función se ejecuta cada vez que se clickea el
botón derecho del ratón. “Función” es a la subrutina que se llama cuando esto pasa.
o Tkinter.Button(Raíz). Crea un Botón en el administrador de ventanas Raiz.
o ImageTk.PhotoImage(Imagen). Produce una imagen compatible con Tkinter. Esto se
puede usar en todas partes donde Tkinter espera un objeto imagen.
o Widget.Destroy() . Destruye el widget selecionado.
o Filedialog.askopenfilename(). Función para crear un objeto de diálogo de archivo.
Puede ser bien para abrir el archivo, para guardar el archivo, o para abrir el directorio.
Herramienta y Desarrollo en Python
18
3.4 Diagrama de flujo
Este diagrama representa el funcionamiento de la interfaz gráfica de usuario.
Figura 4. Diagrama de Flujos.
19
4 IMPLEMENTACIÓN EN PYTHON
El software es como la entropía: dificil de atrapar, no pesa, y cumple la
Segunda Ley de la Termodinámica, es decir, tiende a incrementarse.
-Norman Augustine-
Python es un lenguaje de programación diferencial, y por ello se escoge este lenguaje por delante de otros
también muy usados como Java o Node.js [16].
Muchísimas ventajas mencionadas anteriormente como ser un lenguaje multiparadigma, orientado objetos e
interpretado… hacen a Python ser el segundo lenguaje con mayor crecimiento en los últimos años, y ser el
elegido por la mayoría de los ingenieros, desarrolladores y científicos a la hora de crear o desarrollar una
Herramienta software [16].
A continuación, se explica el desarrollo del programa, sus partes, las variables utilizadas, tanto globales como
locales, el módulo principal y las funciones creadas por el desarrollador para implementar la herramienta.
Antes de comenzar, sería útil definir el concepto de widget, sencillo pero que vamos a nombrar a lo largo de
este capítulo. Un widget es un componente que aparece dentro de nuestra ventana raíz. Se distinguen 21 tipos
de widgets distintos: Canvas widget, Lavel widget, Button widget… con diferentes utilidades.
4.1 Fichero principal GUI_img.py
El programa está compuesto exclusivamente por este fichero donde se encuentran todas las variables,
tanto locales como globales, declaradas. De esta manera, también están las funciones definidas por el
desarrollador, que explicaremos más adelante.
Este fichero corresponde a un archivo de script de Python. Para crearlo, primeramente, se tiene que
recurrir a la IDE elegida que en este caso es PyCharm.
Se importan todas las librerías mencionadas en el capítulo anterior.
Código:
from tkinter import *
from tkinter import filedialog
from tkinter import ttk
import tkinter as tk
import cv2
from numpy import *
import numpy as np
import matplotlib as matplotlib
from matplotlib import pyplot as plt
from PIL import Image, ImageTk
Implementación en Python
20
import scipy.misc as scimis
import imutils
from mpl_toolkits.mplot3d import axes3d
from os import remove
4.2 Variables definidas por usuario
Estas etiquetas son las utilizadas por el desarrollador para hacer referencia en el programa a diferentes
valores o datos.
Distinguimos entre las variables globales y locales, cuyas diferencias están explicadas anteriormente.
4.2.1 Variables globales
Estas variables son usadas en todo el programa. Para la “Herramienta de reconocimiento de imágenes
en Python”, vamos a usar las siguientes, con sus distintas funcionalidades que se describen a
continuación:
• Path_global: Contiene la ruta a la imagen original introducida por el usuario. A través de
ella, se puede leer la imagen de la manera que mejor convenga.
• Image_1_global: Contiene la imagen en forma de array introducida por el usuario. Si la
imagen no ha conseguido leer sería una matriz vacía. Carga la imagen a color.
• Hsv_global: Cambio de espacio de color de Image_1_global para representar mejor los
colores.
• Mask_global: Detecta los colores de Image_1_global en un rango definido [0,255].
• B_global: Etiqueta del botón que llama a la función correspondiente a recortar la imagen
original, y hacer que sea la imagen activa para trabajar en la GUI.
• B1_global: Etiqueta del botón que llama a la función correspondiente a devolver a la
imagen original a la imagen activa para trabajar en la GUI.
• B2_global: Etiqueta del botón que hace que el programa comience a realizar una serie de
transformaciones sobre la imagen activa en la GUI.
• MagnitudFFT_global: Representa a la FFT de la imagen activa en la GUI, es decir, la
imagen original o una imagen recortada sobre la original.
• MagnitudFFT2_global: Representa a un objeto ImageTk, que es una imagen adaptada a
Tkinter. Esta imagen es la FFT de la imagen activa en la GUI.
21
21 Herramienta de Reconocimiento de Imágenes en Python
• Imagen_ecualizada_global: Representa a un objeto ImageTk que es una imagen adaptada
a Tkinter. Esta imagen es la imagen ecualizada de la imagen activa de la GUI.
• Imagen_byn_global: Representa a un objeto ImageTk que es una imagen adaptada a
Tkinter. Es la imagen en escala de grises de la imagen activa de la GUI.
• Blur_img_tk_global: Representa un objeto ImageTk que es una imagen adaptada a Tkinter.
Es la imagen activa tras ser filtrada por un filtro gaussiano.
• Median_img_tk_global: Representa un objeto ImageTk que es una imagen adaptada a
Tkinter. Es la imagen activa pasada por un filtro de mediana.
• Res1_global: Representa la cadena de caracteres de la imagen en escala de grises, pero
como conjunción de dos matrices.
• Res2_global: Representa la cadena de caracteres de la imagen en escala de grises, pero
como conjunción de dos matrices.
• Blur_global. Representa la cadena de caracteres de la imagen activa tras ser filtrada por un
filtro gausiano.
• Median_global: Representa la cadena de caracteres de la imagen activa tras ser pasada por
un filtro de mediana.
• Image_1_global_contour. Representa la cadena de caracteres que conforma el contorno de
la imagen activa dentro de la GUI.
• Contours_cv2_tk_global. Representa un objeto ImageTk que es una imagen adaptada a
Tkinter. Es la imagen que conforma el contorno de la imagen activa dentro de la GUI.
• Cnts_global: Representa una matriz con los contornos de la imagen.
• Alto_global: Representa al alto de la imagen recortada o de la imagen original en la GUI.
• Ancho_global: Representa al ancho de la imagen recortada o de la imagen original en la
GUI.
• Alto_adaptado_global: Alto de la imagen activa adaptado a la altura de la interfaz gráfica.
Esta variable hace que la imagen activa no sobrepase los límites de la GUI.
Implementación en Python
22
• Ancho_adaptado_global:Ancho de la imagen activa adaptado a la anchura de la interfaz
gráfica. Esta variable hace que la imagen activa no sobrepase los límites de la GUI.
• Topx, topy, botx, boty: Coordenadas de la selección del rectángulo a la hora de recortar una
imagen dentro de la GUI.
• Rect_id_global: Representa al rectángulo que se imprime en la imagen activa que se quiere
recortar dentro de la GUI.
• Image_original_global: Representa a la imagen original adaptada al tamaño de la interfaz
gráfica.
• Canvas2_global: Representa al objeto Canvas perteneciente a Tkinter, donde se introduce
la imagen recortada en la GUI.
• Pix_global: Contiene la matriz de la imagen con la que vamos a realizar todas las
transformaciones implantadas en la GUI.
• HayRecorte: Variable con función de bandera. Cuando esta variable tiene valor ‘1’, existe
un recorte sobre la imagen original, sin embargo, cuando vale ‘0’, la imagen original no ha
sufrido más cambios mas allá de un cambio de escala para que esta quepa en la GUI.
A todas estas variables le daremos un valor boolean inicial (Falso o verdadero), un entero
(cero) o ninguno (None).
Código:
path_global = True;
image_1_global = True;
hsv_global = True;
mask_global = True;
B_global = True;
B1_global = True;
B2_global = True;
magnitudFFT_global = True;
magnitudFFT2_global = True;
imagen_ecualizada_global = True;
imagen_byn_global = True;
blur_img_tk_global =True;
median_img_tk_global=True;
res1_global = True;
res2_global = True;
23
23 Herramienta de Reconocimiento de Imágenes en Python
blur_global = True;
median_global = True;
image_1_global_countour = True;
contours_cv2_tk_global = True;
cnts_global = True;
alto_global = True;
ancho_global = True;
alto_adaptado_global= True;
ancho_adaptado_global = True;
topx, topy, botx, boty = 0, 0, 0, 0
rect_id_global = None
image_original_global = None
canvas2_global = None
pix_global = True;
HayRecorte = 0;
4.2.2 Variables locales
Las variables locales se desclaran en su ámbito de uso (en el programa principal, y dentro de una
función).
Por lo tanto, debido a su definición se describirán las variables locales declaradas y definidas por el
usuario en el programa principal o en las funciones en las que están declaradas, ya que son muchas y
puede dar lugar a confusión.
4.3 Módulo principal
El modulo principal del programa contiene los elementos más esenciales del programa, en los que están
incluidos todos los widgets Tkinter, que conformarán nuestra interfaz gráfica.
Uno de ellos, el más importante, es la raíz o base de la interfaz gráfica. A partir de este widget raíz, el
resto de widgets se van almacenando dentro de este, y así se ira dando un aspecto a la interfaz gráfica
haciendo el widget raiz de contenedor. Recibe el nombre de “ventana1”. Le ponemos un tamaño, un
nombre, y no dejamos que su tamaño sea modificable por el usuario (todo en las siguientes figuras).
También se configura el color de fondo, el tipo de cursor, el contorno y el borde de este en la GUI.
A partir de la raíz, creamos el resto de widgets necesarios para la implementación de la interfaz gráfica.
Se crean widgets como “labeltitulo” que son etiquetas de texto. Estos elementos de la interfaz gráfica
también se configuran para darle forma a la GUI.
Debido a las funcionalidades de la herramienta, se ha decidido dividir la interfaz en 3 pestañas distintas
para diferenciar la funcionalidad de cada una dentro de la interfaz. Por lo tanto, se crea un panel de
pestañas siendo esto un tipo de element gráfico que permite dividir una parte de la ventana en distintas
solapas llamado “cuaderno1”. Se añaden las pestañas con nombre “pagina1”, “pagina2” y “pagina3”.
Dentro de estas pestañas, se diseñan todos los elementos que se introducen cada una de ellas.
Implementación en Python
24
En la primera pestaña, se incluye “boton1_abrir”. Este botón permite al usuario introducer una imagen
para tratar con ella. En esta misma pestaña, se introduce un objeto Canvas para una vez introducida la
imagen por el usuario, este objeto Canvas contenga la imagen introducida por el usuario. Asimismo,
este objeto Canvas permite seleccionar un rectangulo sobre la imagen insertada. Este objeto Canvas
recibe el nombre de “canvas”. Se configura también un segundo botón llamado “boton2_limpiar” que
limpiará la GUI de la imagen introducida una vez el botón sea pulsado.
En la segunda pestaña, se incluye una lista deplegable llamada “comboLabel”, en la que están las
siguientes opciones:
• FFT.
• Escala de grises.
• Filtrado gaussiano.
• Histograma.
• Filtrado de Mediana.
• Contorno imagen
Según la opción elegida, en el widget de imagen “label20” se imprimirá la imagen correspondiente a
la opción elegida. También existen dos botones más que son importantes: “boton3_guardar” y
“boton5_histograma”. El primero de ellos sirve para guardar la imagen según la opción elegida, y el
segundo sirve para imprimir un histograma relacionado con la imagen ecualizada.
Por ultimo, en la tercera pestaña se representará la imagen contour y la visualización en 3d de la FFT
de la imagen activa. Estas imagenes respectivamente se insertarán en los widgets “label15” y
“label17”.
Código:
ventana1 = tk.Tk()
ventana1.geometry("1200x700")
ventana1.title("Herramienta de reconocimiento de imágenes")
ventana1.resizable(0,0)
ventana1.config(bg="#0B121D")
ventana1.config(cursor="hand2")
ventana1.config(relief="sunken")
ventana1.config(bd=8)
labeltitulo= Label(ventana1, text="Herramienta de reconocimiento de imágenes", padx=15,pady=15)
labeltitulo.config(fg="white", bg="#0B121D",font=("Arial",18))
labeltitulo.pack(anchor=N)
cuaderno1 = ttk.Notebook(ventana1,width=800, height=600)
cuaderno1.place(x=200,y=50)
25
25 Herramienta de Reconocimiento de Imágenes en Python
pagina1 = ttk.Frame(cuaderno1)
cuaderno1.add(pagina1, text="Inicio", padding=10)
label1 = ttk.Label(pagina1, text="Bienvenido \nInserte una imagen para tratar con ella.\n")
label1.grid(column=0, row=0)
boton1_abrir = ttk.Button(pagina1, text="Abrir imagen",command=choose)
boton1_abrir.grid(column=0, row=1)
canvas = tk.Canvas(pagina1)
canvas.config(cursor="arrow")
canvas.bind('<Button-1>', get_mouse_posn)
canvas.bind('<B1-Motion>', update_sel_rect)
label19 = Label(pagina1, text=None)
label19.grid(column=0,row=4)
boton2_limpiar = ttk.Button(pagina1, text="Limpiar",command=limpiar)
boton2_limpiar.grid(column=0,row=3)
pagina2 = ttk.Frame(cuaderno1)
cuaderno1.add(pagina2, text="Tratamiento de la imagen",padding=10,state="disabled")
comboLabel = ttk.Combobox(pagina2, values=[ "FFT", "Escala de grises", "Filtrado gaussiano",
"Histograma", "Filtrado de Mediana", "Contorno imagen"])
comboLabel.current(1)
comboLabel.bind("<<ComboboxSelected>>", imprime_label)
comboLabel.place(x="20",y="20")
label2 = ttk.Label(pagina2, text=None)
label2.place(x="20", y="0")
label20 = Label(pagina2, image=None)
label20.place(x="320",y="20")
label21 = ttk.Label(pagina2,text=None)
label21.place(x="20", y="100")
boton3_guardar = ttk.Button(pagina2, text="Guardar",command=save_file,state="disabled" )
boton3_guardar.place(x="20", y="45")
boton5_histograma = ttk.Button(pagina2, text="Imprimir Histograma", command=histograma)
Implementación en Python
26
boton5_histograma.place(x="20", y="70")
label_histograma_titulo = Label(pagina2, text=None)
label_histograma_titulo.place(x="20", y="175")
label_histograma = Label(pagina2, image=None)
label_histograma.place(x="20", y="200")
pagina3 = ttk.Frame(cuaderno1)
cuaderno1.add(pagina3, text="Contour / 3D",padding=10,state="disabled" )
label14 = ttk.Label(pagina3, text=None)
label14.place(x="175", y="0")
label15= ttk.Label(pagina3,image=None)
label15.place(x="0", y="60")
label16 = ttk.Label(pagina3, text=None)
label16.place(x="15", y="550")
label17_titulo = ttk.Label(pagina3, text=None)
label17_titulo.place(x="550", y="0")
label17 = ttk.Label(pagina3, image=None)
label17.place(x="370", y="20")
boton4_contour = ttk.Button(pagina3, text="Visualizacion 3D", command = contour_y_3d)
boton4_contour.place(x="650", y="400")
ventana1.mainloop()
4.4 Funciones definidas por usuario
4.4.1 Get_mouse_posn(event)
Se utilizan las variables globales indicadas en la figura.
Devuelve la posición del ratón cada vez que pase el ratón por la imagen.
Código:
def get_mouse_posn(event):
global topy, topx
topx, topy = event.x, event.y
4.4.2 Update_sel_rect(event)
Se utilizan las variables globales indicadas en la figura.
27
27 Herramienta de Reconocimiento de Imágenes en Python
Selecciona las coordenadas del rectángulo a recortar sobre la imagen.
Código:
def update_sel_rect(event):
global rect_id_global
global topy, topx, botx, boty
botx, boty = event.x, event.y
canvas.coords(rect_id_global, topx, topy, botx, boty)
4.4.3 Contour_y_3d()
Se utilizan las variables globales indicadas en la figura.
En esta función, al comienzo cierras las posibles ventanas de pyplot creadas con anterioridad en otras
funciones.
Tras esto, se crea una ventana pyplot con la figura 3D de la FFT de la imagen.
Código:
def contour_y_3d():
global magnitudFFT_global
plt.clf()
plt.close()
x, y = magnitudFFT_global.shape
X = np.arange(0, x)
Y = np.arange(0, y)
xx, yy = np.meshgrid(Y, X)
fig2 = plt.figure()
ax = fig2.gca(projection='3d', facecolor="#F0F0F0")
ax.plot_surface(xx, yy, magnitudFFT_global, facecolor="#F0F0F0")
ax.contourf(xx, yy, magnitudFFT_global, zdir='x', offset=-5)
plt.show()
4.4.4 Histograma()
Se utilizan las variables globales indicadas en la figura.
Se hace grafica un histograma sobre la imagen que procede. Esta imagen se asignará dependiendo de lo
que valga “HayRecorte”. Si esta variable vale “0” el histograma se hará sobre la imagen original
introducida al comienzo del programa por el usuario. Sin embargo, si esta variable vale “1” el
histograma se realizará sobre la imagen recortada.
Todo el procedimiento para graficar el histograma desencadena en la variable “img_histograma_label”,
Implementación en Python
28
un objeto ImageTk que contiene la imagen en Tkinter del histograma a imprimir. Esta imagen se
imprimirá en la variable “label_histograma”.
Posteriormente, se borran las figuras creadas en pyplot.
Código:
def histograma():
global HayRecorte
global pix_global
if HayRecorte == 0:
image_1_global = cv2.imread(path_global, 1)
if HayRecorte == 1:
image_1_global = pix_global
fig = plt.figure()
histr = cv2.calcHist([image_1_global], [0], None, [256], [0, 256])
plt.plot(histr)
fig.savefig('plot.png', facecolor="#F0F0F0")
image_1_global = cv2.imread('plot.png', 1)
image_1_global.shape
image = cv2.cvtColor(image_1_global, cv2.COLOR_BGR2RGB)
hsv = cv2.cvtColor(image_1_global, cv2.COLOR_BGR2HSV)
lw_range = np.array([0, 0, 0])
up_range = np.array([255, 255, 255])
mask= cv2.inRange(hsv, lw_range, up_range)
res = cv2.bitwise_and(image, image, mask=mask)
imagen_histograma = Image.fromarray(res).resize((280, 280), Image.ANTIALIAS)
img_histograma_label = ImageTk.PhotoImage(imagen_histograma)
label_histograma.configure(image=img_histograma_label)
label_histograma.image = img_histograma_label
remove("plot.png")
label_histograma_titulo.configure(text="Nº total píxeles - Rango píxeles")
plt.close(fig)
29
29 Herramienta de Reconocimiento de Imágenes en Python
4.4.5 NoRecorta()
Se utilizan las variables globales indicadas en la figura.
En esta función se retrocede para volver a obtener la imagen original insertada por el usuario. Por lo
tanto, se borra el objeto “canvas2_global” donde se almacena la imagen recortada, y se procede a leer
de nuevo la imagen.
Esta imagen guardará en “canvas”, y sus características geométricas en “alto_global” y
“ancho_global”.
Código:
def NoRecorta():
global image_original_global
global canvas2_global
global B1_global
global HayRecorte
global ancho_global ,alto_global
global pix_global
HayRecorte = 0
img = ImageTk.PhotoImage(image_original_global)
canvas2_global.destroy()
canvas.img = img
canvas.create_image(0, 0, image=img, anchor=tk.NW)
canvas.place(x="320",y="20")
B1_global.configure(state="disabled")
data_original = image_original_global.size
alto_global = data_original[0]
ancho_global = data_original[1]
pix_global = np.array(image_original_global)
4.4.6 Recorta()
Se utilizan las variables globales indicadas en la figura.
En esta función se pretende recortar a través del rectángulo seleccionado la imagen introducida por el
usuario. Se pretende, porque si esta función es llamada sin existir ningún área seleccionada para
recortar, esta función no hace ninguna acción dentro de la GUI.
En esta función, una vez recortada la imagen esta se guarda en “cropped_img”. Con el matiz de que
ahora esta imagen recortarda “cropped_img” tenemos que aumentarla para que el usuario pueda
observarla con mayor definición, manteniendo la relación de aspecto de la imagen y no desfigurarla.
Implementación en Python
30
Código:
def Recorta():
global image_1_global
global topy, topx, botx, boty
global cropped_img_label
global canvas2_global
global B1_global
global pix_global
global HayRecorte
global alto_global, ancho_global
global image_original_global
if topx != 0 or topy != 0 or botx != 0 or boty != 0:
canvas.delete("all")
HayRecorte = 1
canvas2_global = tk.Canvas(pagina1)
area = (topx, topy, botx, boty)
cropped_img = image_original_global.crop(area)
data1 = cropped_img.size
alto_global = data1[0]
ancho_global = data1[1]
if alto_global < 550 and ancho_global < 550:
while ancho_global < 450 and alto_global < 450:
alto_global = alto_global * 1.02
ancho_global = ancho_global * 1.02
cropped_img1 = cropped_img.resize((int(alto_global),int(ancho_global)),Image.ANTIALIAS)
cropped_img_label = ImageTk.PhotoImage(cropped_img1)
canvas2_global.create_image(0, 0, image=cropped_img_label, anchor=tk.NW)
canvas2_global.place(x="320",y="20")
canvas2_global.config(width=int(alto_global), height=int(ancho_global))
pix_global = np.array(cropped_img)
image_1_global = pix_global
B1_global.configure(state="normal")
31
31 Herramienta de Reconocimiento de Imágenes en Python
4.4.7 Limpiar()
Se utilizan las variables globales indicadas en la figura.
En esta función, las dos pestañas últimas se deshabilitan para no poder acceder a ellas, ya que se va a
eliminar la imagen insertada a la GUI. Si existe una imagen recortada, se eliminará el objeto canvas
“canvas2_global” que es donde se encuentra. Igualmente, se vaciarán los widgets pertenecientes a la
primera pestaña.
Código:
def limpiar():
global B_global, B1_global, B2_global
global canvas2_global
global HayRecorte
try:
cuaderno1.tab(1, state="disabled")
cuaderno1.tab(2,state="disabled")
canvas.delete("all")
if HayRecorte == 1:
canvas2_global.destroy()
label19.configure(text=" ")
label_histograma_titulo.configure(text=" ")
label21.configure(text=" ")
label_histograma.configure(image=None)
label_histograma.image = None
label20.configure(image=None, relief = None)
label20.image=None
boton3_guardar.configure(state="disabled")
B_global.destroy()
B1_global.destroy()
B2_global.destroy()
except AttributeError:
print("No hay nada que borrar")
4.4.8 ReconocimientoImagen()
Se utilizan las variables globales indicadas en la figura.
Implementación en Python
32
Esta función es la función cerebro del programa y la que realiza todas las funciones relacionadas con el
tratamiento de las imágenes. Se habilitan las 2 pestañas que estaban deshabilitadas al comienzo del
programa.
Dependiendo si ha habido recorte o no con anterioridad sobre la imagen insertada, se procede de una
manera o de otra para que la variable local “image_2” y la variable global “image_1_global” hagan
referencia al recorte o a la imagen original.
Tras esto, se realiza a realizar transformaciones para conseguir los siguientes objetivos:
• FFT de la imagen.
• Imagen en escala de grises.
• Filtrado gaussiano de la imagen.
• Filtrado de Mediana sobre la imagen.
• Imagen ecualizada
• Contorno de los límites de la imagen
• Contorno de la FFT (con 7 niveles)
• Vista preliminar de la visualización 3d de la FFT.
Tras realizar las transformaciones pertinentes, se borran las figuras creadas en pyplot y los archivos
guardados.
Código:
def ReconocimientoImagen():
global path_global
global cropped_img_global
global imagen_global
global image_1_global
global hsv_global
global mask_global
global magnitudFFT2_global
global imagen_ecualizada_global
global imagen_byn_global
global blur_img_tk_global
global median_img_tk_global
global magnitudFFT_global
global res1_global
global blur_global
global median_global
global res2_global
global image_1_global_countour
33
33 Herramienta de Reconocimiento de Imágenes en Python
global contours_cv2_tk_global
global cnts_global
global alto_adaptado_global , ancho_adaptado_global
global pix_global
global HayRecorte
cuaderno1.tab(1, state="normal")
cuaderno1.tab(2, state="normal")
imagen_recortada= Image.fromarray(pix_global)
imagen_recortada.save("Prueba.png")
image_2 = cv2.imread("Prueba.png", 0)
if HayRecorte == 1:
data_nuevo = image_2.shape
alto_nuevo = data_nuevo[0]
ancho_nuevo = data_nuevo[1]
while ancho_nuevo < 450 and alto_nuevo < 550
alto_nuevo = alto_nuevo * 1.02
ancho_nuevo = ancho_nuevo * 1.02
if HayRecorte == 0:
image_2 = cv2.imread(path_global, 0)
image_1_global = cv2.imread(path_global, 1)
alto_nuevo = alto_adaptado_global
ancho_nuevo = ancho_adaptado_global
f = np.fft.fft2(image_2, [256,256])
fshift = np.fft.fftshift(f)
magnitudFFT_global = 20 * np.log(np.abs(fshift))
magnitudFFT1_global = Image.fromarray(magnitudFFT_global).resize((350, 350),
Image.ANTIALIAS)
magnitudFFT2_global = ImageTk.PhotoImage(magnitudFFT1_global)
gray_img = cv2.cvtColor(image_1_global, cv2.COLOR_BGR2GRAY)
hsv_global = cv2.cvtColor(image_1_global, cv2.COLOR_BGR2HSV)
lw_range = np.array([0, 0, 0])
up_range = np.array([255, 255, 255])
mask_global=cv2.inRange(hsv_global, lw_range, up_range)
Implementación en Python
34
res1_global = cv2.bitwise_and(gray_img, gray_img, mask=mask_global)
gray_img1 = Image.fromarray(res1_global).resize((int(ancho_nuevo), int(alto_nuevo)),
Image.ANTIALIAS)
imagen_byn_global = ImageTk.PhotoImage(gray_img1)
blur_global = cv2.GaussianBlur(image_1_global, (5, 5), 0)
blur_img =
Image.fromarray(blur_global).resize((int(ancho_nuevo),int(alto_nuevo)),Image.ANTIALIAS)
blur_img_tk_global= ImageTk.PhotoImage(blur_img)
median_global = cv2.medianBlur(image_1_global, 5)
median_img =
Image.fromarray(median_global).resize((int(ancho_nuevo),int(alto_nuevo)),Image.ANTIALIAS)
median_img_tk_global = ImageTk.PhotoImage(median_img)
img_to_yuv = cv2.cvtColor(image_1_global, cv2.COLOR_BGR2YUV)
img_to_yuv[:, :, 0] = cv2.equalizeHist(img_to_yuv[:, :, 0])
hist_equalization_result = cv2.cvtColor(img_to_yuv, cv2.COLOR_YUV2BGR)
res2_global = cv2.bitwise_and(hist_equalization_result, hist_equalization_result,
mask=mask_global)
hist_equalization_result2 = Image.fromarray(res2_global).resize((int(ancho_nuevo),
int(alto_nuevo)), Image.ANTIALIAS)
imagen_ecualizada_global = ImageTk.PhotoImage(hist_equalization_result2)
image_1_global_countour = image_1_global
gray = cv2.cvtColor(image_1_global_countour, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
thresh = cv2.threshold(blurred, 60, 255, cv2.THRESH_BINARY)[1]
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts_global = imutils.grab_contours(cnts)
for c in cnts_global:
cv2.drawContours(image_1_global_countour, [c], -1, (0, 255, 0), 2)
contours_cv2 = Image.fromarray(image_1_global_countour).resize((int(ancho_nuevo),
int(alto_nuevo)), Image.ANTIALIAS)
contours_cv2_tk_global = ImageTk.PhotoImage(contours_cv2)
label14.configure(text="Contour")
label17_titulo.configure(text="3D")
35
35 Herramienta de Reconocimiento de Imágenes en Python
lw_range1 = np.array([0, 0, 0])
up_range1 = np.array([255, 255, 255])
x, y = magnitudFFT_global.shape
X = np.arange(0, x)
Y = np.arange(0, y)
xx, yy = np.meshgrid(Y, X)
fig = plt.figure()
contorno1 = plt.contour(xx, yy, magnitudFFT_global, alpha=0.9, levels=7)
plt.colorbar(contorno1)
fig.savefig('plot.png', facecolor="#F0F0F0")
imagen_contour = cv2.imread('plot.png', 1)
hsv_global1 = cv2.cvtColor(imagen_contour, cv2.COLOR_BGR2HSV)
imagen_cv2_contour = cv2.cvtColor(imagen_contour, cv2.COLOR_BGR2RGB)
mask_global1 = cv2.inRange(hsv_global1, lw_range1, up_range1)
res_global1 = cv2.bitwise_and(imagen_cv2_contour, imagen_cv2_contour, mask=mask_global1)
image_1_1 = Image.fromarray(res_global1).resize((400, 400), Image.ANTIALIAS)
img_1 = ImageTk.PhotoImage(image_1_1)
label15.configure(image=img_1)
label15.image = img_1
fig.clf()
plt.clf()
fig = plt.figure()
ax = fig.gca(projection='3d', facecolor="#F0F0F0")
ax.plot_surface(xx, yy, magnitudFFT_global, facecolor="#F0F0F0")
ax.contourf(xx, yy, magnitudFFT_global, zdir='x', offset=-5)
fig.savefig('plot.png', facecolor="#F0F0F0")
surface1 = cv2.imread('plot.png', 1)
hsv_global2 = cv2.cvtColor(surface1, cv2.COLOR_BGR2HSV)
surface1_cv2 = cv2.cvtColor(surface1, cv2.COLOR_BGR2RGB
mask_global2 = cv2.inRange(hsv_global2, lw_range1, up_range1)
res_global2 = cv2.bitwise_and(surface1_cv2, surface1_cv2, mask=mask_global2)
image_surface = Image.fromarray(res_global2).resize((350, 350), Image.ANTIALIAS)
img_surface = ImageTk.PhotoImage(image_surface)
label17.configure(image=img_surface)
label17.image = img_surface
remove('Prueba.png')
Implementación en Python
36
remove('plot.png')
fig.clf()
plt.clf()
plt.close(fig)
4.4.9 Choose()
Se utilizan las variables globales indicadas en la figura.
Esta función permite interactuar por primera vez al usuario con la GUI, permitiéndole al usuario
introducir una imagen para realizarle todas las transformaciones mencionadas anteriorimente.
Antes de guardar la imagen en un objeto canvas, tenemos que saber las dimensiones de este objeto, pero
sin sobrepasar una geometría determinada (450 x 550 píxeles) manteniendo siempre su relación de
aspecto.
Una vez se encuentra el nuevo tamaño de la imagen, la metemos en el objeto canvas llamado “canvas”.
Se extrae información sobre la imagen original y la imprimimos en el widget “label19”.
Se crean nuevos botones:
• “B_global”, que llama a la función Recorta()
• “B1_global”, que llama a la función NoRecorta()
• “B2_global”, que llama a la función ReconocimientoImagen()
Código:
def choose()
global B_global, B1_global, B2_global
global path_global
global cropped_img_global
global imagen_global
global image_1_global
global hsv_global
global mask_global
global funcion_global
global res_global
global ancho_global, alto_global
global alto_adaptado_global, ancho_adaptado_global
global image_original_global
global pix_global
global rect_id_global
global HayRecorte
37
37 Herramienta de Reconocimiento de Imágenes en Python
global canvas2_global
try:
if HayRecorte == 1:
canvas2_global.destroy()
path_global = filedialog.askopenfilename()
image_1_global = cv2.imread(path_global, 1)
data = image_1_global.shape
image_original_global = cv2.cvtColor(image_1_global, cv2.COLOR_BGR2RGB)
hsv_global = cv2.cvtColor(image_1_global, cv2.COLOR_BGR2HSV)
lw_range = np.array([0, 0, 0])
up_range = np.array([255, 255, 255])
mask_global = cv2.inRange(hsv_global, lw_range, up_range)
res_global= cv2.bitwise_and(image_original_global, image_original_global, mask=mask_global)
alto_global = data[0]
ancho_global = data[1]
while ancho_global > 450 or alto_global > 550:
alto_global = alto_global * 0.9
ancho_global = ancho_global * 0.9
alto_adaptado_global = alto_global
ancho_adaptado_global = ancho_global
image_original_global = Image.fromarray(res_global).resize((int(ancho_global),int(alto_global)),
Image.ANTIALIAS)
pix_global = np.array(image_original_global)
imagen_global=image_original_global;
img = ImageTk.PhotoImage(image_original_global)
canvas.img = img
canvas.create_image(0, 0, image=img, anchor=tk.NW)
canvas.place(x="320",y="20")
canvas.config(width=int(ancho_global), height=int(alto_global))
rect_id_global = canvas.create_rectangle(topx, topy, topx, topy,dash=(2, 2), fill='',
outline='white')
Implementación en Python
38
label19.configure(text="Informacion Imagen Original\nAlto: {} píxeles\nAncho: {}
píxeles\nCanales: {} píxeles".format(data[0], data[1], data[2]))
B_global = Button(pagina1, text="Recortar Imagen", command=Recorta)
B_global.place(x=0,y=200)
B1_global = Button(pagina1, text="Sin recortar", command= NoRecorta,state="disabled")
B1_global.place(x=100,y=200)
B2_global = Button(pagina1, text="Comenzar", bg = "#F0F0F0" ,
command=ReconocimientoImagen)
B2_global.place(x=220, y=200)
rect_id_global = canvas.create_rectangle(topx, topy, topx, topy,
dash=(2, 2), fill='', outline='white')
except AttributeError:
print("Error tipo NoneType")
4.4.10 Save_file()
Se utilizan las variables globales indicadas en la figura.
Dependiendo de la opción escogida dentro de la segunda pestaña, se guardará una imagen u otra.
Por ejemplo, si en la segunda pestaña está escogida la opción de la FFT de la imagen, y es llamada esta
función con el botón correspondiente, se guardará la imagen FFT en extensión .png en el directorio que
el usuario elija.
Código:
def save_file():
try:
global magnitudFFT_global
global res1_global
global blur_global
global median_global
global res2_global
global image_1_global_countour
gray_img1 = Image.fromarray(res1_global)
39
39 Herramienta de Reconocimiento de Imágenes en Python
file = filedialog.asksaveasfilename(filetypes=[("PNG",".png")],defaultextension=".png")
if comboLabel.get() == "FFT":
matplotlib.image.imsave(str(file), magnitudFFT_global)
elif comboLabel.get() == "Escala de grises":
gray_img1.save(str(file))
elif comboLabel.get() == "Filtrado gausiano":
matplotlib.image.imsave(str(file), blur_global)
elif comboLabel.get() == "Histograma":
matplotlib.image.imsave(str(file), res2_global)
elif comboLabel.get() == "Filtrado de Mediana":
matplotlib.image.imsave(str(file), median_global)
elif comboLabel.get() == "Contorno imagen":
matplotlib.image.imsave(str(file), image_1_global_countour)
except ValueError:
print("No hay formato escogido")
Implementación en Python
40
4.4.11 Imprime_label(event)
Se utilizan las variables globales indicadas en la figura.
Imprimirá en “label2” y en “label20” el título y la imagen correspondiente con la opción elegida dentro
de la lista desplegable con las opciones . Por ejemplo, si la opción elegida es la FFT de la imagen, en
“label2” aparecerá la etiqueta de texto correspondiente a la FFT, y en “label20” aparecerá la imagen
correspondiente a la FFT.
Código:
def imprime_label(event):
global magnitudFFT2_global
global imagen_ecualizada_global
global imagen_byn_global
global median_img_tk_global
global contours_cv2_tk_global
global cnts_global
label21.configure(text=" ")
boton3_guardar.configure(command=save_file,
state="normal") # state=disabled para deshabilitar
if comboLabel.get() == "FFT":
label20.configure(image=magnitudFFT2_global)
label20.image = magnitudFFT2_global
label2.configure(text="Imagen FFT")
elif comboLabel.get() == "Escala de grises":
label2.configure(text="Imagen original en escala de grises")
label20.configure(image=imagen_byn_global)
label20.image = imagen_byn_global
elif comboLabel.get() == "Contorno imagen":
label20.configure(image=contours_cv2_tk_global)
label20.image = contours_cv2_tk_global
label2.configure(text="Contorno imagen original")
label21.configure(text="Número de Contour: " + str(len(cnts_global)))
elif comboLabel.get() == "Histograma":
41
41 Herramienta de Reconocimiento de Imágenes en Python
label20.configure(image=imagen_ecualizada_global)
label20.image = imagen_ecualizada_global
label2.configure(text="Imagen histograma ecualizada")
elif comboLabel.get() == "Filtrado de Mediana":
label20.configure(image=median_img_tk_global)
label20.image = median_img_tk_global
label2.configure(text="Imagen filtrada por mediana")
elif comboLabel.get() == "Filtrado gaussiano":
label20.configure(image=blur_img_tk_global)
label20.image = blur_img_tk_global
label2.configure(text="Imagen filtrada gaussiana")
Implementación en Python
42
43
5 COMPILACIÓN GUI
5.1 Introducción
Compilar es reunir o juntar en un mismo volumen un conjunto de partes o extractos de distintos
documentos que tienen un tema en común [18].
En el ámbito de la Informática, la compilación es la fase de codificación en que un programa es pasado
y traducido del código fuente (lenguaje de alto nivel) al código máquina. Podemos distinguir en esta
etapa, al menos, cuatro fases:
Figura 5. Fases de la compilación.
• Análisis léxico: Extrae del archivo Fuente todas las cadenas de caracteres que reconoce como
parte del vocabulario y genera un conjunto de tokens como salida. Si no es posible, se
generarán los mensajes de error correspondientes [19].
Figura 6. Análisis léxico.
• Análisis sintáctico: Se procesa la secuencia de tokens generada con anterioridad, y se construye
una representación intermedia que permite al compilador realizar su labor [19].
Compilación GUI
44
Figura 7. Análisis sintáctico.
• Análisis semántico: Se utiliza el árbol generado en la fase previa para detector posibles
violaciones a la semántica del lenguaje de programación [19].
• Generación de Código. Se transforma todo lo anterior en lenguaje máquina (Código objeto).
Muy importante la optimización del Código para esta fase [19].
Este proceso, es realizado por un compilador virtual, cuya tarea consiste en llevar un programa fuente a
programa objeto.
5.2 PyInstaller
Módulo que ayudará para generar archivos ejecutables en Python.
Genera un ejecutable “.exe” en Windows, un “.dmg” en MAC o el ejecutable que utilice el Sistema
Operativo. Dentro del ejecutable se incluye el propio intérprete de Python, y por ello se podrá utilizer el
ejecutable en cualquier ordenador sin necesidad de instalar Python ni ninguna de sus librerías utilizadas
en el programa original [20].
Se compila igual para cualquier SO, solo que creará distintos tipos de ejecutables dependiendo del SO
en el que nos encontremos. Por ejemplo, para Windows creará un archivo con extension “.exe”.
Si se importan las librerías necesarias dentro del script, PyInstaller incluirá los recursos y módulos
necesarios que se haya en el programa de forma automática.
45
45 Herramienta de Reconocimiento de Imágenes en Python
La instalación es muy sencilla, abriendo el “Símbolo del Sistema” y escribiendo:
Figura 8. Instalación PyInstaller.
PyInstaller es muy poderoso, pero tiene algunas complicaciones. Admite la creación de ejecutables para
Windows, Linux y macOS, pero no una compilación cruzada. Es decir, no permite la ejecución de un
ejecutable dirigido a un sistema operativo desde otro sistema operativo distinto. Por lo tanto, para
distribuir ejecutables para múltiples tipos de SO, necesitará una máquina de compilación para cada SO
soportado [25].
El trabajo, generalmente, seguirá las líneas siguientes [25]:
• Crear scrip a usar.
• Instalar PyInstaller.
• Ejecutar PyInstaller para compilar.
• Probar el ejecutable.
5.2.1 Compilación programa
La compilación de un archivo programa en Python sigue siendo muy sencillo.
Tan solo tienes que escribir el siguiente comando de la figura en “Símbolo del Sistema”, justo en la ruta
en la que se encuentre nuestro archivo .py.
En este ejemplo, nuestro programa en Python a convertir en ejecutable sería “hola.py”, y solo generaría
un archivo ejecutable conteniendo todo.
El ejecutable se guardará en una carpeta llamada “dist”, que estará ubicada en el mismo directorio
donde se encuentre nuestro script a compilar.
Figura 9. Compilación programa en Python.
Compilación GUI
46
47
6 RESULTADOS DE LA GUI
Figura 10. Inicio de la GUI.
Resultados de la GUI
48
Figura 11. Introducción de la imagen a tratar.
49
49 Herramienta de Reconocimiento de Imágenes en Python
Figura 12. Inicio con la imagen introducida.
Resultados de la GUI
50
Figura 13. Inicio con la selección del área recortada sobre la imagen.
51
51 Herramienta de Reconocimiento de Imágenes en Python
Figura 14. Inicio con recorte de la imagen.
Resultados de la GUI
52
Figura 15. Tratamiento de la imagen, FFT.
53
53 Herramienta de Reconocimiento de Imágenes en Python
Figura 16. Tratamiento de la imagen, escala de grises.
Resultados de la GUI
54
Figura 17. Tratamiento de las imágenes, filtrado gaussiano.
55
55 Herramienta de Reconocimiento de Imágenes en Python
Figura 18. Tratamiento de la imagen, imagen ecualizada e histograma.
Resultados de la GUI
56
Figura 19. Tratamiento de la imagen, filtrado de mediana.
57
57 Herramienta de Reconocimiento de Imágenes en Python
Figura 20. Tratamiento de la imagen, contornos.
Resultados de la GUI
58
Figura 21. Guardar imagen tratada seleccionada.
59
59 Herramienta de Reconocimiento de Imágenes en Python
Figura 22. Contour y vista preliminar 3D de la FFT.
Resultados de la GUI
60
Figura 23. Visualización 3D de la FFT.
61
61 Herramienta de Reconocimiento de Imágenes en Python
Figura 24. Inicio, limpieza de imagen
Resultados de la GUI
62
63
7 CONCLUSIONES Y LÍNEAS FUTURAS
Este trabajo ha supuesto poner en práctica, no solo mucho de lo aprendido durante el Grado, sino además
estudiar cada una de las librerías implementadas para alcanzar los objetivos con una GUI. Comenzando desde
el reconocimiento y el procesado de cada uno de los píxeles de las imágenes, hasta su misma programación e
implementación en Python. Es una mezcla de conocimientos, pero quiero hacer una especial mención a la
conexión directa que se hace en el trabajo entre dos de las intensificaciones del Grado, como son Telemática
(referencia a todo lo relacionado con la programación en Python: programación, módulos, compilación…) y
Sonido e Imagen (trabajo con imágenes y transformaciones). Esto ha hecho que, sumado a mi mención
Sistemas de Telecomunicación, los conocimientos sobre las distintas áreas que también maneja las
telecomunicaciones que tenía han incrementado.
Durante la realización del trabajo han ido surgiendo problemas y dificultades que he sabido resolver
en poco tiempo. Estas dificultades no eran sencillas de resolver, pero por ello Python es un lenguaje de
programación tan usado. Estas dificultades en la mayoría de las veces las he podido resolver navegando por
Internet, y encontrando siempre una solución que ya esta predefenida en algún modulo o librería. Distintas
dificultades como redimensionar la imagen introducida por el usuario, posicionar correctamente distintos
widgets que forman parte de la GUI, compilación correcta de un programa implementado en Python 3.8 …
todas ellas, se han resuelto dedicándole unas horas a navegar por Internet y revisando distintos foros sobre
Python.
Este trabajo también me ha servido para aprender a desarrollar un proyecto de trabajo desde el
principio hasta el final de este. Al principio del trabajo, tenía una idea en la cabeza mucho más sencilla de lo
que iba a ser el trabajo. Con el paso de las semanas, esta idea ha ido cogiendo forma, ha ido añadiendo nuevos
estilos y nuevas funcionalidades que han deparado en una GUI completa.
Me ha servido para saber a lo que me puedo encontrar en un futuro, a realizar un trabajo complejo y
que este se complique en ciertos momentos. Saber controlar los momentos en los que las cosas no salen como
uno quiere, y encontrar el momento y la forma para seguir adelante en una tarea. Creo que esto en el futuro me
ayudará a desempeñar distintas tareas bajo tensión.
Cabe destacar que este lenguaje de programación no era nuevo para mí, pero nunca lo llegue a ver tan
profundamente. Esto suponía un reto que a comienzo de curso no sabía como sería. En este sentido, si que
tenía una gran motivación para poder aprender a programar en uno de los lenguajes de programación más
importantes del mundo.
Con vistas hacia el futuro, aquí van una serie de posibles mejoras para poder expandir la interfaz
gráfica para hacerla aún más usable para el público:
• Añadir más funcionalidades: más filtrados tanto lineales como no liales sobre la imagen o la porción
de la imagen seleccionada sobre la imagen original. Estas funcionalidades se programarían en el
fichero principal Trabajo_UltimoAvance.py, y sería una buena idea añadir una o varias opciones en la
lista desplegable de la segunda pestaña para que el usuario pueda seleccionar la transformación sobre
la imagen que desee.
• Ampliar la GUI: más pestañas dentro de la GUI. Por ejemplo, crear una nueva pestaña dentro de la
Conclusiones y Líneas futuras
64
GUI para que el usuario pueda interactuar con la imagen, girando la imagen o haciendo un recorte
sobre ella con alguna figura curva. También en estas pestañas se podría crear una sección para tocar
algún área relacionada con las imágenes.
• Cambiar el diseño de la GUI: se puede cambiar el diseño de la GUI, de forma que el ingeniero que lo
haga mejore la interacción GUI-usuario.
Tras ver cuales son las posibles líneas de mejora del trabajo, algunos detalles para tener en cuenta si se
quiere continuar con el desarrollo de la Herramienta son:
• El código está descrito en el capítulo titulado “Implementación en Python”. En este capítulo están
definidas todas las variables globales, las variables locales y las funciones definidas usadas en el
programa. Además, está el cuerpo del programa, que es el bloque fundamental del trabajo. Con
copiar todo el código en una IDE e instalar las librerías descritas en el capítulo titulado “Software
y diseño” el software funcionará a la perfección. Para ampliarlo, sólo se tendrá que
modificar/añadir las funciones del programa.
• Respecto a la compilación, con PyInstaller se podrá compilar el programa en cualquier SO. Eso
sí, solo se podrá utilizar en el SO en el que se compile. Por ejemplo, si se compila en Windows y
produce un ejecutable “.exe”, este ejecutable sólo será usable en Windows.
65
65 Herramienta de Reconocimiento de Imágenes en Python
66
REFERENCIAS
[1] Covantec R.L., « Programación en Python - Nivel básico », 2018. [En línea]. Available:
https://entrenamiento-python-basico.readthedocs.io/es/latest/leccion1/introduccion.html
[2] OpenWebinars S.L.,« Qué es Python: Características, evolución y futuro », 2020. [En línea]. Available:
https://openwebinars.net/blog/que-es-python/
[3] JetBrains s.r.o., « PyCharm », 2020. [En línea]. Available: https://www.jetbrains.com/es-es/pycharm/
[4] OpenCV team, 2020. [En línea]. Available: https://opencv.org/about/
[5] NumPy, 2020. [En línea]. Available: https://numpy.org/
[6] SciPy developers, 2020. [En línea]. Available: https://www.scipy.org/about.html
[7] Wikipedia, la enciclopedia libre, « Tkinter », 2020. [En línea]. Available:
https://es.wikipedia.org/wiki/Tkinter
[8] The Matplotlib development team, 2018. [En línea]. Available: https://matplotlib.org
[9] Uniwebsidad, « Python para principiantes », 2020. [En línea]. Available:
https://uniwebsidad.com/libros/python/capitulo-10/modulos-de-sistema
[10] Universitat de Barcelona, « El filtrado de imágenes ». [En línea]. Available:
http://www.ub.edu/pa1/node/filtrado
[11] Wkipedia, la enciclopedia libre, « Scipy », 2019. [En línea ]. Available:
https://es.wikipedia.org/wiki/SciPy
[12] Wikilibros, libros libres para un mundo libre, « Python », 2016. [En línea]. Available:
https://es.wikibooks.org/wiki/Python/Interfaz_gr%C3%A1fica_con_Tkinter
[13] Wikipedia, la enciclopedia libre, « Interfaz gráfica de usuario », 2020. [En línea]. Available:
https://es.wikipedia.org/wiki/Interfaz_gr%C3%A1fica_de_usuario
[14] Mclibre, «Introducción a la programación con Python », 2020. [En línea]. Available:
https://www.mclibre.org/consultar/python/lecciones/python-variables.html
[15] GeeksforGeeks, «Python OpenCV». [En línea]. Available: https://www.geeksforgeeks.org/python-
opencv-cv2-cvtcolor-method/
[16] Paradigma, «¿Es Python el lenguaje del futuro? », 2018. [En línea]. Available:
https://www.paradigmadigital.com/dev/es-python-el-lenguaje-del-futuro/
67
67 Herramienta de Reconocimiento de Imágenes en Python
[17] Pythones, « Crear, guardar y ejecutar scripts de Python », 2020. [En línea]. Available:
https://pythones.net/archivos-py-crear-guardar-y-ejecutar-scripts-de-python/
[18] Significados, « Significado de Compilación », 2020. [En línea]. Available:
https://www.significados.com/compilacion/
[19] López Vega, Jeder, « Análisis y diseño de algoritmos: El proceso de compilación ». [En línea].
Available:
http://libroweb.alfaomega.com.mx/book/477/free/ovas_statics/lec_adicionales/Compiladores.pdf
[20] Hector Costa, « PyInstaller » , 2019. [En línea]. Available:
https://docs.hektorprofe.net/python/distribucion/pyinstaller/
[21] Recursos Python, 2020. [En línea]. Available: https://recursospython.com/guias-y-manuales/instalar-pil-
pillow-efectos/
[22] Covantec R.L., « Funciones», 2018. [En línea]. Available: https://entrenamiento-python-
basico.readthedocs.io/es/latest/leccion5/funciones.html
[23] Python, «Servicios genéricos del sistema operativo: os », 2020. [En línea]. Available:
https://docs.python.org/2/library/os.html
[24] LinuxAdictos. [En línea]. Available: https://www.linuxadictos.com/breve-aclaracion-sobre-los-entornos-
graficos-libres.html
[25] Real Python, « Uso de PyInstaller para distribuir fácilmente aplicaciones de Python », 2020. [En línea].
Available: https://realpython.com/pyinstaller-python/#limitations
Referencias
68
69
GLOSARIO
FFT: Transformada Rápida de Fourier
3D: Tres Dimensiones
SO: Sistema Operativo
GUI: Interfaz Gráfica de Usuario
3D: Entorno de Desarrollo Integrado
API: Interfaz de Programación de Aplicaciones
Glosario
70