CREANDO APLICACIÓN PARA LEER CÓDIGOS «QR» CON LA CÁMARA WEB.

Bienvenidos una semana más a vuestro blog sobre programación en Python. Como recordarán, en semanas anteriores vimos el modo en que podíamos efectuar la lectura de códigos «QR«, en python, (aunque en esta ocasión haremos uso de la librería «pyzbar«). A su vez, hace dos semanas, vimos como podíamos hacer uso de la cámara web, usando «opencv«. Hoy vamos a combinar los conocimientos que adquirimos en esas ocasiones para crear un sencillo programa (a cuyo código integro podéis acceder a través del enlace que dejo al final), mediante el cual podremos efectuar la lectura de dichos códigos de un modo sencillo:

La aplicación, como se ve, consistirá en una ventana, con un espacio en el que se mostrará la entrada recogida por la cámara (cuando esta sea activada mediante el botón «INICIAR CAPTURA POR CAMARA«), de modo que una vez iniciada la cámara, simplemente tendremos que poner el código a leer, delante de la misma, hasta que su información aparezca en el espacio de texto inferior. A su vez, (sin necesidad de usar la cámara) nuestra aplicación nos dará la opción de leer códigos, a partir de archivos «jpg» o «png» almacenados en nuestro ordenador, con el botón «CARGAR ARCHIVO» (esta opción también nos permitirá detectar códigos de barras). Finalmente, podremos leer, directamente, códigos que pueda haber en pantalla, usando el botón «DETECTAR EN PANTALLA» (para lo que nos ayudaremos de la librería «pyautogui«).

Visto someramente en que va a consistir nuestra aplicación, comenzaremos a escribir nuestro código. Para lo cual, naturalmente, empezaremos importando las librerías y recursos que va a emplear nuestro programa para realizar su función:

Como se ve, son varios los recursos y librerías que vamos a emplear: «tkinter» para la elaboración de la ventana, con sus elementos (canvas, botones y caja de texto), «pyzbar» para la lectura de los códigos «QR» (y eventualmente, también, de barras), «pyautogui» para car capturas de pantalla, «numpy«, para trabajar con los arrays de los frames generados por la cámara, «opencv» («cv2») fundamentalmente, pare el uso de la cámara web y «PIL» («pillow») para mostrar los frames generados por la cámara, en el visor. Hemos de señalar también que algunas de estas librerías («opencv«, «pyautogui«, «numpy«, «PIL» y «pyzbar«) deberán haber sido instaladas previamente en nuestro equipo (para lo que podremos usar, en «windows», el comando «pip install «) para poder usarlas. Una vez importados los recursos, pasaremos a iniciar la clase (a la que llamaremos «App«) que contendrá los elementos y funciones de nuestro programa:

La clase App (que iniciaremos con la función «def __init__()«) empezará creando los elementos visuales de nuestra aplicación: Empezando por la ventana misma (que crearemos con «self.ventana=Tk()«) en la que insertaremos los tres botones (definidos en los objetos «self.btnLoad«, «self.btnCamera» y «self.btnScreen«) el espacio de texto en el que se mostrará la información leída (con «self.display») y el objeto canvas, en el que se mostrará la imagen, captada por la cámara web («self.canvas«). A su vez, usaremos «mainloop()» para mostrar la ventana abierta.

Ejecutando lo hecho hasta ahora, obtendremos nuestra interfaz tal y como se muestra en la imagen sobre estas líneas. No obstante, nuestro programa aún no puede hacer nada (aparte de mostrar la referida ventana) siendo necesario incluir las distintas funciones encargadas de leer los códigos «QR» y mostrar el resultado de la lectura en el «display» inferior.

Empezaremos por la función encargada de leer información, a partir de un archivo «jpg» o «png», almacenada en nuestro equipo (esta se ejecuta con el botón «self.btnLoad«, «CARGAR ARCHIVO«). Dicha función llevará por nombre «abrir()«:

Esta función usará el método «askopenfilename()» para que, navegando por nuestro sistema de carpetas, podamos escoger el código «QR» en formato «png» o «jpg» que queramos leer. De modo que si por dicho procedimiento seleccionamos un archivo («if ruta != «»«) este (que será un archivo de imagen) será leído por nuestro programa (con «cv2.imread(ruta)«) siendo almacenada dicha lectura en la variable «archivo«. Sobre este archivo es el que vamos a aplicar la función de lectura «decode()«, que solo devolverá (en la variable «info«) un resultado, si en el archivo de imagen, se detecta un código «QR» (en cuyo caso después de borrar el contenido que pueda haber en la caja de texto («self.display.delete(‘1.0’.END)«) insertaremos el texto correspondiente a la información leída («self.display.insert(END,self.info[0][0])«). Si con tal operación, no se detecta ningún «QR» mostraremos la correspondiente ventana de aviso («messagebox.showwarning()«):

La segunda opción de lectura es la que aplicaremos seleccionando el botón «DETECTAR EN PANTALLA» (elemento «btnScreen» en nuestro script) mediante una nueva función de nombre «screen_shot()«:

Esta función usa el método «.screenshot()» de la librería «pyautogui» para realizar una captura de pantalla, en la que se supone que se encuentra el código «QR» a leer. Esta captura crea un archivo de imagen «.jpg» que, de modo similar al caso anterior, será tomado como argumento de la función «decode()» de modo que se si esta consigue detectar el «QR» mostrará su información en el cuadro de texto inferior. En caso contrario, mostrará la correspondiente ventana de código no encontrado.

La tercera (y última) vía de lectura, que ofrecerá nuestro programa es, también, la principal, ya que es la que va a hacer uso de la cámara web de nuestro dispositivo para la lectura del «QR«. Dicha vía de lectura comenzará con la ejecución de la función «active_cam()«:

El cometido de esta función no es otro que el activar o desactivar la cámara web, en función del estado actual de la variable «active_camera» (que definimos al crear la ventana, con un valor inicial de «False» («self.active_camera=False«)). De modo que si el estado actual de dicha variable es «False» («if self.active_camera==False:«), en primer lugar cambiará su valor a «True» y pasará a ejecutar las funciones «VideoCaptura()» (para iniciar la cámara) seguida de la función «visor()» ,para mostrar en el componente canvas, el contenido de la entrada de la cámara (ambas funciones las veremos a continuación). Por contra, si el valor de «active_camera» no es «False» (por ser «True«), en primer término cambiará su estado a «False«, finalizará la cámara («self.vid.release()«) y borrará el contenido que haya en el componente canvas («self.canvas.delete(‘all’)«) para dejar la pantalla del visor en negro. A su vez, cambiaremos el texto del botón «btnCamera» a «INICIAR CAPTURA POR CAMARA».

Como hemos dicho, al activar la cámara la primera función que se ejecutará será «VideoCaptura()«:

Una de las circunstancias que debemos tener en cuenta, para que nuestro programa acceda a la cámara, es si esta, se encuentra o no activada. Así para evitar errores derivados del intentar acceder a una cámara no activada, después de crear el objeto encargado de acceder a la misma («self.vid=cv2.VideoCapture()«) asegurarnos de que esta está encendida («self.vid.isOpened()«) de modo que si se da dicha circunstancia («if self.vid.isOpened():«) pasar a adaptar las dimensiones del componente canvas al alto y ancho de la imagen de entrada de la cámara. Por contra, si la cámara no se encuentra activa, para evitar errores en el programa, abriremos una ventana de aviso con el correspondiente mensaje de error, tras lo cual, como se ve en el código , el valor de la variable «active_camera» volverá a su estado original («False«).

Una vez que, se ha comprobado que la cámara está activada, y (en caso afirmativo) una vez que las dimensiones del canvas se ha adaptado a las dimensiones de los futuros frames de entrada, pasaremos a mostrar la entrada en el canvas, con la función «visor():

El cometido de esta función es bien sencillo: El de mostrar, en la pantalla de la cámara, con una periodicidad de 0,015 segundos, los frames, obtenidos por la misma, mostrando sucesivamente cada frame en el canvas mediante el método «create_image()«. Dichos frames, a su vez, serán creados por la función «get_frame()» que vemos a continuación:

Esta función será la encargada de ir proporcionado, a la función «visor()», cada uno de los «frames», que, por medio del método «.read()» («self.vid.read()«), irá generando a partir de la información de entrada de la cámara web (el producto de esa lectura se almacenará en la variable «frame«) otra variable que nos proporcionará aquí «self.vid.read()» es «verif«, la cual la cual adoptará un valor «True» o «False» en función de si la lectura puede o no efectuarse (la lectura no podrá realizarse si la cámara, estando activada, está sin embargo, siendo utilizada por otra aplicación). Así, si el valor de «verif» es «True» (o lo que es lo mismo: «if verif:«) la función devolverá el frame a «visor()» para que esta lo muestre en el canvas. De no ser así, («else:«) se mostrará una nueva ventana de aviso, tras lo que el estado de «active_camera» retornará a «False«.

Otra consecuencia que, dentro de la función «get_frame()» tendrá «verif=True», es que, al «frame» generado le aplicaremos la función «capta()«:

Lo que hará esta función es tomar cada uno de los frames generados por la función anterior, e ir aplicando la función «decode()» para decodificar el contenido de códigos «QR«. El resultado de esta operación será una lista (asignada a la variable «info«) con la información de dicho «QR«. No obstante, si en el frame analizado no se detecta ningún «QR» (por no haberse puesto este delante de la cámara), el resultado de dicha operación será una lista vacía («info = []«). Por contra, si en el frame se detecta un código «QR» cuya información puede leerse («if self.info!=[]:«), pasaremos a limpiar el contenido que pueda haber en el display de texto, («display.delete()«) e insertar el texto correspondiente al contenido decodificado del «QR» («self.display.insert(END,self.info[0][0])«). También en este caso procederemos a dibujar sobre el «frame» un rectángulo que enmarque el código detectado/leído, con la función «draw_rectangle()«:

La función «draw_rectangle()» dibujará un recuadro azul que enmarcará el «QR» detectado.

El cometido de «draw_rectangle()«, como puede deducirse por su nombre, es el de dibujar sobre los frames que se muestran en el canvas, un el rectángulo en el que se enmarca el código «QR» detectado. Para la creación de dicho rectángulo (cuyas dimensiones, se actualizarán frame a frame, con el movimiento del «QR» delante de la cámara y que vendrá definido por las variables «x«, «y» (coordenadas de posición) y «w» y «h» (anchura y altura del código detectado) usaremos el método «rectangle()» en el que también definiremos el color de su contorno («(255,0,0)» en «BGR«, correspondiente al azul) y un grosor de 6. Igualmente incorporaremos un texto («QR Code«) en rojo, con el método «putText()«.

Finalmente, incluiremos la función («def __del__(self):«) para finalizar el programa, la cual, al cerrar la ventana del programa, finalice la cámara («self.vid.release()«) en caso de que esta esté siendo usada por el programa al tiempo de cerrarlo («if self.active_camera==True:«).

Con lo visto, tendríamos creada nuestra sencilla aplicación para lectura de códigos «QR» en Python y cuyo script completo podéis ver en el siguiente enlace:

https://github.com/antonioam82/QR_Camera/blob/master/QR_Camera.py

Una segunda versión, de esta aplicación, con visor de cámara desplegable, puede verse en el siguiente enlace:

https://github.com/antonioam82/QR_Camera/blob/master/QRCamera_new.py

Saludos.

COPIANDO TEXTO, EN EL BLOC DE NOTAS, CON PYTHON Y «pyperclip»

Saludos y bienvenidos una semana más a «El Programador Chapuzas«. En nuestro trabajo diario, no es infrecuente el que en determinadas ocasiones necesitemos copiar un texto a nuestro bloc de notas. Para ello seleccionamos la información a «copiar» para a continuación pegarla en el documento deseado. No obstante, dicha tarea puede verse simplificada haciendo uso de la librería «pyperclip» para Python, la cual instalaremos mediante el comando «pip install pyperclip«.

Para ver como podemos realizar dicha acción, empezaremos creando un nuevo archivo «.py» al que llamaremos «clipboard_copy.py«, en el que empezaremos importando nuestra librería «pyperclip» (además de «sys» y «time«) :

La idea de nuestro programa consiste en que una vez seleccionado nuestro texto, este se copie (acción que se llevará a cabo mediante «pyperclip.paste()«) de forma directa en nuestro bloc de notas, simplemente seleccionando la opción «copiar«:

Como se ve, nuestro programa se ejecutará en un bucle (que se repetirá cada 0,1 segundos) en el que una variable «copia» contendrá el texto copiado mediante el referido método «pyperclip.paste()«. De modo que, siempre que este sea distinto a la última copia realizada, («if copia != ultima_copia:«), se procederá a su escritura en el documento «clipboard.txt» (previamente creado, con el nombre de «f«) con el formato indicado por nosotros.

Así, si ejecutamos el código sobre estas líneas, cuando pinchemos en la opción «copiar«, el texto seleccionado, quedará automáticamente copiado en nuestro documento «clipboard.txt«:

Llevada a cabo esta sencilla operación, podremos comprobar como en nuestro directorio de ejecución a aparecido un nuevo archivo de nombre «clipboard.txt«, con el texto copiado.

De modo que si abrimos dicho archivo, encontraremos el texto que acabamos de copiar:

Como hemos visto, nuestro programa se desarrolla dentro de un bucle. De modo que, mientras no lo cerremos, podremos repetir la operación de copiado tantas veces como queramos:

En el siguiente enlace tenéis el código del programa:

https://github.com/antonioam82/ejercicios-python/blob/master/clipboard_copy.py

Saludos.

USO DE CÁMARA WEB Y GRABACIÓN DE IMAGEN, EN PYTHON, CON «opencv».

Bienvenidos una vez más a vuestro página sobre programación en Python en una ocasión en la que nos disponemos a explicar el modo en que podemos hacer uso de la librería «opencv» para mostrar la información de entrada de la cámara de nuestro dispositivo. Puesto que vamos a hacer uso de «opencv«, nos aseguraremos de tener dicha librería instalada en nuestro equipo (de no ser así podemos usar el comando «pip install opencv» para instalarla con el «cmd» ).

MOSTRAR ENTRADA DE CAMARA.

Lo primero que vamos a aprender, es como podemos usar «opencv» para mostrar la imagen captada a través de la cámara de nuestro equipo. En realidad se trata de un procedimiento bien sencillo, que puede efectuarse en pocas líneas:

Como se ve, lo primero que haremos para crear nuestro visor, será importar las librería «opencv«, tras lo cual, procederemos a iniciar nuestra cámara (con el método «VideoCapture()«) creando el objeto «cap» («cap=cv2.VideoCapture(0)«). Una vez, iniciada la cámara, usaremos un «while» en el que el método «cap.read()» irá realizando sucesivas capturas de la imagen captada por la cámara (cada una de estas capturas sucesivas serán asignadas a la variable «frame»). Tras ello, cada una de estas capturas (frames) irán siendo mostradas en pantalla mediante el método «cv2.imshow()» que tomará como argumentos el título de la ventana y la imagen a mostrar (la captura contenida en la variable «frame«). Para finalizar este bucle (con «break«) estableceremos que este se produzca al pulsar «q» en el teclado («if cv2.waitkey(1) & 0xFF=ord(‘q’):«). Para terminar, una vez roto el bucle, finalizaremos la cámara («cap.release()«) y cerraremos la ventana («cv2.destroyAllWindows()«).

Como se puede observar, el método «cap.read()«, además de devolvernos la imagen capturada por la cámara (variable «frame«), también nos devuelve un valor booleano (variable «ret«) que será «True» cuando la cámara este disponible para uso, y «False» en caso contrario. Esto nos servirá para evitar que nos surja un error cuando intentemos ejecutar nuestro código, estando la cámara desactivada o siendo utilizada por otra aplicación:

En este caso hemos hecho que los frames se muestren con su color natural, no obstante, podemos usar distintos métodos y funciones que introduzcan cambios en los mismos (por ej: en el color). Así, podemos mostrar la imagen de salida en una escala de grises. Para ello no tendremos más que aplicar «cv2.COLOR_BGR2GRAY» a cada uno de los frames, guardando el resultado en una variable, a la que hemos llamado «gray» y que finalmente mostraremos en la ventana con «cv2.imshow(‘Visor’,gray)«:

GRABACIÓN DE VÍDEO:

Hasta ahora hemos visto el modo de mostrar en una ventana de «opencv«, el contenido captado por la cámara de nuestro dispositivo. A continuación, emplearemos un procedimiento similar, para guardar nuestra captura en un formato de vídeo:

En este caso, tras iniciar la cámara como en el caso anterior, pasaremos a definir el «codec» que vamos a usar para comprimir los sucesivos «frames«, para crear el vídeo («fourcc=cv2.VideoWriter_fourcc(*’XVID’)«) siendo ‘XVID‘ los caracteres que definirán el «codec» empleado. A continuación, creamos el objeto que albergará el contenido de nuestro vídeo, con el método «VideoWriter()» introduciendo como argumentos, el nombre del futuro archivo, el codec empleado, los «frames» por segundo, y sus dimensiones. Tras ello, iniciaremos el proceso de grabación, siempre que esté activada la cámara, de un modo similar al de los ejemplo anteriores, salvo que, como estamos grabando, usaremos el método «.write()» para añadir el contenido al objeto de vídeo «out«. Terminado el proceso de grabación, finalizaremos la cámara, el objeto de grabación y cerraremos la ventana.

Con esto tendríamos visto, tanto el modo de usar nuestra cámara web con Python, como la manera de efectuar la grabación de la información de entrada de la misma. A partir de este punto, solo nos queda aplicar lo visto, para incorporar el uso de este dispositivo a nuestras aplicaciones.

Saludos.

CREACIÓN DE ARCHIVOS Y CARPETAS TEMPORALES EN PYTHON.

Bienvenidos una semana más a este, vuestro blog sobre programación en Python. No es raro que cuando ejecutamos un programa, este nos genere algún tipo de información, (por ejemplo, en forma de archivo). A su vez, tampoco es infrecuente el hecho de que tal generación de archivos sea de carácter puramente instrumental, siendo así, que una vez usado dicho archivo por nuestro programa, no queramos que este quede almacenado en nuestro equipo. Es aquí donde surge la idoneidad de emplear archivos temporales, cuya creación y gestión (haciendo uso del módulo «tempfile» de python) será el tema de este artículo.

Como hacemos habitualmente, ilustraremos la creación de archivos temporales mediante un sencillo ejemplo, consistente en un script que constará únicamente de una función («ver_archivo()«), la cual, creará un archivo temporal, sobre el que escribirá un texto antes de mostrarlo, y que finalmente borrará:

Como se ve, lo primero que hacemos es importar «tempfile» que es el módulo que necesitamos usar para crear este tipo de archivos, Tras ello hemos creado la función encargada de crear y mostrar el contenido de nuestro archivo temporal, para, finalmente, borrarlo. Como se ve también, hemos empezado creando el archivo temporal («temp«) haciendo uso de la clase «TemporaryFile()«. Esto creará nuestro archivo, que, en principio estará vacío. Así, a continuación, hemos procedido a escribir un sencillo texto, en el, mediante el método «write()«. Una vez, escrito el nuestro archivo temporal, procederemos a leer el contenido del mismo (donde con el valor ‘0’ en «temp.seek()«, estamos indicando que la lectura se efectúe desde el primer caracter de la cadena) con el método «read()«, mostrando a continuación e resultado («conten«) en pantalla. Una vez efectuada la operación, borraremos el archivo temporal usado, con «temp.close()«. De este modo, si ejecutamos veremos nuestro texto (en bytes) en pantalla:

En el ejemplo anterior hemos visto como crear un archivo temporal en formato «bytes» (razón por la que hemos escrito «b'» antes de nuestro contenido). No obstante, también podemos hacerlo en formato «string». Para lo cual introduciremos «w+t«, como argumento de la clase «TemporaryFile()«:

Como vemos, después de crear, abrir y mostrar el contenido de nuestro archivo temporal, procedemos a eliminarlo en tiempo de ejecución de nuestra función «ver_archivo()«, con «temp.close()«. Sin embargo existe otro procedimiento para trabajar con archivos temporales que no requiere esa última acción, con la consiguiente reducción del número de líneas en nuestro código:

Por otra parte, en ocasiones, puede ser necesario que nuestro programa «conozca» datos tales como el nombre y ubicación que está usando de modo temporal. Así para ello podemos hacer uso del atributo «.name«:

De modo que al ejecutar nuevamente obtendremos la ruta y el nombre del archivo temporal (en este caso «tmp4eul3xpw«) que se ha creado, y que hemos usado para mostrar el texto:

A su vez, del mismo modo que en ocasiones podemos necesitar que nuestro programa haga uso de archivos que no queremos que queden guardados, también puede suceder que necesitemos crear una carpeta temporal para albergar más de un archivo. Para ello, deberemos usar la clase «TemporaryDirectory()» de forma similar que en el caso anterior:

En este caso, nuestra función se limitará a crear un nuevo directorio, cuya ruta imprimiremos, introduciendo el nombre de variable con la que la hemos denominado («temp«):

Hemos visto así, un sencillo procedimiento para crear archivos temporales, los cuales, evitarán que acaben almacenandose en nuestro equipo, archivos y directorio, cuya único cometido sea ser empleados por nuestro programa, unicamente durante su ejecución.

Saludos.