Instalación de un Nano Lynx Wireless-N USB 2.0 en una Raspberry Pi

Introducción

Los controladores para los adaptadores NanoLynx Wireless-N USB 2.0 ya se encuentran incluidos en las distribuciones actuales de Linux (Raspbian y DietPi entre otras) para la Raspberry Pi.

En caso de no tenerse se deberán obtener los controladores para rt2800 mediante la instalación del paquete firmware-ralink.

Verificación

Para verificar que el hardware se encuentra instalado y que ha sido reconocido exitosamente se debe ejecutar el siguiente comando.

$ lsusb

    Bus 001 Device 007: ID 148f:5370 Ralink Technology, Corp. RT5370 Wireless Adapter

Así mismo es conveniente verificar que los controladores necesarios hayan sido cargados exitosamente.

$ lsmod | grep rt2

    rt2800usb         18832    0 
    rt2800lib         81962    1    rt2800usb
    rt2x00usb         11918    1    rt2800usb
    rt2x00lib         47354    3    rt2x00usb,rt2800lib,rt2800usb
    mac80211         594951    3    rt2x00lib,rt2x00usb,rt2800lib
    cfg80211         477515    2    mac80211,rt2x00lib
    crc_ccitt          1620    1    rt2800lib

Configuración

La configuración de la interfaz de red se puede realizar mediante la herramienta de configuración de la red inalámbrica que viene con el sistema operativo o se puede realizar manualmente como se describe a continuación.

Instalar el paquete de wpasupplicant en caso de no tenerse aún.

# apt-get install wpasupplicant

Ejecute el siguiente comando reemplazando la palabra ssid por el identificador de la red inalámbrica a la cual se desea conectar y password por su respectiva contraseña.

$ wpa_passphrase ssid password 

Copie el resultado de la ejecución del comando anterior y agregue (o reemplace) la sección network en el archivo /etc/wpa_supplicant.conf.  Es posible que este archivo esté ubicado en /etc/wpa_supplicant/wpa_supplicant.conf (DietPi Jessie).

# vi /etc/wpa_supplicant.conf

 network={
   ssid="MiRed"
   psk=945609aab2413e64d57daef00eb5fab3acdde716e1e440981c004bc61dccc98c
 }

Para verificar la conexión con la configuración establecida en el paso anterior, ejecute el siguiente comando.  Una vez desee terminar la verificación presione CTRL+C.

$ wpa_supplicant -Dwext -iwlan0 -c/etc/wpa_supplicant.conf

Ajustar la configuración de las interfaces de red para incluir la información de wlan0 agregando la siguiente información.

# vi /etc/network/interfaces

    auto wlan0
    iface wlan0 inet dhcp
    wpa-driver wext
    wpa-conf /etc/wpa_supplicant.conf

Una vez terminados los ajustes, iniciar la interfaz de red para que tome la nueva configuración.

#  ifup wlan0

Finalmente si desea verificar los datos de configuración con los que se encuentra funcionando la interfaz de red inalámbrica ejecutar el siguiente comando.

# wpa_cli status

Recursos

  1. RPi Ralink WLAN devices
    http://elinux.org/RPi_Ralink_WLAN_devices
  2. RPi USB Wi-Fi Adapters
    http://elinux.org/RPi_USB_Wi-Fi_Adapters
  3. Rpi USB check-list (posible solución al bug de desconexión)
    http://elinux.org/Rpi_USB_check-list

Detectando movimiento con GSVideo y Processing

Introducción

De manera análoga a como se realizó inicialmente con OpenCV, se realizó el proceso de detección de movimiento básico utilizando Processing y la librería de GSVideo instalada hace poco.  Esta librería se especializa en la captura, grabación y reproducción del video mas que en su procesamiento así que la manipulación de las imágenes se realiza manualmente con las facilidades que provee el lenguaje.

En términos generales el procedimiento se basa en capturar el video proveniente de la cámara web a través de una instancia de la clase GSCapture provista por la librería GSVideo.  Cada una de las imágenes obtenidas es comparada con la imagen inmediatamente anterior.  De cada uno de sus píxeles se toma el color en forma de tripleta RGB y se determina su cantidad de variación utilizando la fórmula de distancia (función dist en Processing).  De esta manera se determina si en ese punto específico sucedió movimiento o no y es traducido a un píxel de color blano o negro respectivamente.

Screenshot

Imagen de movmiento sobre el objetivo
Imagen de movmiento sobre el objetivo

Enlaces

Detectando movimiento con OpenCV y Processing

Introducción

Una de las características que quería aprender a implementar con OpenCV era la detección de movimiento, esto me permitirá implementar formas de interacción interesantes (y bastante simples de generar) entre el usuario y el sketch a través de la cámara web.

En pocas palabras, la técnica para detectar movimiento que se describe a continuación se basa en generar una imagen monocromática con los píxeles que han cambiado entre dos cuadros del video.  Para hacer esto se siguen los pasos mostrados a continuación.

  1. Obtener una nueva imagen de la cámara web
  2. Invertir la imagen horizontalmente (opcional)
  3. Calcular la diferencia entre la imagen recién obtenida y la almacenada en memoria (recordada)
  4. Procesar la imagen para facilitar su manejo: convertirla a escala de grises, suavizar la imagen y reducir el ruido eliminando los valores demasiado altos o bajos.
  5. Mostrar la imagen de movimiento (opcional)
  6. Recordar la imagen actual para ser procesada nuevamente en la siguiente iteración

opencv.read();

opencv.flip(OpenCV.FLIP_HORIZONTAL);

opencv.absDiff();

opencv.convert(OpenCV.GRAY);

opencv.blur(OpenCV.BLUR, 3);

opencv.threshold(20);

image(opencv.image(), 0, 0);

opencv.remember(OpenCV.SOURCE, OpenCV.FLIP_HORIZONTAL); 

Para verificar si ha sucedido movimiento en una determinada área de la imagen se debe verificar si los píxeles que pertenecen a esa área se encuentran blancos (si hubo) o no.  Esta información se obtiene utilizando el método get(int x, int y) del objeto PImage el cual retorna el color del píxel seleccionado.  Por facilidad se recomienda que se obtenga el brillo (brightness(color)) de este píxel para su comparación.

El siguiente código revisa un área cuadrada de píxeles en búsqueda de movimiento en esa zona.

for(int px=x; px<x+size; px++)  
    for(int py=y; py<y+size; py++)     
        if (px < width && px > 0 && py < height && py > 0)       
            if (brightness(mImage.get(px, py)) > 127)
                count ++;

Screenshot

Imagen de movmiento sobre el objetivo (modo buffer)
Imagen de movmiento sobre el objetivo (modo buffer)

 

Enlaces

Poniendo sombreros a las personas con OpenCV y Processing

Introducción

Como una versión un poco mas elaborada de la publicación anterior he preparado este sketch que toma el flujo de video proveniente de la cámara web,  encuentra en él los rostros de las personas y les pone un sombrero.  Se incluyen diferentes sombreros que pueden cambiarse mediante el teclado.

q – terminar el sketch
a – mostrar/ocultar el rectángulo rojo alrededor de cada cara encontrada
s – mostrar/ocultar la máscara sobre cada cara encontrada
z/x – alternar entre las imágenes de máscaras disponibles

Screenshots

Demostración con varias personas en la misma imagen
Demostración con varias personas en la misma imagen
Demostración con la foto de un rostro
Demostración con la foto de un rostro

Agradecimientos para Martha, Diego y Jennifer Connerlly por participar como modelos para las fotos del artículo.

Acerca de la ubicación de los rostros

Hasta el momento el perfil que mejores resultados me ha dado para ubicar los rostros de las personas ha sido OpenCV.CASCADE_FRONTALFACE_ALT_TREE (haarcascade_frontalface_alt_tree.xml).  Este encuentra los rostros con el menor número de errores (identificación equivocada de un objeto inanimado como si fuera un rostro), sin embargo parece tener poca tolerancia a las variaciones de posición del rostro de las personas, si ellas agachan o rotan un poco la cara probablemente ya no serán renocidas.  Un trabajo a futuro consistirá en encontrar como mejorar estos resultados de la ubicación de rostros.

Estos son los perfiles de reconocimiento disponibles a través de OpenCV según la instalación que se realizó de la librería.

Los siguientes perfiles se encuentran disponibles como constantes asociadas a la clase OpenCV de Processing.

  public static final String CASCADE_FRONTALFACE_ALT_TREE
  public static final String CASCADE_FRONTALFACE_ALT
  public static final String CASCADE_FRONTALFACE_ALT2
  public static final String CASCADE_FRONTALFACE_DEFAULT
  public static final String CASCADE_PROFILEFACE
  public static final String CASCADE_FULLBODY
  public static final String CASCADE_LOWERBODY
  public static final String CASCADE_UPPERBODY

A continuación se listan todos los archivos XML de los perfiles de reconocimiento que también pueden ser utilizados directamente en Processing.

  haarcascade_eye_tree_eyeglasses.xml   
  haarcascade_frontalface_default.xml  
  haarcascade_mcs_eyepair_small.xml  
  haarcascade_mcs_upperbody.xml
  haarcascade_eye.xml                   
  haarcascade_fullbody.xml             
  haarcascade_mcs_lefteye.xml        
  haarcascade_profileface.xml
  haarcascade_frontalface_alt2.xml      
  haarcascade_lefteye_2splits.xml      
  haarcascade_mcs_mouth.xml          
  haarcascade_righteye_2splits.xml
  haarcascade_frontalface_alt_tree.xml  
  haarcascade_lowerbody.xml            
  haarcascade_mcs_nose.xml           
  haarcascade_upperbody.xml
  haarcascade_frontalface_alt.xml       
  haarcascade_mcs_eyepair_big.xml      
  haarcascade_mcs_righteye.xml 

Enlaces

Ubicando caras en una webcam con OpenCV y Processing

Introducción

En este sketch se aprovecha la agilidad para desarrollar en Processing con la facilidad que provee OpenCV para ubicar los rostros de las personas en el flujo de video proveniente de una cámara web.  En este caso el sketch mostrará una cara sonriente cuando se encuentra acompañado por una persona y una cara triste cuando está solo.

Screenshots

Sketch feliz
Sketch feliz

Sketch triste
Sketch triste

Enlaces

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