día 3: Separando funciones: detect, draw, show

Tenemos un método que es detect_and_draw, que lo que hace es detectar las caras con ojos, dibujarlas y mostrarlas en pantalla. Vamos a intentar dividirla en distintas funciones para poder mostrar imágenes con dibujo o sin dibujo según deseemos, y tener también la opción de mostrarlas o no mostrarlas. Las funciones serían:

  • detect: detecta para una imagen donde están las caras, y guarda una copia de la imagen con la situación de las caras.
  • draw: dibuja en una imagen las caras y los ojos detectados.
  • show: Muestra una imagen en una pantalla.

Antes a detect_and_draw le pasábamos un puntero a una imagen. Ahora como este puntero va a ser utilizado tanto por detect como por draw como por show, necesitamos pasarles un puntero a puntero:  “IplImage** img” a los tres métodos.

Esto cambiará también todas las llamadas al método al que tendremos que pasarle la variable que contiene al puntero que antes le pasábamos. Por ello creamos en ImageProcess, desde donde van s ser llamados los métodos detect, draw show, el puntero a puntero de la imagen que luego se le pasará a la función:IplImage **frame_cop=&frame_copy;

Dentro de detect, hay que tener cuidado, porque el puntero a la imagen era un struct, y ahora al utilizar la operacíon de puntero y la de struct, es necesario un paréntesis para que se puedan realizar, por ejemplo, siendo img el puntero a puntero de una imagen, necesitamos hacer lo siguiente:

gray = cvCreateImage( cvSize((*img)->width,(*img)->height), 8, 1 );

En verde se indica el paréntesis para que sea correcto el orden de operaciones:

  1. Coge el contenido de img que es un struct (es un puntero a una imagen)
  2. Coge el parámetro de ese struct, en ese caso width o height, que sería lo mismo que (*img).width, o (*img).height

Ahora debemos de crear una serie de arrays, para que se guarden todas las caras y ojos detectados y así puedan ser dibujadas posteriormente en caso de desearlo, o podemos hacer lo que queramos con ellas. De momento, sólo sirven para dibujar, pero podría servir también para implementar una función que fuera guardar captura, ya que ahora esa función la realizamos cada vez que detectamos, porque suponemos que es necesario guardar la información al detectar.

Habrá un array para el centro de las caras o ojo, (que es un struct), otro para el radio y otro para el color. Como los arrays ya son punteros a una zona de memoria, no hace falta utilizar el símbolo *, sino que el contenido del array quedará guardado al llamar a distintas funciones. Los arrays los creamos de capacidad 50 elementos y por ello creamos un contador, para saber hasta que elemento tenemos guardado algo, y para que en caso de llegar al elemento 50, no guarde más. De todas maneras, creemos que nunca se pasará de detectar 50 ojos y caras, porque debería haber muchas personas en pantalla.

En ImageProcess declaramos los arrays y el contador, que si habrá que pasarlo por puntero.

 CvPoint centros[50];
 int radios[50];
 CvScalar colores[50];
 int cont=0;
 int *contador=&cont;

Una cosa importante es poner el contador a cero al principio de detect, para que en cada imagen esté correctamente inicializado, y los arrays no hace falta resetearlos, porque el contador nos sirve para saber hasta qué elemento hay información útil.

Ahora, dentro del bucle donde ve dónde se encuentra cada cara detectada, debemos de ir guardando los parámetros de los ojos y caras detectados. Esto debemos hacerlo dentro del bucle que va analizando los ojos detectados dentro de caras detectadas previamente en el anterior bucle:

for( j = 0; j < (nested_objects ? nested_objects->total : 0); j++ )
            {
    
                CvRect* nr = (CvRect*)cvGetSeqElem( nested_objects, j );
    CvPoint centero;
    int radiuso;
    double dist=0;
                centero.x = cvRound((r->x + nr->x + nr->width*0.5)*scale);
                centero.y = cvRound((r->y + nr->y + nr->height*0.5)*scale);
                radiuso = cvRound((nr->width + nr->height)*0.10*scale);

    if(*contador<50){

     if(!j){

     centros[*contador]=center;
     radios[*contador]=radius;
     colores[*contador]=color;
     *contador=*contador+1;
     }

    }
    else {
     printf(“ERROR: No se pueden dibujar más círculos\n” );
    }

    if(*contador<50){

     centros[*contador]=centero;
     radios[*contador]=radiuso;
     colores[*contador]=color;
     *contador=*contador+1;

    }
    else {
     printf(“ERROR: No se pueden dibujar más círculos\n” );

    }

De esta forma, con el primer if guardamos los datos de la cara, sólo para el ojo de j=0, porque la cara es la misma en todos los ojos, y con el segundo if, guardamos los datos del ojo. Utilizamos el contador para el caso en que hubiera desbordamiento; en tal caso, se imprimiría un mensaje por pantalla.

Ahora, draw queda como una función muy sencilla:

void draw(IplImage** img, CvPoint centros[], int radios[], int *contador, CvScalar colores[] ){

 int i;
 for(i=0;i<*contador;i++){
 cvCircle( *img, centros[i],radios[i] , colores[i], 3, 8, 0 );
 }
}

 En ella, cogemos todos los ojos y caras guardamos y los dibujamos en la imagen indicada por el parámetro img.

En show, simplemente debemos mostrar la imagen:

void show(IplImage** img){

cvShowImage( “result”, *img );
}

Por tanto ahora, detect, draw y show son tres funciones independientes, declaradas de la siguiente forma:

void detect( IplImage** image,int *entero, CvPoint centros[], int radios[], int *contador,CvScalar colores[] );
void draw(IplImage** img, CvPoint centros[], int radios[], int *contador, CvScalar colores[] );
void show(IplImage** img);

Lo que es necesario es llamar a detect para detectar las caras, porque sin ella, no podríamos dibujar y si mostráramos la imagen, sería sin hacer la función esencial del programa que es detectar caras.

En el futuro, quizás podríamos independizar también la función de guardar capturas, simplemente creando un array de booleans que sea true si guardo una cara y false si guardo un ojo, ya que sólo querré guardar información de las caras.

 

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: