Siempre creciendo, siempre aprendiendo. Cultura maker.

¡Hola otra vez!. ¡Cuánto bueno por aquí!. ¡Pasad!. ¡Pasad!. Hoy había pensado recuperar un poquito algo de lo que ya hemos visto sobre visión por computador con Python y OpenCV, pero esta vez adaptado a un lenguaje mucho más rápido para trabajar con él desde la perspectiva de la ESO y el Bachillerato: Processing.

Como bien sabéis, el mayor problema a la hora de utilizar OpenCV como librería de programación, es su alta dificultad (muy alta) para instalarla correctamente en sistemas operativos comerciales o en Linux y utilizarla con lenguajes como Python o C++ en entornos como CodeBlocks.

Por lo que estoy averiguando y aprendiendo en las últimas semanas, parece mucho más sencillo empezar a trabajar con Processing. Como sabéis, es un lenguaje que sigue la estructura sintáctica de C++ muy rápido en la ejecución y francamente muy adecuado para la educación.

logoProcessinglogoOpenCV

 

 

En el momento de escribir estas líneas, Processing va ya por su versión 3.X. Su mayor ventaja a la hora de utilizarlo en Educación Secundaria es su extremado dinamismo, su sencillez de uso y la continua retroalimentación en el aprendizaje (cada modificación hecha en el código por los estudiantes provocará inmediatamente una reacción en la ejecución del programa). Aquí tenéis también una serie de artículos de introducción a Processing para estudiantes de la ESO que redacté en su momento (por si creéis que os puede ser de ayuda).

Otra ventaja a la hora de iniciarse en el uso de este conjunto de librerías es lo fácil que es instalarlo para Processing, frente a su contrapartida en Python u OpenCV. En el menú del IDE, nos vamos a Sketch->Importar Biblioteca->Añadir Biblioteca, y poner OpenCV en el buscador. La instalación es bastante rápida. ¡Más fácil imposible!.

instalarOpenCVComo inconveniente, hay ciertamente diferencias tanto en el modo de llamar a determinadas funciones de cada librería, como en los resultados obtenidos en algunas ocasiones. Además, hasta donde he podido ver, la documentación está algo limitada y algunos de los ejemplos incorporados por las librerías dan algunos problemas. ¡Pero bueno!. ¡Algo podremos ir aprendiendo!. ¡Vamos allá!

 

Mi ¡Hola Mundo! con Processing y OpenCV

En primer lugar, comentaros que además de la librería OpenCV necesitaréis instalar también la librería de gestión de vídeo, processing.video.* , ¡ojo! no todas las librerías valen. La que estáis buscando es la librería oficial de Processing, la que en la ventana de instalación de nuevas bibliotecas indica como autor a la Fundación Processing. Concretamente, buscáis la librería que se basa en el framework Gstreamer:

instalaVideoProcessing

¿Ya lo tenéis?. Muy bien... Empecemos pues. El primer código es muy sencillito. Se va a limitar a crear dos objetos: uno de la clase Capture (el que va a conectar con nuestra webcam), al que llamaremos  video, y otro de la clase OpenCV (que va a gestionar todas las imágenes que le vaya pasando el objeto video, y sobre las que realizará las operaciones pertinentes).

El código tiene cuatro zonas bien diferenciadas:

  1. Importación de las librerías OpenCV y video, así como la declaración de los objetos video y opencv
  2. En setup(), inicializamos los dos objetos: video, de la clase Capture, perteneciente a la librería de video, que se encargará de leer todas las imágenes que vaya grabando nuestra webcam, y opencv, de la clase OpenCV. También iniciaremos el trabajo de video con el comando video.start();
  3. En draw(), tenemos dos tareas cíclicas: pedirle a opencv que cargue la siguiente imagen del objeto video con el comando opencv.loadImage(video), para a continuación pasarla a pantalla mediante el comando image();
  4. Por último, hay una función de sistema, denominada captureEvent(), que se aplicará al objeto capture (es decir, la entrada de video de la webcam), que se pondrá en marcha cada vez que dicha cámara envíe una nueva imagen, y que se limitará a actualizar dicha imagen mediante el comando read().

Una última cosa, fijaos que en el código de ejemplo utilizo una resolución muy simple, de 640x480. Esto es así porque es la máxima resolución a la que puede trabajar mi webcam.

¿Es difícil?. ¡Claro que sí!. Si no no sería tan divertido. Probad con este código:

 

 

//Importamos librerías
import processing.video.*;
import gab.opencv.*;
//Declaramos objetos video(webcam) y opencv (gestión de imágenes)
Capture video;
OpenCV opencv;
//Configuración
void setup(){
//La resolución deberá ir acorde con la de la cámara que uséis
 size(640,480);
 video=new Capture(this,640,480);
 opencv=new OpenCV(this,640,480);
//Iniciamos video
 video.start();
}
//En esta función cíclica, opencv carga la imagen del objeto video y lo pasa por pantalla
void draw(){
  opencv.loadImage(video);
  image(video,0,0);
}
//Esta función se ejecuta automáticamente a cada nueva lectura de la webcam
void captureEvent(Capture c) {
  c.read();
}

 ¿Resultado? ¡Processing pasa por pantalla lo que ve vuestra webcam!. ¡No está mal para empezar!.

modorreoconWebcam

A continuación vamos a aplicar alguna de las poderosas herramientas que esta librería basada en OpenCV pone a nuestra disposición: los FILTROS. Uno de los filtros más utilizados es el especializado en hallar bordes. Para ello, compara la luminosidad de grupos de píxeles y establece los bordes de acuerdo a cambios en dicha magnitud en base a un valor umbral mínimo y otro máximo. El comando a utilizar es: objetoOpenCV.findCannyEdges(umbralMinimo,umbralMáximo);

Sólo vamos a hacer tres modificaciones al código anterior: en primer lugar, declararemos un objeto de tipo PImage al que llamaremos bordes. En segundo lugar, en la función draw(), justo después de cargar el objeto de tipo Capture (video en nuestro programa) en el objeto OpenCV, le aplicaremos el filtro mediante el comando arriba explicado. Por último, mediante el comando objetoOpenCV.getSnapshot() pasaremos la imagen procesada al objeto bordes,que finalmente pasará a pantalla mediante el comando Image.

¡Pero ya basta de explicaciones!. ¡Veamos el resultado!. El nuevo código es éste:

 

//Importamos librerías
import processing.video.*;
import gab.opencv.*;
//Declaramos objetos video(webcam) y opencv (gestión de imágenes)
//Declaramos también un PImage que recogerá el procesado de openCV
Capture video;
OpenCV opencv;
PImage bordes;
//Configuración
void setup(){
//La resolución deberá ir acorde con la de la cámara que uséis
 size(640,480);
 video=new Capture(this,640,480);
 opencv=new OpenCV(this,640,480);
//Iniciamos video
 video.start();
}
//En esta función cíclica, opencv carga la imagen del objeto video y lo pasa por pantalla
void draw(){
  opencv.loadImage(video);
  //aplicamos Filtro a opencv
    opencv.findCannyEdges(20,75);
  //pasamos imagen de opencv a objeto PImage
    bordes=opencv.getSnapshot();
  //objeto PImage se muestra en pantalla
    image(bordes,0,0);
}
//Esta función se ejecuta automáticamente a cada nueva lectura de la webcam
void captureEvent(Capture c) {
  c.read();
}

 Y aquí tenéis el resultado que he obtenido trasteando en el taller del instituto:

openCVcanny

Os aconsejo que trasteéis un poco jugando con los valores umbral mínimo y máximo en el comando findCannyEdges(). Notaréis que el resultado puede variar ostensiblemente.

¿Pero qué es eso que oigo?. ¡Es la campana!. ¡Hay que retomar las clases!. ¡Es la vida en el instituto!. Espero vuestros comentarios, sugerencias y/o peticiones aquí o en mi Twitter.Mientras tanto, ¡sed felices!. ¡Siempre creciendo!. ¡Siempre aprendiendo!. ¡Cultura maker!