Tag Archives: Processing

Instalación de la librería de OpenCV en Processing bajo GNU/Linux Mint 12

Introducción

En el presente artículo se describirán los pasos necesarios para instalar el software de OpenCV y su correspondiente librería para desarrollar sketches con él utilizando Processing.

Durante el desarrollo de la instalación se utilizó GNU/Linux Mint 12 sin emgbargo el procedimiento debe ser compatible con Ubuntu.

Aviso! La versión de OpenCV que se encuentra en los repositorios del sistema operativo (2.1.0-7build1) es un poco antigua, sin embargo se encontraron problemas para compilar la parte nativa de la librería con una versión mas reciente.  Por este motivo se decidió utilizar la versión disponible y experimentar posteriormente una posible actualización.

Procedimiento

Instalar OpenCV

$ sudo aptitude install libcv-dev libhighgui-dev libcvaux-dev opencv-doc

Instalar la librería de Processing

Nota!  Se recomienda descargar la última versión disponible de la página web del desarrollador.  En este caso se utilizó opencv_01.zip.

Crear el directorio donde se almacenarán las librerías de Processing del usuario.

$ mkdir -p ~/sketchbook/libraries ; cd ~/sketchbook/libraries

Descargar la librería y los ejemplos de la misma.

$ wget http://ubaa.net/shared/processing/opencv/download/opencv_01.zip
$ wget http://ubaa.net/shared/processing/opencv/download/opencv_examples.zip

Descomprimir los paquetes recién descargados

$ unzip opencv_01.zip
$ rm opencv_01.zip
$ unzip opencv_examples.zip
$ rm opencv_examples.zip

Ubicar correctamente el directorio con los ejemplos.

$ mv OpenCV\ examples/ OpenCV/examples

Recompilar el módulo nativo de la librería

La librería incluye una librería del sistema operativo (libOpenCV.so) enlazada dinámicamente con OpenCV.  La incluída con la distribución de la librería recién instalada fue compilada con versiones anteriores de OpenCV motivo por el cual no se cumplen sus dependencias y en el momento de compilar los sketches se obtiene el siguiente mensaje de error.

!!! required library not found : /home/jimezam/sketchbook/libraries/OpenCV/library/libOpenCV.so: libcxcore.so.1: cannot open shared object file: No such file or directory
Verify that the java.library.path property is correctly set and 'libcxcore.so', 'libcv.so', 'libcvaux.so', 'libml.so', and 'libhighgui.so' are placed (or linked) in one of your system shared libraries folder

Exception in thread "Animation Thread" java.lang.UnsatisfiedLinkError: hypermedia.video.OpenCV.capture(III)V
    at hypermedia.video.OpenCV.capture(Native Method)
    at hypermedia.video.OpenCV.capture(OpenCV.java:945)
    at sketch_jan12b.setup(sketch_jan12b.java:35)
    at processing.core.PApplet.handleDraw(Unknown Source)
    at processing.core.PApplet.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:662)

Por este motivo es necesario recompilar el módulo nativo con las versiones actuales.  Para hacer esto se deben seguir los siguientes pasos.

$ cd ~/sketchbook/libraries/OpenCV/library/

Crear una copia de seguridad del módulo nativo a recompilarse.

$ mv libOpenCV.so libOpenCV.so.OLD

Generar la cabecera del módulo nativo de Java (JNI).

$ javah -classpath OpenCV.jar -jni hypermedia.video.OpenCV

Recompilar el módulo nativo.

$ g++ -shared ../source/cpp/OpenCV.cpp -o libOpenCV.so -I/usr/include/opencv/ -I/usr/lib/jvm/java-1.6.0-openjdk/include/ -I. -lcv -lhighgui -fPIC

Finalmente se obtienen los siguientes archivos.

$ ls -l

-rw-rw-r– 1 jimezam jimezam  10748 2012-01-12 14:43 hypermedia_video_OpenCV.h
-rwxr-xr-x 1 jimezam jimezam  80088 2009-05-27 13:15 libOpenCV.jnilib
-rwxrwxr-x 1 jimezam jimezam  41953 2012-01-12 16:16 libOpenCV.so
-rwxr-xr-x 1 jimezam jimezam  42861 2009-05-27 13:15 libOpenCV.so.OLD
-rwxr—– 1 jimezam jimezam 515184 2009-05-27 13:15 OpenCV.dll
-rw-r–r– 1 jimezam jimezam  12116 2009-05-27 13:15 OpenCV.jar

Instalar los perfiles de reconocimiento

Los perfiles de reconocimiento son archivos XML donde se estructura el conocimiento que le permite a la librería reconocer rostros sin la necesidad de mayor entrenamiento.  La versión actual de los paquetes de OpenCV en los repositorios instala estos perfiles en una ubicación que no permite que sean utilizados fácilmente desde Processing.  Los siguientes pasos corrígen esta situación.

$ sudo cp -R /usr/share/doc/opencv-doc/examples/haarcascades /usr/share/opencv/
$ sudo gunzip /usr/share/opencv/haarcascades/*.gz

Sketch de prueba

Una vez instalada la librería se podrán desarrollar sketches con ella, a continuación se presenta el sketch mas sencillo posible que muestra la imagen proveniente de la cámara web utilizando OpenCV.

import hypermedia.video.*;
OpenCV opencv;
void setup()
{
  size(640, 480);
  opencv = new OpenCV(this);
  opencv.capture(width,height);
}
void draw()
{
    opencv.read();
    background(opencv.image());
}

Enlaces

Utilizar la cámara infraroja (IR) del Kinect utilizando Processing

Introducción

Así como inicialmente se accedió a las imágenes RGB (convencional) y de profundidad de las cámaras del Kinect, también es posible acceder a la información proporcionada por la cámara infraroja con la misma facilidad.

Screenshot

Imagen de profundidad | Imagen infraroja

Imagen de profundidad | Imagen infraroja


Enlaces

Búsqueda del punto mas cercano con el Kinect utilizando Processing y Simple-OpenNI

Introducción

El siguiente paso lógico consiste en identificar cual es el punto mas cercano al Kinect, presumiblemente el usuario que interactúa con el sketch, para utilizar este valor como coordenada de entrada.

Su implementación se reduce simplemente a recorrer el mapa de profundidad de alta resolución (context.depthMap()) que provee la cámara de profundidad y obtener de allí la coordenada cuyo valor sea menor pero mayor a cero ya que este corresponde a las áreas no medidas.  Para mayores detalles acerca de la implementación referirse a la función int[] findClosestPoint(int, int).

Para hacerlo un poco mas interesante se agregaron dos barras de desplazamiento en la parte inferior que sirven para limitar la profundidad de los objetos que van a ser realmente tenidos en cuenta en la determinación del punto mas cercano, esto con el fin de aislar otras zonas de acuerdo a su distancia que no quieran ser tenidas en cuenta y puedan estar produciendo interferencia.  Hacia la izquierda de las barras de desplazamiento la distancia es menor (mas cerca del Kinect) y hacia la derecha la distancia crece (se aleja del Kinect).

Basado en esta característica se agregó la funcionalidad de aislar las porciones de la imagen de los objetos que no se encuentran ubicados en el rango de profundidad válido.  Para conmutar entre imagen completa e imagen parcial sólo es necesario presionar la letra 't' (toggle) en el sketch.

Screenshot

Punto mas cercano al Kinect filtrado por un rango de distancia

Punto mas cercano al Kinect filtrado por un rango de distancia

Separación de la imagen mostrando sólo los objetos ubicados en la distancia válida

Separación de la imagen mostrando sólo los objetos ubicados en la distancia válida

Enlaces

Prueba de las cámaras del Kinect utilizando Processing

Introducción

Este sketch es una demostración simple del uso de las cámaras del Kinect utilizando Processing y la librería Simple-OpenNI.  Se incluyen las siguientes características.

  • Mostrar las imágenes provenientes de la cámara de profundidad
  • Mostrar las imágenes provenientes de la cámara RGB (video convencional)
  • Mostrar la información de color/brillo de un punto específico de una imagen
  • Calcular la distancia física entre la cámara y el punto elegido en el mundo real.

Requisitos

  1. Librería OpenNI
    http://blog.jorgeivanmeza.com/2011/12/instalacion-openni-sensor-kinect-y-nite-en-gnulinux-ubuntu-11-10-desde-fuentes/
  2. Librería Simple-OpenNI para Processing
    http://blog.jorgeivanmeza.com/2012/01/construccion-de-la-libreria-simple-openni-para-processing-bajo-ubuntu-de-32-bits/
  3. Processing
    http://www.processing.org/

Screenshot

Demostración imágenes de profundidad y RGB

Demostración imágenes de profundidad y RGB

Al hacer clic izquierdo sobre cualquiera de las imágenes se obtiene información del color/brillo del pixel seleccionado y en el caso de la imagen de profundidad se obtiene además el cálculo de la distancia física entre la cámara y el punto elegido en el mundo real.

Bright: r = 175
Distance: 2443 mm/96.18111 inches

Bright: r = 81
Distance: 2609 mm/102.71654 inches

Color: r = 49; g = 66; blue = 51

Color: r = 73; g = 53; blue = 11

Enlaces

Construcción de la librería Simple-OpenNI para Processing bajo Ubuntu de 32 bits

Introducción

Simple-OpenNI es una librería de Processing que actúa como un recubrimiento (wrapper) para utilizar fácilmente OpenNI desde este lenguaje de programación.

La distribución binaria de esta librería puede ser descargada directamente desde el sitio web del proyecto.  En el presente artículo se describirán los pasos necesarios para construír esta librería a partir de su distribución de fuentes lo cual resulta interesante para garantizar compatibilidad con las versiones de las librerías nativas instaladas y mantener la última versión disponible, así como utilizar arquitecturas cuyas distribuciones binarias no se encuentren disponibles.

Prerequisitos

Para poder construír la librería bajo GNU/Linux Ubuntu es necesario contar con los siguientes requisitos previamente instalados.

  1. OpenNI y NITE
  2. Java Development Kit.
    $ sudo aptitude install openjdk-6-jdk openjdk-6-jre openjdk-6-jre-headless openjdk-6-jre-lib
    Activar la versión recién instalada: /usr/lib/jvm/java-6-openjdk/jre/bin/java
    $ sudo update-alternatives –config java
  3. CMake
    $ sudo aptitude install cmake
  4. Swig >= v2.0.2
    $ sudo aptitude install swig
  5. Eigen >= v3.0
    $ sudo aptitude install libeigen3-dev
  6. Boost >= v1.46 (use the static build)
    $ sudo aptitude install libboost-all-dev

Procedimiento

Obtener la última versión del código fuente de la librería.

$ svn checkout http://simple-openni.googlecode.com/svn/trunk/ simple-openni-read-only

$ cd simple-openni-read-only/SimpleOpenNI/

Ajustar el script de construcción modificando la invocación a cmake de la siguiente manera.  (Ajustar las rutas que se consideren convenientes, en especial a DP5_JAR)

$ vi buildLinux32.sh

(actualizar)

cmake -DOPEN_NI_INCLUDE=/usr/include/ni/ \
      -DXN_NITE_INCLUDE=/usr/include/nite/ \
      -DXN_NITE_LIB=/usr/lib/ \
      -DEIGEN3D_INCLUDE=/usr/include/eigen3/ \
      -DP5_JAR=~/Processing/2.0a4/lib/core.jar \
      -JAVA_INCLUDE_PATH=/usr/lib/jvm/java-6-openjdk/include/ \
      -JAVA_INCLUDE_PATH2=/usr/lib/jvm/java-6-openjdk/include/linux \
      ..

Realizar la construcción de la librería.

$ ./buildLinux32.sh

Instalar la librería recién construída.

$ ./installLinux.sh

Verificar la instalación de la librería

El procedimiento anterior construye e instala la librería de Simple-OpenNI bajo ~/sketchbook/libraries/SimpleOpenNI/ dejándola lista para ser utilizada con Processing.

$ tree -d ~/sketchbook/libraries/SimpleOpenNI/

/home/jimezam/sketchbook/libraries/SimpleOpenNI/
├── documentation
│   ├── resources
│   └── SimpleOpenNI
├── examples
│   ├── eclipse
│   ├── Nite
│   │   ├── CircleCtrl
│   │   ├── Hands
│   │   └── Slider2d
│   └── OpenNI
│       ├── AlternativeViewpoint3d
│       ├── DepthImage
│       ├── DepthImageXml
│       │   └── data
│       ├── DepthInfrared
│       ├── DepthMap3d
│       ├── Hands3d
│       ├── MultiCam
│       ├── RecorderPlay
│       ├── Scene
│       ├── SceneDepth
│       ├── Threaded
│       ├── User
│       ├── User3d
│       ├── User3dCallback
│       ├── UserSaveCalib
│       └── UserScene3d
└── library

Enlaces

The Falling Things (reloaded) con Processing

Introducción

Aprovechando los últimos días de vacaciones decidí rehacer el sketch de TheFallingThings que había creado hace un tiempo.  Esta nueva versión es muy similar en su funcionalidad pero tiene un código mejor orientado a objetos y mas limpio, de igual manera que su antecesora fue implementada utilizando el lenguaje de programación Processing.

El objetivo del sketch sigue siendo el mismo, atrapar con el paddle las cosas que caen desde el cielo.  El usuario puede controlar el paddle utilizando el teclado (flechas izquierda y derecha) o el ratón.

Las variables del sketch pueden ser controladas durante su ejecución: cantidad de cosas que caen (teclas +/-) y la velocidad de las cosas que caen (flechas arriba y abajo).  Otras teclas útiles son r (reset) para reiniciar el sketch, p (pause) para pausarlo y q (quit) para salír de él.

Screenshot

The Falling Things v0.1

The Falling Things v0.1

 

Enlaces

Problemas para reproducir sonidos en Processing con Minim bajo Ubuntu 10.10

Introducción.

Minim parece ser una muy buena librería para la reproducción y manipulación de archivos de audio utilizando a Processing como lenguaje de desarrollo.

Experimentando con esta librería intentaba reproducir dos sonidos provenientes de dos archivos WAV diferentes, sin embargo siempre obtenía el siguiente mensaje de error a pesar de que cuando lo intentaba con uno sólo funcionaba correctamente.

JavaSound Minim error
==== Couldn't open the line: line with format PCM_SIGNED 44100.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian not supported. ====

Este problema me sucedía tanto al utilizar AudioSample como con AudioSnippet.

Solución.

Aparentemente el problema está relacionado con la plataforma Ubuntu ya que esta apuesta por OpenJDK como máquina virtual de Java por encima de la distribución oficial de Oracle (sun-java6) y por este motivo desafortunadamente olvidaron agregarle el soporte para el sistema PulseAudio que utiliza por defecto esta distribución.

La solución propuesta en los foros es copiar los archivos necesarios desde los directorios de OpenJDK a sus equivalentes de SunJava6.  En mi caso que utilizo exclusivamente la última versión fue necesario que instalara temporalmente el paquete openjdk-6-jre-lib, copiara los siguientes archivos y lo desinstalara nuevamente.

$ sudo cp /usr/lib/jvm/java-6-openjdk/jre/lib/[ARCH]/libpulse-java.so /usr/lib/jvm/java-6-sun/jre/lib/[ARCH]/

$ sudo cp /usr/lib/jvm/java-6-openjdk/jre/lib/ext/pulse-java.jar /usr/lib/jvm/java-6-sun/jre/lib/ext/

Se debe tener cuidado al reemplazar la subcadena [ARCH] contenida en la primera instrucción a ejecutar con la correspondiente plataforma instalada realmente, ya sea de 32 bits (será entonces i386) o de 64 bits (amd64).  La ejecución del comando uname -m debería brindar información suficiente al respecto.

Enlaces.

Interferencia entre wrj4P5 y los eventos de mouseMoved con Processing en GNU/Linux Ubuntu 10.10

Introducción.

En días anteriores escribí acerca de como utilizar el wiimote en sketches de Processing bajo GNU/Linux Ubuntu 10.10.  El método detallado funciona bastante bien al menos para el manejo del evento de la presión de los botones del dispositivo, sin embargo he encontrado un problema molesto con el uso de esta librería y del cual no he podido encontrar mayor información.

Si en un sketch en el cual se está manejando el evento de movimiento del ratón (mouse moved) se empareja un wiimote utilizando la librería wrj4P5 se empiezan a generar múltiples eventos sugiriendo que el ratón se está moviendo aunque sus coordenadas no varian!

Aplicación de demostración.

Aplicación de demostración uso de Wiimote con Processing

Aplicación de demostración uso de Wiimote con Processing

Para experimentar con el problema sugerido he creado un sketch muy simple que utiliza la librería mencionada y además maneja el evento de movimiento del ratón.

Este problema ha sido probado en tres equipos, dos portátiles y uno de escritorio, con GNU/Linux Ubuntu 10.10 y 9.10 respectivamente.  Aún no he tenido la oportunidad de experimentar con la aplicación de demostración en Windows.

Una solución temporal.

Por ahora la única solución, para nada elegante, que he encontrado es el verificar si efectivamente el puntero del ratón ha sido movido para garantizar que el supuesto evento si sucedió en realidad.

int lastX;
int lastY;
void mouseMoved()
{
  if(mouseX == lastX && mouseY == lastY)    // There was no movement: avoid this "event"!
  {
    return;
  }
  else    // There WAS movement, update "last" positions.
  {
    lastX = mouseX;
    lastY = mouseY;
  }
  // ... do some stuff ...
}

El sketch puede ser descargado del sitio de demostraciones con la modificación para evitar el problema desactivada.  Para activarla remueva los comentarios al rededor del condicional if(mouseX == lastX && mouseY == lastY) aproximadamente en la línea 66.

Enlaces.

Descubrir equipos cercanos con Processing y bluetoothDesktop

Introducción.

En el presente artículo se describe el proceso de instalación de la librería bluetoothDesktop en GNU/Linux (para Windows es similar) que permite manipular el módulo de Bluetooth del dispositivo donde se ejecuta el sketch y con ella se implementa el procedimiento para detectar dispositivos cercanos que utilicen este protocolo de comunicaciones.

Obtener la librería.

Descargar la versión disponible mas reciente en el sitio web del proveedor.

http://www.extrapixel.ch/processing/bluetoothDesktop/download.html

Instalación de la librería.

Descomprimir el paquete recién descargado.

Mover el directorio bluetoothDesktop/ al directorio de librerías de Processing en ~/sketchbook/libraries/.  El resultado se deberá apreciar de la siguiente manera.
$ ls -l ~/sketchbook/libraries/bluetoothDesktop/

drwxr-xr-x 5 jimezam jimezam 4096 2010-12-08 22:47 examples
-rw-r–r– 1 jimezam jimezam  910 2007-12-17 21:25 howto.txt
drwxr-xr-x 3 jimezam jimezam 4096 2010-12-08 23:09 library
drwxr-xr-x 2 jimezam jimezam 4096 2010-12-08 22:47 src

Remover los siguientes archivos ubicados bajo el directorio ~/sketchbook/libraries/library/.

  • libavetanaBT.so
  • export.txt
  • bluecove-2.0.2-snapshot.jar
  • avetanaBT_readme.txt
  • avetanaBT.jar

Copiar en es mismo directorio los siguientes archivos que pueden obtenerse del sitio web de Bluecove.

  • bluecove-x.x.x.jar
  • bluecove-gpl-x.x.x.jar (requerido para Linux).

El contenido final de ese directorio se aprecia de la siguiente manera.

$ ls -l ~/sketchbook/libraries/bluetoothDesktop/library/

-rw-r–r– 1 jimezam jimezam 547156 2010-12-08 21:27 bluecove-2.1.0.jar
-rw-r–r– 1 jimezam jimezam  89022 2010-12-08 21:26 bluecove-gpl-2.1.0.jar
-rw-r–r– 1 jimezam jimezam   9409 2007-11-14 19:01 bluetoothDesktop.jar

Implementación.

Importar el paquete principal de la librería.

import bluetoothDesktop.*;

Crear un objeto para hacer referencia al dispositivo de Bluetooth.

Bluetooth bluetoothInstance = new Bluetooth(this);

Iniciar el proceso de descubrimiento de dispositivos cercanos.

bluetoothInstance.discover();

Implementar el método deviceDiscoverEvent el cual es llamado cada vez que un nuevo dispositivo Bluetooth es detectado.

void deviceDiscoverEvent(Device dev)
{
    println("Discovering ... name=" + dev.name + "; address=" + dev.address);
}

Implementar el método deviceDiscoveryCompleteEvent el cual es llamado una única vez al terminarse el proceso de descubrimiento.

void deviceDiscoveryCompleteEvent(Device[] devices)
{
  println("I Found " + devices.length+ " devices.");
  for(int i=0; i<devices.length; i++)
  {
    println(i + "# name=" + devices[i].name + "; address=" + devices[i].address);
  }
}

Aplicación de demostración.

Aplicación de demostración - Descubrir dispositivos Bluetooth cercanos

Aplicación de demostración - Descubrir dispositivos Bluetooth cercanos

Enlaces.

Laberinto 0.2 controlado por wiimote

Introducción.

Preparando un mejor ejemplo para el uso del wiimote con Processing decidí actualizar la versión procedimiental del Laberinto que utilicé como demostración en una charla hace un par de meses.

Con esta mejora es posible conectar el wiimote al sketch y controlar con él al caballero en busca de su tesoro mas preciado: la princesa :-)  Adicionalmente el wiimote vibrará cuando el caballero se encuentre con ella.

El movimiento del caballero es controlado por el d-pad mientras que el botón de inicio (home) lo teletransporta y el botón #1 reinicia el juego.

Implementación.

Como primera instancia es necesario tener instaladas las librerías requeridas para el uso del wiimote con Processing.

A continuación se realizan las siguientes modificaciones al código base del sketch.

Se importa el paquete de las clases relacionadas con el wiimote.

import lll.wrj4P5.*;

Se establece una referencia global al control.

Wrj4P5 wii;

En el setup se establece la conexión con el wiimote.

void setup()
{
    // ...
    wii = new Wrj4P5(this);
    wii.connect();
}
Se implementa el método buttonPressed para manejar los eventos provenientes del control con la lógica que se mencionó anteriormente: d-pad controla la dirección, home teletransporta al jugador y el botón #1 reinicia el juego.
void buttonPressed(RimokonEvent evt, int rid)
{
  if (evt.wasPressed(RimokonEvent.LEFT))
    moverJugador(LEFT);
  if (evt.wasPressed(RimokonEvent.RIGHT))
    moverJugador(RIGHT);
  if (evt.wasPressed(RimokonEvent.DOWN))
    moverJugador(DOWN);
  if (evt.wasPressed(RimokonEvent.UP))
    moverJugador(UP);
  if (evt.wasPressed(RimokonEvent.ONE))
    reset();
  if (evt.wasPressed(RimokonEvent.HOME))
    teletransportarJugador();
}

La verificación del encuentro entre la princesa y el caballero se realiza en el método moverJugador y sucede cuando la nueva ubicación del caballero no es una pared && es un tesoro, en ese momento se ejecuta la siguiente instrucción para hacer vibrar el control.

wii.rimokon.vibrateFor(400);

Enlaces.