Mostrando entradas con la etiqueta desarrollo. Mostrar todas las entradas
Mostrando entradas con la etiqueta desarrollo. Mostrar todas las entradas

martes, 13 de abril de 2010

Facedetect, los primeros pasos

Hola de nuevo, siento el parón informativo, pero modificando el facedetect.cpp, hemos tenido un par de etapas muy diferenciadas, una de rápidos avances, en la que el tiempo que le podíamos dedicar a la asignatura lo hemos invertido principalmente en avanzar, ya que los logros obtenidos eran bastante prometedores y visuales y nos animaban a seguir probando cosas. La segunda etapa, es la de la ofuscación, ya que tras los logros conseguidos en la primera parte, el avance se ha parado en seco, a la hora de manejar el haartraining, pero esto ya lo explicaremos con un poco más de calma en otro post...

Ahora, explicaremos que es lo que nos ha tenido entretenidos, mientras veíamos sus progresos y los pequeños problemas a los que nos hemos tenido que enfrentar, así como un poco el funcionamiento del facedetect.

Facedetect: es un programa propio de ejemplo de las librerías de OpenCV, y nos está sirviendo de base para la parte del reconocimiento visual. Este código, lo que realiza es la captura de una imagen obtenida mediante una webcam (también permite aplicarlo sobre imágenes almacenadas, u obtenidas por otros medios, pero es una parte que no nos interesa, por lo que no hemos indagado en ella) y detectar las posibles caras que en ella se encuentren, con un alto grado de detección, en detrimento de las falsas alarmas, ya que nos ha detectado en diversas ocasiones zonas arbitrarias como caras...

Recuadrar la zona de interés y guardarla: Para realizar esta parte, primero nos aprovechamos de que el propio programa pintaba un círculo sobre la cara detectada, por lo que nos aprovechamos de las dimensiones de dicho círculo, y su centro para establecer las cuatro esquinas de nuestro recuadro que se focalizará la cara, y nos ayudará a mejorar el sistema de detección de caras que estamos implementando, ya que así reducimos gran cantidad del fondo de la imagen que no va ha hacer más que meter ruido.
También, tuvimos problemas a la hora de salvar las imágenes, ya que los formatos que manejaba el facedetect, el Mat y cv::Mat, no permitían guardar la información como imagen ni convertirla al formato IplImage, que es el que si se puede guardar fácilmente, por lo que tuvimos que analizar el código, y modificarlo, ya que por suerte las capturas desde la webcam las realiza y guarda como variables IplImage.
a continuación, tras intentar manejarnos con punteros y extraer la información de estos, para poder modificar esta, acabamos teniendo que recurrir a la opción de guardar la imagen original y acto seguido cargarla de nuevo, en otra variable, para poder modificar esta sin afectar a la primera.
Además, por necesidades de los programas que nos permiten generar el sistema de reconocimiento, todas las imágenes de cara tenían que tener las mismas dimensiones, y hemos descubierto que es altamente recomendable que estén en escala de grises, lo que nos ha obligado a redimensionar las imágenes obtenidas, así como hacerles una conversión a escala de grises, que incluye un ajuste en el histograma (véase el código ejemplo)

Código:

Size s(210, 270);

IplImage* img = cvLoadImage(NOMBRE_IMAGEN, 1);

IplImage* img2 = cvCreateImage(s, 8, 1);

cvResize( img, img2, CV_INTER_LINEAR );

cvCvtColor( img2, img2, CV_BGR2GRAY ); //Convertimos a escala de grises

cvEqualizeHist( img2, img2 );//equalizamos el histograma a una imagen de un solo canal de 8 bit

cvSaveImage(NOMBRE_NUEVA_IMAGEN, img2, 0);


Por otro lado, también cabe destacar que como acabamos necesitando guardar gran cantidad de imágenes, nos valimos de una serie de comandos que hay en c++ para poder crear un bucle de captura en función de una variable de tipo int, la cual añadíamos como número, que no como caracter, al nombre del archivo a guardar, para generar una colección de imágenes con nombres legibles. Para esto, usamos el siguiente código:

for (int i = 0; i < 3000; i++){
char* nombre = "imagenPruebas";

std::string cont;

std::stringstream out;

out << i;
cont = out.str();

String extension = ".png";

String tot = nombre + cont + extension;

char *total = &tot[0];

}


Finalmente, cabe destacar que para evitar problemas, con los bordes de la pantalla, hemos introducido una serie de condiciones, que impiden guardar la imagen, si esta se encuentra en una posición que haría que el recuadro que seleccionamos, se salga de las dimensiones máximas de nuestra imagen total.

Superponer imagenes: Una vez que conseguímos guardar las imágenes, intentamos superponer unas encima de otras, para así poder realizar más adelante la parte de la realidad aumentada. Para esto, tuvimos que cargar una imagen y, pixel a pixel, pintarla sobre la imagen original, pero ya que las imágenes solo hemos descubierto como cargalas con fondo, hemos tenido también que hacer un filtrado de cada color, para saber cuales pintar y cuales no, aunque este método no funciona totalmente bien, ya que la imagen que pintamos además está redimensionada para ajustarla a la zona sobre la que la estamos pintando, que normalmente coincide con una parte del cuerpo y, en función de la distancia a la que nos encontremos de la cámara, nuestra imagen será más pequeña, y por ello, la imagen superpuesta ha de ajustarse.
Además, como parte de la imagen podía llegar a salirse de los límites de la imagen de 'fondo', nos vimos obligados a ajustar los valores de pintado, para que esta siempre se mostrara correctamente, y las partes que salieran de la pantalla, las mostrara correctamente 'cortadas' por los bordes de la imagen.

lunes, 5 de abril de 2010

El desarrollo físico del juego

Buenas despues de tanto tiempo sin actualizar, os vamos a contar los avances desarrollados en la práctica durante este último mes, aunque a partir de ahora actualizaremos más a menudo. Mientras Jorge se esta encargando del entrenamiento para la detección de caras, para ir avanzando, iré desarrollando la parte física de lo que será nuestro juego.

El primer problema que se planteó, como en cualquier juego, fue el simple hecho de empezarlo. ¿Cómo hacerlo?¿Por donde empiezo? ¿Como lo vamos a ligar a la otra parte?

Después de mucho pensarlo decidimos desarrollar el juego utilizando una matriz de dos dimensiones de numeros enteros rellenandola con ceros para los puntos en blanco, señalando con 1 los puntos criticos de la pelota, y con un 2 las palas.
Para ello creamos nuestra matriz
int TablaJuego[Pixelesfila][PixelesColumna]
Con esto ya tenemos la tabla ajustada al tamaño de la pantalla.
Además tambien hemos definido un RADIO de la pelota, que realmente será una cruz pero que nos dará los puntos donde la pelota puede chocar contra los bordes o las palas y un tamaño para la pala TAMANOPALA que momentaneamente y como una primera simplificación ocupará una columna.
for (int i=90; i<90+TAMANOPALA; i++){
TablaJuego [i][1]= 2;
TablaJuego [i][PixelesColumna-1] = 2;
}
Con esta inicialización estamos dejando una linea a la "espalda" de nuestro pala que será considerada como tanto del jugador contrario.

A partir de este momento se nos plantea la gran dificultad del juego. El movimiento de la pelota, sobre todo en los momentos críticos. Los golpes con la pala y los rebotes con las paredes. Y aún mas crítico será el momento en el que la pelota rebote y ademas se encuentre con la pala.

Asi pues recorreremos la matriz variando la posición de la pelota acorde a unas sencillas leyes como por ejemplo la que ilustra el siguiente fragmento de código.

ContinuaTrayectoria [0] = Trayectoria [0];
ContinuaTrayectoria [1] = Trayectoria [1];
TablaJuego [i+ContinuaTrayectoria[0]][j+ContinuaTrayectoria[1]] =1;
TablaJuego [i][j]=0;
i= i+ContinuaTrayectoria[0];
j= j+ContinuaTrayectoria[1];

Cuando el programa esté completamente operativo, se podrá observar, para quien quiera leer el código que se están estudiando todos los casos posibles.

Además en la última parte se ha incluido un pequeño marcador que variará cada vez que un jugador anote un gol.

Esperamos volver a escribir pronto.