Читать книгу Visión artificial - Tomás Domínguez Mínguez - Страница 22

Оглавление

Unidad 5

INTERACCIÓN CON EL RATÓN Y EL TECLADO

La forma habitual de utilizar la interfaz de usuario de una aplicación es a través del ratón y el teclado. En OpenCV, dicha interacción se realiza capturando los eventos que producen estos dispositivos. Cuando se mueve o se pulsa el ratón, o cualquier tecla, dichos eventos provocan la ejecución de una función de callback, que será la encargada de realizar las acciones correspondientes. Veamos cómo funciona.

5.1 GESTIÓN DE EVENTOS DEL RATÓN

Con frecuencia, será necesario interaccionar con la imagen mostrada en pantalla mediante el ratón. Por ese motivo, OpenCV proporciona un mecanismo que permite la captura de los eventos que genera, los cuales provocarán la ejecución de la función de callback encargada de realizar las tareas correspondientes a cada uno de ellos. La forma de establecer este mecanismo de captura de eventos es mediante la función:

setMouseCallback(ventana, función)

El primer argumento es el nombre de la ventana en la que se van a capturar los eventos del ratón, mientras que el segundo corresponde al nombre de la función de callback encargada de manejarlos.

Se podría añadir un tercer argumento con los parámetros adicionales que se pasarían a la función de callback cuando se produjera el evento.

La función de callback se debe declarar con los siguientes argumentos:

función de callback(evento, x, y, flags)

El primer argumento es el evento generado por el ratón, representado por las constantes:

• EVENT_MOUSEMOVE. El puntero del ratón se ha movido.

• EVENT_LBUTTONDOWN. Se ha presionado el botón izquierdo del ratón.

• EVENT_RBUTTONDOWN. Se ha presionado el botón derecho del ratón.

• EVENT_MBUTTONDOWN. Se ha presionado el botón central del ratón (si lo hubiera).

• EVENT_LBUTTONUP. Se deja de presionar el botón izquierdo del ratón.

• EVENT_RBUTTONUP. Se deja de presionar el botón derecho del ratón.

• EVENT_MBUTTONUP. Se deja de presionar el botón central del ratón (si lo hubiera).

• EVENT_LBUTTONDBLCLK. Se hace doble clic con el botón izquierdo del ratón.

• EVENT_RBUTTONDBLCLK. Se hace doble clic con el botón derecho del ratón.

• EVENT_MBUTTONDBLCLK. Se hace doble clic con el botón central del ratón (si lo hubiera).

• EVENT_MOUSEWHEEL. Los valores positivos y negativos indican un desplazamiento hacia delante o atrás de la rueda del ratón, respectivamente.

• EVENT_MOUSEHWHEEL. Los valores positivos y negativos delatan un desplazamiento hacia la derecha o la izquierda de la rueda del ratón, respectivamente.

Los dos argumentos siguientes son las coordenadas x, y del punto en el que se encontraba el ratón cuando se produjo el evento. El argumento flags indica diferentes situaciones especiales, identificadas por las siguientes constantes:

• EVENT_FLAG_LBUTTON. El botón izquierdo del ratón está presionado.

• EVENT_FLAG_RBUTTON. El botón derecho del ratón está presionado.

• EVENT_FLAG_MBUTTON. El botón central del ratón está presionado.

• EVENT_FLAG_CTRLKEY. La tecla CTRL está presionada.

• EVENT_FLAG_SHIFTKEY. La tecla SHIFT está presionada.

• EVENT_FLAG_ALTKEY. La tecla ALT está presionada.

El siguiente programa se utiliza para escribir el tipo de evento de ratón generado, en el punto de la pantalla en el que se produjo. Por simplicidad, solo se detecta si se ha pulsado el botón derecho o el izquierdo del ratón.


En primer lugar, se importan las librerías que se van a utilizar en el programa. En este caso, además de OpenCV, se importa NumPy para crear una imagen blanca que se usará como fondo de pantalla.


Dicha imagen se obtiene con la función zeros(), tal como ya conoce.


A continuación, se declaran las variables que establecen el color del texto (rojo), su grosor, la fuente y la escala.


Luego, se muestra la ventana “Eventos raton” con el fondo blanco.

cv2.imshow(‘Eventos raton’, img)

Saltando a la última línea del programa, puede ver que se establece la función eventos_raton() como la encargada de tratar los eventos del ratón producidos en la ventana “Eventos raton”.

cv2.setMouseCallback(‘Eventos raton’, eventos_raton)

Dicha función debe ser declarada antes de esta última sentencia. De los parámetros que tiene, usará únicamente el nombre del evento y las coordenadas en las que se ha producido.


Dentro de dicha función hay una condición if que comprueba si el evento es el de la pulsación del botón derecho (cv2.EVENT_LBUTTONDOWN). De no ser así, se verificaría si corresponde al izquierdo (cv2.EVENT_RBUTTONDOWN). En caso contrario, la función no haría nada. De producirse alguno de los dos eventos anteriores, se escribiría en pantalla de cuál se trata con la función putText().


Como se ha modificado la imagen, dentro de esta función se tiene que volver a llamar a la función imshow() para mostrarla de nuevo con los cambios realizados.

cv2.imshow(‘Eventos raton’, img)

El resultado de la ejecución de este programa puede verlo a continuación, donde se aprecia que se ha pulsado dos veces el botón izquierdo del ratón y otras tantas el derecho en diferentes puntos de la ventana.


A continuación, realizará un programa de carácter más práctico, con el que conseguirá una pizarra electrónica en la que, pulsando el botón izquierdo del ratón, podrá dibujar lo que quiera. Su código es el siguiente:


Este programa es similar al anterior, por lo que solo se explicará la función de tratamiento de eventos de ratón, que ahora se llama pinta(). En dicha función, lo primero que se hace es declarar como globales las variables que fijan la posición en la que estaba situado el ratón cuando se produjo el evento anterior (x_prev, y_prev). La idea es dibujar una línea entre el punto en el que estaba el ratón en ese momento y el actual (cuando se ha disparado el evento de movimiento). La línea dibujada sería diminuta porque (en el caso ideal) uniría dos píxeles adyacentes. Eso es debido a que, cada vez que mueva el ratón lo suficiente como para pasar de uno a otro, se generaría un evento.

Pero, para dibujar en la pizarra, se debe haber presionado el botón izquierdo previamente. Por eso, la condición del primer if de esta función comprueba si se ha producido el evento cv2.EVENT_LBUTTONDOWN, asignando la posición en la que se produjo a las variables x_prev e y_prev. Será a partir de ese punto cuando se empiece a dibujar una línea.


El evento cv2.EVENT_LBUTTONDOWN no se volverá a disparar mientras mantenga el botón izquierdo del ratón pulsado. El que sí se producirá será cv2. EVENT_MOUSEMOVE al mover el ratón. Pero antes de empezar a trazar la línea siguiendo este desplazamiento, será necesario asegurar que esté pulsado el botón izquierdo del ratón, por lo que tendrá que recurrir al argumento flags, cuyo valor cv2.EVENT_FLAG_LBUTTON será el que indique este hecho.


El punto inicial desde el que se trace la línea será en el que estaba el ratón la última vez que se movió (o cuando se pulsó el botón izquierdo). El punto final corresponderá a aquel en que se encuentra actualmente. Si se siguiera moviendo el ratón, este punto sería, a su vez, el de inicio de la siguiente línea. Por eso, la posición actual se asigna posteriormente a las variables x_prev e y_prev.


Una vez realizado el cambio en la imagen (se le ha añadido una nueva línea), se visualiza de nuevo con la función imshow().

cv2.imshow(‘Pizarra’,img)


Mientras tenga el ratón pulsado, las diminutas líneas dibujadas entre píxeles se mostrarán como una sola.

El resultado de la ejecución del programa lo puede ver a continuación, al mismo tiempo que mis escasas dotes artísticas.


5.2 GESTIÓN DE EVENTOS DEL TECLADO

En este apartado aprenderá a gestionar los eventos del teclado, que utilizará básicamente para capturar la pulsación de una tecla. Para ello, OpenCV ofrece la función:

waitKey(milisegundos)

Su único argumento fija el número de milisegundos que estaría bloqueado el programa en este punto hasta que se pulsara cualquier tecla. Si su valor fuera 0, sería de forma indefinida.

El resultado de dicha función es el código Unicode de la tecla pulsada (o -1, si transcurrido el número de milisegundos indicado, no se hubiera pulsado ninguna).


Para llamar a esta función, es necesario que al menos haya una ventana activa.

En el siguiente programa, se amplía el de la pizarra electrónica del apartado anterior para poder salir de la aplicación pulsando las teclas ‘Esc’ o ‘q’. Además, al presionar el retorno de carro, pasará alternativamente del modo dibujo al de borrado. El código es el siguiente:


Solo se explicarán las diferencias con el código del programa anterior, empezando por la declaración inicial de variables, ya que se ha añadido una de tipo booleano (borrado), cuyo valor True indicaría que la aplicación está en modo borrado. Inicialmente tiene el valor False porque se comienza en modo dibujo.

borrado = False

Lo realmente novedoso de este nuevo programa es el bucle while, cuya condición True indica que podría estar ejecutándose indefinidamente.


Dentro, lo primero que se hace es llamar a la función waitKey() para esperar cierto tiempo (se ha puesto 100 ms, aunque podría ser otro diferente) hasta que se pulse una tecla. A continuación, hay una serie de condiciones que detectan si se ha pulsado el retorno de carro para cambiar del modo dibujo al de borrado o viceversa, o las teclas con las que se quiere abandonar la aplicación (‘Esc’ o ‘q’). En este último caso únicamente se ejecutaría la sentencia break, que permite salir del bucle y, en consecuencia, de la aplicación.



El código Unicode del retorno de carro es 13, mientras que el de la tecla ‘Esc’ es 27.

Si se pulsara retorno de carro, lo primero que se haría es cambiar de modo (invertir el valor de la variable borrado) y, en función de este, modificar los valores de las variables que establecen el color del trazo (color) y su grosor (grosor). En el modo borrado, el color del trazo será el mismo que el del fondo (blanco), cuyo efecto será la eliminación de cualquier línea roja que se hubiera dibujado previamente. Además, se amplía el grosor del trazo para facilitar dicho borrado.



Una vez fuera del bucle, lo que se hace es cerrar la ventana con destroyAllWindows().

cv2.destroyAllWindows()

Ya solo queda probarlo. Esta vez, podrá corregir los trazos que no le gusten.

Visión artificial

Подняться наверх