11/3/09

Feria 2008: Shooter/Mover mouse con la mano.

Para la feria de ciencias d la EET nº9 de Lanus del 2008 yo,pereira y britez teniamos algo en la mente: Un jueguito donde le disparas a unos logos de WindowsXP con una pistola de jugete a un monitor/pantalla de proyector.

El proyector teniamos (prestaba profesor), la pistola de juegete y la webcam las aporte yo.

La idea constaba de poner un led infrarojo arriba del monitor y una webcam atada a la pistola y hackeada para que no filtre los rayos infrarojos, pero filtrando todos los demas con el material de los diskettes (la cosa gris/negra/marron) y que mande una foto a una PC que detectaria la posicion del punto mas brillante (led infrarojo) y calcularia la posicion XY donde se esta apuntando.

El programa era una mezcla rara de C con opencv (libreria analizadora de imagenes) y bash.

/***laopencv.c***/

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <opencv/cv.h>
#include <opencv/highgui.h>


int main(int argc, char *argv[])
{
  IplImage* img = 0;
  int height,width,step,channels;
  uchar *data;
  int i,j,k;

  if(argc<2){
    printf("Usage: main <image-file-name>\n\7");
    exit(0);
  }

  // load an image  
  img=cvLoadImage(argv[1],-1);
  if(!img){
    printf("Could not load image file: %s\n",argv[1]);
    exit(0);
  }

  // get the image data
  height    = img->height;
  width     = img->width;
  step      = img->widthStep;
  channels  = img->nChannels;
  data      = (uchar *)img->imageData;
  printf("Processing a %dx%d image with %d channels\n",height,width,channels);

  // create a window
  //cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE);
  //cvMoveWindow("mainWin", 100, 100);

  // invert the image
  //for(i=0;i<height;i++) for(j=0;j<width;j++) for(k=0;k<channels;k++)
  //  data[i*step+j*channels+k]=255-data[i*step+j*channels+k];

  //IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
  for (int x=0;x<width;x+=10) {
  for (int y=0;y<height;y+=10){
    CvScalar s;
    s=cvGet2D(img,y,x); // get the (i,j) pixel value
    printf("%f %i %i\n",s.val[0],x,y);
  }
  }

  // show the image
  //cvShowImage("mainWin", img );

  // wait for a key
  //cvWaitKey(0);

  // release the image
  cvReleaseImage(&img );
  return 0;
}

/***laopencv.c***/

/***shooter.sh***/

XY=($(./laopncv tmp.jpg | sort -r -n | head -n 1 | awk '{printf("%i %i",$2*3.41,$3*3.41)}'))
echo "mousemove ${XY[0]} ${XY[1]}" | xte

/***shooter.sh***/

El C esta practicamente robado de los ejemplos que vienen con la libreria, lo que hace es agarrar una foto y detectar el punto mas "brillante" (creo, yo en realidad fui cambiando el 0 en s.val: printf("%f %i %i\n",s.val[0],x,y);) hasta que me dio mas o menos lo que esperaba)

La documentacion daba asco, lo que encontramos era poco y dificil de entender, casi sin ejemplos simples.

La cosa esta andaba bastante bien, pero algo fallab enormemente: para adquirir la foto probamos cientos de comandos, tecnicas y programas, y todos tardaban mas de 1 segundo (lo que es excesivo siendo un jugeito de disparar que tenga un lag de mas de 1 segundo).

Capaz era el driver, capaz era la webcam, capaz mi kernel, nadie supo; pero el proyecto quedo ahi, ademas nadie tenia ganas de ensamblarlo(pereira = C, britez = PHP, alvare = Python, nadie sabia ni queria).

No solo eso sino que ademas si la persona era mas baja o se paraba mas cerca y al costado ya el mouse se movia para cualquier lado.

Bueno eso quedo en la nada, hace unos dias britez me viene mostrando progresos con una libreria llamada "touchlib" que encima es multitouch, con una caja y un vidrio (absurdamente simple comparado con nuestro pandemonium).

Dejo el codigo ahi, si cualquiera quiero robarlo, invitado sea.