OpenCV on the Raspberry Pi with Arch Linux ARM

These are my notes on how I got OpenCV running on the Raspberry Pi today with a webcam. On this post you can find the Debian version that I did earlier.

  • Install Arch Linux ARM from image, use this guide.
  • Expand linux parition, also detailed on the same guide.
  • Configure copying arm224_start.elf to start.elf to get more memory for the apps
  • Configure networking: edit /etc/rc.conf and /etc/resolv.conf. Check this topic
  • Modify pacman configuration /etc/pacman.conf to use curl to download packages for my slow connection by uncommenting the line:
     XferCommand = /usr/bin/curl -C - -f %u > %o
  • I tried several times to update pacman and system using
    pacman -Syu

    but some errors about udev and libusb were found, and I finally gave up with this step. At last, everything worked except lxde which I don’t need, so I’ll check this back some other time.

  • Install lxde. I’m not sure if some libraries installed by this are useful to OpenCV.
    pacman -S lxde xorg-xinit xf86-video-fbdev
    
  • lxde didn’t worked: every time I tried to xinit, it throwed a error about libudev.so.1 not being found.
  • Install python2 (which was already installed but was updated), numpy, opencv and samples:
    pacman -S python2 python2-numpy opencv opencv-samples
    
  • Finally I run a simple test I use to open the webcam stream, take a frame and save it. It didn’t worked immediatly since I found that a Dell multimedia keyboard I had attached to a USB hub with my DIY USB powered cable with the webcam had some issues. But after solving it, the camera works and saves the image. The sample is this:
    import cv2.cv as cv
    import time
    
    #cv.NamedWindow("camera", 1)
    
    #capture = cv.CaptureFromCAM(-1)
    capture = cv.CreateCameraCapture(1)
    #cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FPS, 3)
    cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FRAME_WIDTH, 1280)
    cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FRAME_HEIGHT, 720)
    
    img = cv.QueryFrame(capture)
    
    print "Captured "
    cv.SaveImage("output.jpg",img)

Law of Large Numbers, Visualized

As a follow up on the post “How Common Is Your Birthday – 360 degrees” we are getting our own data from OCCMundial to compare México with the US data from the NYTimes. We made several runs with different dataset sizes and, as a byproduct of this, we got a visualization that shows how the probability distribution of the birthday rank becomes apparent as the dataset size increases.

Check the visualization and source code (in Processing.js) here.

Rank for more common birthdays along the year. Whiter is highest rank, so most common birthday. Data for a random sample of 5,000, 100,000, 1.5 million and 4.5 million records. As dataset size increases, the real distribution becomes apparent. Data from México (OCCMundial).

Visualization: How Common Is Your Birthday – 360 degrees

I’ve done a visualization based on this one by Matt Stiles. Use the mouse to locate a birth date. I’ve a added a red arc that indicates the most probable conception date for the given birth date based on an average pregnancy of 39.5 weeks. January 1st is at 0 degrees and the year goes clockwise. I think that a circle gives a better impression on what’s happening around the year. Check the gaps at some special dates likes July 4th, Christmas and Thanks Giving weeks.

I hope to have another visualization with our own data soon.

Images licensed under Creative Commons Attribution 3.0 Unported. These files are licensed under the Creative Commons Attribution 3.0 Unported license. You are free: to share, to copy, distribute and transmit the work to remix or to adapt the work Under the following conditions: attribution: You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work). Code is OpenSource bajo MIT License.

DIY Powered USB Cable for Raspberry Pi

I’ve got a Logitech c270 webcam working on the Raspberry Pi with Archlinux, since the current Debian image does not include the video modules. The main issue is power. I’ve measured the current that the camera is using and it goes up to 240mA when capturing video which is well over the Pi’s specification. If you can get a powered USB hub I guess that will work, just keep an eye on the power consuption of all the devices connected to it.

I have built a powered usb cable from a USB extension cable and a USB Type A-B cable. The extension cable is the one that has on each side a Type A male and female (receptacle), and is used to access a remote USB port. The type A to B cable is the one that is commonly used to connect a host to a device, like a computer to a printer, and that seems to be used less nowadays.


USB connectors. Three right-most are: Type A female (receptacle), Type A male and Type B

Please note that doing this may be dangerous or risky for your devices, since a shortcut or an incorrectly plugged terminal may damage or blow any of them. Build this at you own risk!. Also take into account that this cable will be less reliable than the original cables.

The USB standard pinout consists of four conductors: Ground (GND – black), VBUS (+5V – red), Data+ (D+ – green) and Data- (D- – white). We will connect the GND and VBUS lines from the extension cable to the GND and VBUS lines of the Type A side of the other cable, leaving both Data lines untouched in the extension cable. The Data lines of the Type-A from the AB cable will not be used (will be unconnected). The Type-B side of the AB cable will be thrown away.

Cut the extension cable from the middle. If possible, do not touch the green and white lines. If you need to cut them, resolder both later to keep the same configuration as the original.

Cut the A-B cable and throw away the B side. Peel the red and black lines of the A side and trim the white and green lines since they will not be used. Connect and solder the red conductors of the two Type A male sides and the Type A female. Connect and solder the black conductors of the three connectors. Isolate the connections (I used thermofit). Use some electrical tape to strengthen the cable. Test using a multimeter.

You will have a cable with two Type A male connectors and one Type A female connector (receptacle).

You can now connect the cable to the devices. I recommend this order:

  • The Type-A (male) from the A-B cable to a USB power source (like a phone’s charger)
  • The Type-A (male) from the extension cable to the Raspberry Pi
  • The Type-A (female, receptable) to the device, in my case, the webcam.

Everything should run smoothly since the power for the device is now taken from the charger and not from the board.

Once again, do this at your own risk and evaluate your skills. The procedure is simple but it may produce irreversible damage to your devices if done improperly.

Installing OpenCV on the Raspberry Pi

UPDATE 2:Here is my guide for Arch Linux

UPDATE: I’ve moved to Archlinux because it has the webcam modules included. OpenCV is really easy to install: pacman -S opencv

Installing OpenCV (2.3.1) on the Raspberry Pi is pretty easy using the base Debian Squeeze image and following these instructions for Debian/Ubuntu.You will need to have more space on the root partition so I recommend resizing it to at least 3GB (see the video tutorial using GParted or follow these instructions). Here they are with some comments on the few issues I found:

I found an error trying to install cmake for the first time, so first do

sudo apt-get update

two times before anything else. The first time I did the update an error on “duplicate sources” was shown thus the second update was necessary.

Install in the following order:

sudo apt-get install build-essential
sudo apt-get install cmake 
sudo apt-get install pkg-config 
sudo apt-get install libpng12-0 libpng12-dev libpng++-dev libpng3 
sudo apt-get install libpnglite-dev libpngwriter0-dev libpngwriter0c2 
sudo apt-get install zlib1g-dbg zlib1g zlib1g-dev 
sudo apt-get install pngtools libtiff4-dev libtiff4 libtiffxx0c2 libtiff-tools 
sudo apt-get install libjpeg8 libjpeg8-dev libjpeg8-dbg libjpeg-progs 
sudo apt-get install ffmpeg libavcodec-dev libavcodec52 libavformat52 libavformat-dev 
sudo apt-get install libgstreamer0.10-0-dbg libgstreamer0.10-0  libgstreamer0.10-dev 
sudo apt-get install libxine1-ffmpeg  libxine-dev libxine1-bin 
sudo apt-get install libunicap2 libunicap2-dev 
sudo apt-get install libdc1394-22-dev libdc1394-22 libdc1394-utils 
sudo apt-get install swig 
sudo apt-get install libv4l-0 libv4l-dev 
sudo apt-get install  python-numpy 
sudo apt-get install libpython2.6 python-dev python2.6-dev 
sudo apt-get install libgtk2.0-dev pkg-config

The package build-essential was already installed on my device so maybe you don’t need to install it. Note that for the eighth line the original link says “libjpeg-prog” but it must be “libjpeg-progs”. Also, check the last step that is not included on the original instructions but it’s needed for this platform.

Get the sources (check the version you want to install):

wget http://sourceforge.net/projects/opencvlibrary/files/opencv-unix/2.3.1/OpenCV-2.3.1a.tar.bz2/download

Uncompress the sources and create a directory inside it (I called it ‘release’). Chdir to it. Run cmake to configure, compile and install. Compilation will take a while, about a couple of hours:

cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_PYTHON_SUPPORT=ON -D BUILD_EXAMPLES=ON ..
make
sudo make install 

Now you can run the samples. In this image, the Python version of contours:

Visualización de Densidad Poblacional de México

Gracias a los datos recién publicados por INEGI del Censo 2010 de Población y Vivienda estoy haciendo algunas visualizaciones en Processing.

Usando el método descrito en dos posts anteriores generé la siguiente imagen tipo heatmap o mapa de calor para la densidad poblacional de todo México. Básicamente lo que hice fue:

  • Tomar de aquí los datos de todas las poblaciones en formato de texto tal como los provee INEGI.
  • Generar un archivo tipo CSV con las coordenadas geográficas de las pobaciones con al menos 100 habitantes y el logaritmo base 10 de esa cantidad para facililitar el manejo. Son 52,856 ubicaciones. El archivo está disponible aquí
  • En Processing se grafica cada ubicación con un círculo cuyo color, radio y transparencia es proporcional al tamaño de la población del lugar. Cada círculo tiene un pequeño degradado para conseguir un efecto más suave en la imagen.

El resultado es la siguiente imagen (click para una imagen de mayor resolución):

El objetivo de la visualización no es la precisión geográfica sino la sensación de la densidad poblacional. Las ciudades más grandes son fácilmente identificables, así como las zonas metropolitanas. Hay grandes areas poco habitadas de las que podemos imaginar sus características geográficas.

Links a imágenes a diferentes resoluciones y al proyecto en Github:

Los datos son información pública de INEGI y no alterados mas que en formato para poder ser procesados. Las imágenes tienen licencia Creative Commons Attribution 3.0 Unported (These files are licensed under the Creative Commons Attribution 3.0 Unported license. You are free: to share � to copy, distribute and transmit the work to remix � to adapt the work Under the following conditions: attribution � You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work). El c�digo es OpenSource bajo MIT License

Otros Mapas Georeferenciados de M????xico para Visualizaci????n

Continuando con el tema del post anterior sobre la creación de visualizaciones de mapas georeferenciados de México he hecho un par de mapas más que pueden dar buenos resultados.

Todos están basados en este Mapa que tiene bien marcados los límites visibles en coordenadas geográficas y que es una proyección equirectangular. Yo eliminé la información hidrográfica e hice varias versiones incluyendo o no los estados y con diferentes colores. Los límites son los siguientes:

float lng_max=-86.3;
float lng_min=-118.5;
float lat_max=33.3;
float lat_min=14.2;

 

Ejemplo:

Licencia: Creative Commons Attribution 3.0 Unported

These files are licensed under the Creative Commons Attribution 3.0 Unported license. You are free: to share – to copy, distribute and transmit the work to remix – to adapt the work Under the following conditions: attribution – You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).

Cómo Hacer Mapas Georeferenciados de México para Visualización

La visualización de información es uno de los aspectos fundamentales del análisis de datos en la actualidad, como en el caso de la reciente visualización de amistad en Facebook que tuvo gran éxito

En OCCMundial estamos trabajando en geolocalización de ofertas de trabajo. Obtuvimos datos muy interesantes pero al tratar de visualizarlos con un mapa de fondo para hacer más interesante la presentación de los datos me encontré con el problema de conseguir un mapa georeferenciado sobre el cual mostrar la información. De otras regiones tales como el mundo completo, Estados Unidos o Europa es sencillo conseguirlos pero fue más complicado en el caso de México. Tampoco encontré un procedimiento sencillo para generarlo, por lo que en este post pongo mi experiencia y los resultados esperando que le sirvan a alguien más. La idea vino de Minigis que lo usa en un mapa mundial.

El problema consiste en conseguir una imagen de un mapa en el cual se tenga una correspondencia entre coordenadas geográficas y los pixeles. Los buenos mapas que escalan con el nivel de zoom son imágenes vectoriales.Wikimedia es un excelente recurso para comenzar. Los mapas estan en formato SVG. Aquí se encuentran los mapas de México. Es importante fijarse en el tipo de proyección ya que afecta el aspecto del mapa. Para este caso necesitamos un mapa equirectangular en el cual las coordenadas geográficas se pueden mapear de forma lineal con los pixeles de la imagen. Aunque el mejor mapa de México que conseguí tiene división política por municipios, lo que lo hace pesado y no muy bonito para algunos casos, pero es suficientemente bueno para nuestro uso.

Desafortunadamente el mapa no especifica las coordenadas que comprende por lo que es necesario averiguarlas. Usando Inkscape abrí el mapa y encontré que tiene marcados paralelos y meridianos cada 5 grados. Dado que el primer meridiano que se muestra es el 15 y está en la posición Y=48.4, el siguiente es el 20 y está en la posición Y=173.739 podemos comprobar que cada 5 grados corresponden a 125 pixeles, 1 grado a 2.06 pixeles y 0.03999 grados a 1 pixel. De la misma forma podemos comprobar para los paralelos ya que el último paralelo mostrado es el 115W (-115.0) en posición X=56.79 y se mantiene la misma proporción de grados a pixeles (lo que es correcto dado que es una proyección equirectangular). Con esto podemos calcular que el origen de la imagen se encuentra en 13.064° de latitud y -117.271° de longitud (dicho sea de paso, usaremos grados decimales por simplicidad).

Con esto se puede generar una imagen bitmap para ser usado en algún programa o con lenguaje de programación. En este caso estoy usando Processing para generar las visualizaciones. Importante, en general en las imágenes raster el origen no se encuentra en la esquina inferior izquierda como en el SVG sino en la superior izquierda, por lo que el origen se encuentra en 34.6586° lat y -117.271° long, que son las coordenadas se deben usar para calcular las posiciones de los pixeles. La longitud mínima se encuentra en -86.54. Para calcular los pixeles se usan las funciones lineales descritas abajo. La derivación es sencilla por lo que dejo solo una imagen de mis notas por si le sirve a alguien.

En el sketch de processing se puede ver una prueba con algunos puntos interesantes para comprobar que funciona. IMPORTANTE: los datos son muy aproximados, por lo que no recomendaría usar estos métodos para algo mas que visualizaciones sencillas, no mediciones o para ubicar exactamente alguna posición.

Cómo usar:

Se puede usar esta imagen con las dimensiones descritas arriba y las siguientes funciones para calcular pixeles a partir de coordenadas.

 

 
  int x = int( (117.271-lng)*770/(117.271-86.54) );
  int y = int( (34.6586-lat)*540/(34.6586-13.064) );
  

 

Otra imagen, con fondo negro que suele ser mejor para visualizaciones.

En caso de requerir una imagen de otro tamaño no es dificil escalar estas imágenes y encontrar las correspondientes funciones.

Sketch de Processing bajar

//Mantiene las mismas dimensiones del SVG original
int imgx=770;
int imgy=540;

void setup()
{
  //También se puede bajar con la URL directa a Wikimedia 
  //http://commons.wikimedia.org/wiki/File:Municipalities_of_Mexico_(equirectangular_projection).svg
  PShape mx = loadShape( "Municipalities_of_Mexico_(equirectangular_projection).svg" );
 
  size(imgx,imgy);
  shape(mx,0,0,imgx,imgy);
  smooth();
  noLoop();
  
  //Puntos de prueba
  plotAt(19.43333,-99.1333333,5); //DF
  plotAt(25.6666,-100.5, 5);   //MTY
  plotAt(20.6666,-103.3333, 5);  //GDL
 
  plotAt(32.534, -117.123,5); //Tijuana 
  plotAt(21.227, -86.7199,5); //Isla Mujeres
  
  plotAt(14.5176, -92.2199, 5); //Sur
  plotAt(17.8212, -89.1551, 5); //Belice
  plotAt(20.7959, -90.4006, 5); //Campeche
  plotAt(25.9393, -97.1231, 5); //Tamps
  plotAt(29.8605, -102.2996, 5); //Coah Nte
  plotAt(31.7820, -106.5058, 5); //Chih
  plotAt(32.7125, -114.7015, 5); //Nte
  plotAt(22.8865, -109.9164, 5); //Cabos
  plotAt(20.6,-100.38333, 5); //Qro
  plotAt(16.85,-99.93333, 5); //Acapulco
  
  save("mexico.jpg");
}

void plotAt(float lat, float lng, float rad)
{
  lng=-lng; //Si viene en long oeste
  int x = int( (117.271-lng)*770/(117.271-86.54) );
  int y = int( (34.6586-lat)*540/(34.6586-13.064) );
  

  println(x);
  println(y);
  
  fill(10,10,60,80);
  ellipse(x,y,rad,rad);
 }

Espejo del mapa SVG

Imagen con los puntos de prueba

Visualización – Algunas ofertas de empleo actuales (naranja), y principales ciudades (azul)

Arduino RGB LED HSV “Color Wheel”

Recently I’ve been playing with Arduino, Scratch and the 3pi robot for a personal project that I hope will be interesting enough to show soon. (I’ve got a lot of motivation from these guys specially the little one with big eyes).

To start I made this little example of a RGB Led. Usually you begin making a loop through the RGB scale of colors. But it doesn’t look very natural since you expect to loop through a color hue. What you need is to convert a HSV (Hue Saturation Value) scale to RGB (Red Green Blue) scale that the LED support, and then loop through the Hue domain mantaining the Saturation and Value constants.

Circuit is here, look for the RGB LED example

Video:

Code (I’ve coded it as close as I could to the Arduino sample guidelines):


/*
 * Color Wheel LED
 *
 * Loops a RGB LED attached to pins 9,10,11 through
 * all the "exterior" colors of a Color Wheel
 * 
 * The RGB LED uses a 3 component (red green blue) model which adds light colors to produce 
 * a composite color. But the RGB does not make easy to loop through a more
 * "natural" sequence of colors. The HSV (hue saturation value) model uses a color cylinder
 * in which each color is a point inside the cylinder. 
 * The hue is represented by the angle at which the point is, the saturation represents
 * the length (how close to the center the point is) and the value represent the height at
 * which the point is. 
 *
 * By cycling the hue value from 0 to 360 degrees, and keeping the saturation and value at 1
 * we can represent all the brightest colors of the wheel, in a nice natural sequence.
 *
 * The algorithm to convert a HSV value to a RGB value is taken from Chris Hulbert's blog (splinter)
 *
 * Created 1 January 2011
 * By Eduardo A. Flores Verduzco
 * http://eduardofv.com
 *
 * References:
 * http://en.wikipedia.org/wiki/HSL_and_HSV
 * http://en.wikipedia.org/wiki/Color_wheel
 * http://splinter.com.au/blog/?p=29
 *
 *
 */

void setup() {
  //Set the pins to analog output
  pinMode(9,OUTPUT);
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
}

void loop() {
  //The Hue value will vary from 0 to 360, which represents degrees in the color wheel
  for(int hue=0;hue<360;hue++)
  {
    setLedColorHSV(hue,1,1); //We are using Saturation and Value constant at 1
    delay(10); //each color will be shown for 10 milliseconds
  }
}

//Convert a given HSV (Hue Saturation Value) to RGB(Red Green Blue) and set the led to the color
//  h is hue value, integer between 0 and 360
//  s is saturation value, double between 0 and 1
//  v is value, double between 0 and 1
//http://splinter.com.au/blog/?p=29
void setLedColorHSV(int h, double s, double v) {
  //this is the algorithm to convert from RGB to HSV
  double r=0; 
  double g=0; 
  double b=0;

  double hf=h/60.0;

  int i=(int)floor(h/60.0);
  double f = h/60.0 - i;
  double pv = v * (1 - s);
  double qv = v * (1 - s*f);
  double tv = v * (1 - s * (1 - f));

  switch (i)
  {
  case 0: //rojo dominante
    r = v;
    g = tv;
    b = pv;
    break;
  case 1: //verde
    r = qv;
    g = v;
    b = pv;
    break;
  case 2: 
    r = pv;
    g = v;
    b = tv;
    break;
  case 3: //azul
    r = pv;
    g = qv;
    b = v;
    break;
  case 4:
    r = tv;
    g = pv;
    b = v;
    break;
  case 5: //rojo
    r = v;
    g = pv;
    b = qv;
    break;
  }

  //set each component to a integer value between 0 and 255
  int red=constrain((int)255*r,0,255);
  int green=constrain((int)255*g,0,255);
  int blue=constrain((int)255*b,0,255);

  setLedColor(red,green,blue);
}

//Sets the current color for the RGB LED
void setLedColor(int red, int green, int blue) {
  //Note that we are reducing 1/4 the intensity for the green and blue components because 
  //  the red one is too dim on my LED. You may want to adjust that.
  analogWrite(9,red); //Red pin attached to 9
  analogWrite(10,green/3); //Red pin attached to 9
  analogWrite(11,blue/3); //Red pin attached to 9
}