domingo, 20 de mayo de 2012

Detección facial


Asignación #3 Implementación de un sistema inteligente
IntroducciónEl tema que elegí para esta asignación fue el de redes neuronales artificiales. Objetivo
Con la ayuda de un biblioteca de codigo abierto lograr desarrollar una aplicación que mediante el uso de redes neuronales artificiales logré detectar rostros humanos.

Justificación


Básicamente seleccione este tema por que es parte de mi proyecto de clase, el cual consiste en un detector de mentiras de tiempo real. Mientras tanto en esta practica he decidido poder iniciarme en el uso de redes neuronales artificiales para el procesamiento de datos, ya que la deteccion facial no es nadamas que simple agrupamiento y clasificacion a niveles un poco más complejos.




Desarollo

Para iniciar con el desarrollo de esta practica requeri descargar la libreria que me ayudaria a realizar el procesamiento de imagenes, video y por fortuna también a utilizar las redes neuronales artificiales. Decidí usar esta libreria por que esta bajo la licencia BSD que me permite usarla libremente para propósitos comerciales y de investigación tal es este caso.
Lo primero que hice fue descargar los binarios necesarios de la pagina de openCV para poderlos utilizar en el sistema android, esto es un poco complicado ya que el codigo de openCV esta hecho en C/C++ entonces hay dos opciones utilizar el NDK de android para poder utilizar codigo nativo en las aplicaciones y poder usar openCV tranquilamente. O usar javaCV el cual se podría decir que es la tradución de openCV pero en java.


Despues de configuraciones simples en el IDE eclipse ( agregar librerias externas a un proyecto de android 2.2 ) y agregar el codigo de ejemplo que viene para crear vistas simples con javaCV fui creando la aplicación.

Para el entrenamiento me di cuenta que para lograr resultados decentes o considerables necesitaba una buena base de conocimiento, por fortuna openCV contiene ya una base entrenada por haartraining con una cantidad de 3000 samples positivos y 1500 negativos la cual no pude quedarme con la tentación de ver que tan acertada era con una cantidad tan grande samples.

A continuacion muestro la parte del codigo del procesamiento.

  
/*En esta seccion de codigo podemos ver como 
 *se hace el procesamiento de 
 *cada frame, primero se hace una 
 *copia a color y una en escala de grises
 *despues se verifica si mCascade no esta 
 *vacia, este objeto es el clasificador
 *despues se toman los datos para iniciar 
 *con la comparacion y se utiliza el
 *metodo detectMultiScale del clasificador 
 *para comparar dicho imagen
 *Despues por cada rostro que se detecte se 
 *crea un rectangulo para enmarcarlo.
 *Por ultimo se crea un mapa de bits con los 
 *datos de la matriz de colores.
 */

     @Override
     protected Bitmap processFrame(VideoCapture capture) {    
        capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
        capture.retrieve(mGray, Highgui.CV_CAP_ANDROID_GREY_FRAME);

        
        if (mCascade != null) {
            int height = mGray.rows();
            int faceSize = Math.round(height * FdActivity.minFaceSize);
            List<Rect> faces = new LinkedList<Rect>();
            mCascade.detectMultiScale(mGray, faces, 
              1.1, 2, 2 , new Size(faceSize, faceSize));
            
            for (Rect r : faces)
                Core.rectangle(mRgba, r.tl(), r.br(), 
                        new Scalar(0, 255, 0, 255), 3);
        }
        
        Bitmap bmp = Bitmap.createBitmap(mRgba.cols(),
              mRgba.rows(), Bitmap.Config.ARGB_8888);

        if (Utils.matToBitmap(mRgba, bmp))
            return bmp;

        bmp.recycle();
        return null;
    }

Este segmento de codigo esta inmediato despues de proporcionarle a la aplicacion la base del entrenamiento previo. Por ultimo otras generalidades del proyecto fueron que solo lo pude permitir usar como landscape para tener una uso solido y poder seleccionar el tamaño del rostro en comparación del tamaño de resolución del celular. Esto es para poder ver el comportamiento dandole diferentes rangos al procesamiento.
Código completo AQUI

Resultados

La aplicación es capaz de detectar rostros, utilizando un tamaño de rostro pequeño en comparacion de la resolución de la camara. Son buenos resultados tomando en cuenta que el entrenamiento de la red fue tomando desde los ejemplos que proporciona openCV.

Video





Conclusiones

Pués los resultados resultaron bastantes satisfactorios, sin embargo no son 100% perfectos. Esto lo digo por que cuando esta detectando los rostros a veces confunde otras cosas con rostros, ademas parece ser que es más practico utilizar un tamaño de rostro pequeño con respecto a la resolución de la camara, pero esto produce más procesamiento y por ende le pide mas recursos al telefono lo cual no es muy bueno. 

lunes, 26 de marzo de 2012

Autómata Celular


Asignación #2 Implementación de un sistema complejo
IntroducciónEl tema que elegí para esta asignación fue el de autómatas celulares. Objetivo
Desarrollar un sistema capaz de recrear algunas reglas de los autómatas celulares utilizando solamente el lenguaje de programación java.

Justificación


Seleccione este tema porque me interesa el desarrollo de sistemas caóticos y descubrí que con una de las reglas de los automates celulares se pueden crear algunos. Por ejemplo la regla número 90 nos crea los triángulos de Sierpiński






Desarollo
Para el desarollo de este sistema primero me enfoque en como modelar las reglas en un sistema computacional, para lo que pensé en utilizar un vector con valores booleanos que representara las reglas de esta manera :

Vector booleano
Este sistema se rige por valores booleanos para pintar los pixeles y dibujar la regla correspondiente. Además se toma en cuenta que un autómata celular puede ser sensible a los valores iniciales de entrada (caracteristica de un sistema caótico) así que se toma en cuenta si el desarrollo del autómata inicie con un motivo inicial aleatorio o que inicie con un vector booleano de descrito por esta formula:

De cualquier forma eso es desición de cada persona al ejecutar el sistema.

Las reglas que tome en cuenta fueron las siguientes: 

Código
Las partes interesantes del código iniciando con la parte que decide que color y pixel pintar.
public void paint(Graphics g){
     g2 = (Graphics2D) g;
     g2.setStroke(stroke);
     for(int y = 0; y < Automata.SIZE_Y; y++){
      if(y != 0) area = Regla.evalua(area,y-1,regla);
      for(int x = 0; x < Automata.SIZE_X; x++){
       color = (area[x][y] == true)?Color.WHITE:Color.BLACK;
       g2.setPaint(color);
       g2.draw(new Line2D.Float(x, y, x, y));
      }
     }
Ahora estas son las reglas
    public static final Boolean[] regla30 = {false,false,false,true,true,true,true,false};
    public static final Boolean[] regla90 = {false,true,false,true,true,false,true,false};
    public static final Boolean[] regla110 = {false,true,true,false,true,true,true,false};
    public static final Boolean[] regla150 = {true,false,false,true,false,true,true,false};
    public static final Boolean[] regla184 = {true,false,true,true,true,false,false,false};
y por ultimo la seccion donde se decide el valor de la siguiente casilla
Boolean[] subArray = { area[size-1][y], area[0][y], area[1][y] };
     for(int x = 0; x < size; x++){
      if(x == 0){
       area[x][y+1] = aplicaRegla(subArray,regla);
      }else if(x == size-1){
       subArray[0] = area[x-1][y];
       subArray[1] = area[x][y];
       subArray[2] = area[0][y];
       area[x][y+1] = aplicaRegla(subArray,regla);
      }else{
       subArray[0] = area[x-1][y];
       subArray[1] = area[x][y];
       subArray[2] = area[x+1][y];
       area[x][y+1] = aplicaRegla(subArray,regla);
      }
     }
     return area;


Código completo AQUI

Resultados
Los resultados fueron los esperados, ya que dichas reglas ya fueron comprobadas desde hace un par de años por Stephen Wolfram. Sin embargo descubrí que un sistema complejo de ese tipo puede llegar a tener cambios muy interesantes con solo cambiar sus valores iniciales.

Video




Conclusiones
Como antes mencioné los resultados fueron los esperados, los autómatas celulares dan principio para la creación de fractales simples. Ahora tomando en cuenta los patrones quizá diseñe un sistema que relacione los automatas con sonidos y no con pixeles. 

Sistema de semaforos


Asignacion #1 del laboratorio de Sistemas adaptativos.
En esta practica se requiere simular un sistema de trafico controlado por semaforos. La idea principal es evitar que los semaforos permitan una colisión al permitir el paso de los automóviles por vias abiertas al flujo que intersecten.
Objetivo

 Crear la simulación de un semáforo para una avenida con 3 sentidos, un sistema de trafico comun contiene 4 semaforos para controlar 4 sentidos. En este caso tomamos un modelo real con solo 3 sentidos.

Podemos ver en el dibujo que el sentido A puede avanzar de izquierda a derecha, con posibilidad de entrar al sentido de C y de B, con la condicion de que estos sentido esten deshabilitados para evitar colisiones.

Respecto al sentido B este puede avanzar de arriba hacia abajo, con la condicion de que A este deshabilitado.

El sentido C recorre de abajo para arriba siempre y cuando A & D esten deshabilitados. 


El sentido D recorre en diagonal desde arriba comenzando en el sentido B para pasar hacia el sentido de A siempre y cuando esten deshabilitados el A y el C.






Justificacion


A partir de el dibujo y la logica de como funciona un semaforo real, modelamos la solucion con algebra booleana, tomando en cuenta que cuando el semaforo esta en verde seria un uno logico y cuando el semaforo esta en rojo seria un cero logico.

Los casos especiales estan en la linea 2, que es cuando todos estan apagados y en gran cantidad de combinaciones se provocaria una colision. Solo tendriamos 6 casos posibles de combinaciones.

De los 6 casos disponibles, hicimos una minimizacion de ecuaciones dejando disponible 4.

A = !B && !C && !D
B = !A && C && D
C = !A && B &&  !D
D = !A && B && !C

De ahi concluimos que B y C son similares y pueden actuar al mismo tiempo, al igual que B y D. Asi que las combinaciones nos quedaron asi:

A
B && C
B && D

Puesto que D es una vuelta, le daremos prioridad en la ecuacion para terminar con una serie de ciclos solidos.

A -> B&&D -> B&&C

Ahora que los ciclos estan definidos, podemos darle las prioridades a cada ecuacion, esto lo haremos creando un numero aleatorio de carros, que a su vez sean comparados en cada sentido. Tomando en cuenta que los sentidos B,C,D estan ligados, se agarra el valor maximo de carros en esos tres sentidos y se compara con el valor resultante aleatorio de el sentido A, despues el sentido que tenga mayor cantidad de carros en espera es el que toma mas tiempo encendido.
La cantidad resultante de los carros afecta directamente al tiempo que dura encendido el semaforo correspondiente, recordando que los sentidos B,C,D estan ligados para evitar colisiones.

Codigo
public void iniciar(){
 
   semaforos[0].start();
   semaforos[1].start();
   semaforos[2].start();
   semaforos[3].start();
   inicia(); // Inicializa los elementos graficos

   try { Thread.sleep(1000); }catch(InterruptedException e){}

while(true){

   //Tiempos
   juezTiempos();

   secuenciaA();
   try { Thread.sleep(tiempoX); }catch(InterruptedException e){}

   secuenciaAmarillos(0);
   try { Thread.sleep(500); }catch(InterruptedException e){}

   secuenciaBD();
   try { Thread.sleep(tiempoY-300); }catch(InterruptedException e){}

   secuenciaAmarillos(3);
   try { Thread.sleep(500); }catch(InterruptedException e){}

   secuenciaBC();
   try { Thread.sleep(tiempoY); }catch(InterruptedException e){}

   secuenciaAmarillosDobles(1,2);
   try { Thread.sleep(500); }catch(InterruptedException e){}

 }
} // fin del iniciador

private void juezTiempos(){

      carrosX = Randoms.NumerosAleatorios(1,10); // rango del 1 al 10
      carrosY = Randoms.NumerosAleatorios(1,10);

      Carros[0].setText(""+carrosX); // Heuristica para la impresion del numero de carros
      Carros[1].setText(""+carrosY);

      switch (carrosX){

      case 1: tiempoX = 1800;
              break;
      case 2: tiempoX = 2000;
              break;
      case 3: tiempoX = 2400;
              break;
      case 4: tiempoX = 3000;
              break;
      case 5: tiempoX = 3800;
              break;
      case 6: tiempoX = 4400;
              break;
      case 7: tiempoX = 5000;
              break;
      case 8: tiempoX = 6000;
              break;
      case 9: tiempoX = 7300;
              break;
      case 10: tiempoX = 8500;
              break;
      default: tiempoX = 1000;
      }
 
      switch (carrosY){

      case 1: tiempoY = 1800;
              break;
      case 2: tiempoY = 2000;
              break;
      case 3: tiempoY = 2400;
              break;
      case 4: tiempoY = 3000;
              break;
      case 5: tiempoY = 3800;
              break;
      case 6: tiempoY = 4400;
              break;
      case 7: tiempoY = 5000;
              break;
      case 8: tiempoY = 6000;
              break;
      case 9: tiempoY = 7300;
              break;
      case 10: tiempoY = 8500;
              break;
      default: tiempoY = 1000;
      }
  } // Fin del juez de tiempo 
Aqui dejamos lo que mas resalta del codigo, que es la forma en que se adapta este sistema.


El codigo completo lo pueden ver aqui


Resultados
Despues de analizar el programa durante su ejecuccion nos dimos cuenta que se logra evitar cualquier tipo de choque, se mejora un poco el rendimiento de los semaforos utilizando la logica difusa con respecto a la cantidad de carros que llegan a cada semaforo.


Conclusiones



Como conclusion obtuvimos que las colisiones no son probables, ya que la solucion logica no permite que los semaforos den paso a que los automoviles choquen. Y el hecho de que la cantidad de automoviles sea aleatoria no influye en la logica que evita que los carros colisionen, pero tampoco es la solucion optima para librerar el trafico lento.


Video

En el video se puede apreciar que la secuencia de los semaforos es A, despues B y D, se termina el D, y continuan el B y C. 
Los numeros que aparecen determinan la cantidad de carros en las direcciones. Como B,C,D dependen de ellos mismos gracias a las ecuaciones.