OpenCV
Por Julia Saenz
Última actualización
Por Julia Saenz
Última actualización
Palabras Clave
Cascadas de Haar, OpenCV, Visión computacional
Programa que detecte y siga la posición de la mano
Conocimiento básico de paradigma orientado a objetos
OpenCV (Open Source Computer Vision Library) es una librería de visión computacional y machine learning orientada especialmente a aplicaciones de visión en tiempo real.
OpenCV for Processing es la librería de OpenCV desarrollada específicamente para ser utilizada con el entorno de programación Processing. Está basada en la versión de OpenCV para Java y tiene soporte para Linux, MacOS y Windows, pero no Android. Las funcionalidades de esta librería son mucho más reducidas que la versión original: puede reconocer diferencias entre dos imágenes para eliminar fondos o detectar nuevos objetos, encontrar líneas, contornos o bordes de una imagen, trabajar con los canales de color de una imagen o detectar algún objeto o parte del cuerpo específica mediante las cascadas de Haar que vienen con la librería o cascadas importadas.
Esta última es la funcionalidad que usaremos para la detección de una parte del cuerpo.
Las cascadas de Haar son un método de detección de objetos basado en imágenes. Se configuran mediante imágenes que tienen aquello que se quiere detectar (imágenes positivas) e imágenes que no lo tengan (imágenes negativas), a partir de las cuales se extraen y agrupan las características que hacen al objeto que se quiere reconocer.
Una vez configurada la cascada, para realizar la detección el algoritmo recorre la imagen y evalúa si cumple con todas las características encontradas, yendo de la más general a la más particular.
Esta entrada sigue la estructura planteada en la página "Detección del cuerpo con Processing" por lo que se recomienda leerla antes de continuar
En este ejemplo vamos a realizar una detección de manos usando la librería OpenCVForProcessing. Para esto vamos a crear una clase Detector
a la cuál le vamos a pasar la entrada de la cámara web y nos va a retornar la posición de la mano más cercana a la cámara.
Empezamos importando la librería, cuya guía de descarga se puede encontrar en su página:
Nuestra clase Detector
va a tener 4 atributos:
Un objeto de tipo openCV
, que es lo que nos va a permitir hacer la detección
La posición en x
e y
de la mano detectada, que inicializamos fuera de la pantalla
Un objeto de tipo Timer
que nos permite detectar si no hay nadie en la escena
Un número de easing
que permite suavizar el movimiento de la detección
Esta clase va a recibir 2 parámetros:
El sketch
sobre el que se va a ejecutar, cuyo nombre corresponde al nombre con el que se guardo el archivo
Un String
de la ruta en la que se aloja la cascada
El sketch
es necesario para indicarle al objeto OpenCV
donde tiene que realizar la detección, en este caso dentro de nuestra pantalla. Cuando llamemos a la clase Detector
desde nuestro programa principal le vamos a pasar el parámetro this
indicando nuestro programa.
La ruta indica la ruta absoluta en donde está ubicada la cascada que vamos a utilizar. El librería de openCV tiene incluidas algunas cascadas, pero para detectar manos necesitamos pasar una propia. La desventaja de que pida una ruta absoluta (en lugar de una relativa) es que cada vez que el archivo se mueve de lugar, ya sea dentro de la misma computadora o una distinta, tiene que actualizarse la variable ruta para indicar la nueva posición del archivo.
Una vez que tenemos esos parámetros podemos inicializar nuestro Detector
.
openCV
recibe el sketch
y las dimensiones de la cámara, luego se carga la cáscada con la que vamos a hacer la detección mediante el método .loadCascade(ruta,true);
y el Timer
lo iniciamos con el tiempo en segundos que tiene que pasar sin cambios en la pantalla para que se detecte que una persona se fue. Dejarlo en 2 o 3 segundos permite asegurarnos que no se pierda el seguimiento de la mano si por algún momento breve falla la detección.
Una vez inicializado el objeto Detector
podemos empezar a configurar la detección de la mano, para lo cual vamos a usar un método que llamaremos medicion()
que va a recibir el feed (la imagen de la cámara) y va a pasar por cada uno de sus frames la cascada para detectar la presencia de manos en la escena.
Para realizar la detección son necesarios dos métodos del objeto openCV
:
.loadImage( imagen )
recibe la escena sobre la que vamos a realizar la detección
.detect( ScaleFactor, MinNeighbour, flags, minSize, maxSize )
realiza efectivamente la detección sobre la escena, retornando un arreglo de rectángulos correspondiente a cada instancia de mano detectada
Este último método puede llamarse sin la necesidad de los parámetros indicados, pero no es recomendable ya que estos son los que permiten controlar cómo se está realizando la detección y son la mejor forma de minimizar falsas detecciones.
Acá agregar imagen de la diferencia de detección con parámetros y sin parámetros
Estos son cada uno de los parámetros, sus función y los parámetros recomendados:
ScaleFactor
refiere a cuánto más chico es el sector en el que detecta la cascada cada pasada; el valor por defecto es 1.1, por lo que en cada pasada el sector es 10% más chico que el anterior. Un número más cercano a 1 implica una detección más lenta pero más meticulosa y un número más alejado corresponde con una detección más rápida pero menos precisa
MinNeighbours
corresponde con la cantidad mínima de detecciones positivas que tiene que tener una detección para guardarse finalmente en el arreglo. Se recomienda un valor entre 1 y 5, pero dependerá en cada caso
flags
solía usarse para especificar distintos modos de detección pero que ahora no se utiliza, por lo que el valor se deja en 0
minSize
y maxSize
estos dos últimos parámetros indican el menor y mayor tamaño en píxeles que puede tener el objeto detectado, pudiendo así eliminar positivos que aparezcan más cerca o más lejos de lo que se espera
La variable deteccion
ahora aloja todas las instancias detectadas de manos en nuestra escena. Idealmente, solo se detecta la instancia que nos interesa (en este caso, la mano más grande de la escena), pero como eso no siempre es posible, va a ser necesario hacer un recorte de esa detección.
Adicionalmente, vamos a usar el Timer
para asegurarnos de no perder el seguimiento de la mano antes de tiempo. Para esto preguntamos si se detectó algo (si el arreglo de detecciones tiene elementos) y si es el caso actualizamos el temporizador. Cuándo no está detectando nada (no hay nadie en la escena) deja de actualizarse y si pasa el tiempo indicado (en nuestro caso 2 segundos) podemos asumir con seguridad que no hay nadie en la escena.
Ahora que ya tenemos el arreglo de detecciones y una forma de asegurarnos de no perder un seguimiento antes de tiempo, podemos pasar a elegir qué mano detectada vamos a seleccionar y mostrar en pantalla. Esto lo vamos a hacer usando 2 métodos:
rectMasGrande( deteccion )
nos va a devolver el rectángulo más grande del arreglo
puntoMedio( detecccion, i)
va a calcular y dibujar el punto medio del rectángulo
Además tendremos un método con el cuál podemos ver todas las manos detectadas en tiempo real, con el fin de poder configurar la cascada.
El método medicion()
queda entonces de la siguiente forma:
El método mostrarDeteccion( deteccion )
recibe el arreglo de rectángulos y muestra todas las instancias detectadas. Es usado solamente para calibración, por lo que es privado a la clase.
El método rectMasGrande( deteccion )
recorre el arreglo de detecciones y devuelve solamente el índice de aquel rectángulo de mayor tamaño, es decir, la detección que es más cercana a la cámara.
Una vez que sabemos el índice del rectángulo que vamos a usar, lo pasamos al método puntoMedio( deteccion, indice)
y este se va a encargar de calcular el punto medio del rectángulo, suavizar el movimiento de la detección y dibujarlo en pantalla.
Ahora que ya tenemos nuestro Detector
configurado, podemos usarlo en nuestro programa principal de la siguiente forma:
Una versión de este código está disponible en GitHub
Documentación de openCV for Processing