domingo, 5 de septiembre de 2010

SOLUCIÓN RETO II: RECONOCER UNA PELOTO Y SEGUIRLA

Este reto me está costando más de lo que me había planteado en un principio, pero bueno voy a publicar las soluciones que tengo hasta ahora.  De momento no sigo a la pelota pero la reconozco tanto en una foto como en un con la cámara.  Esto lo hago de la misma manera que el reto uno, con el algoritmo de hough.  
Para la fotografía este el  código que he hecho, como siempre he utilizado las librerías de OpenCV:

#include <cv.h>
#include <highgui.h>
#include <math.h>
void main ()
{   
    int percent=25;
    // Leemos la imagen
    IplImage* imagen = cvLoadImage("DSCN1886.jpg", CV_LOAD_IMAGE_GRAYSCALE);
    //Leemos imagen en color
    IplImage* imagenColor = cvLoadImage("DSCN1886.jpg");
    //Tenemos que reducir el tamaño de la imagen
    IplImage* imagenPequeña =cvCreateImage(cvSize((int)((imagen->width*percent)/100) , (int)((imagen->height*percent)/100) ),imagen->depth, imagen->nChannels );
    cvResize(imagen,imagenPequeña,CV_INTER_NN);
    //Lo mismo con la imagen en color   
    IplImage* imagenPequeñaColor =cvCreateImage(cvSize((int)((imagenColor->width*percent)/100) , (int)((imagenColor->height*percent)/100) ),imagenColor->depth, imagenColor->nChannels );
    cvResize(imagenColor,imagenPequeñaColor,CV_INTER_NN);

    //Creamos el lugar donde se almacenaran los circulos en el algoritmo de hough
    CvMemStorage* storage = cvCreateMemStorage(0);
    //Suavizamos la imagen
    cvSmooth(imagenPequeña, imagenPequeña, CV_GAUSSIAN, 5, 5 );
    //Aplicamos el algoritmo de Hough para circulos
    CvSeq* results = cvHoughCircles(
        imagenPequeña,        //Imagen en escala de grises, no hace falta aplicar ni canny ni sobel ya que lo invoca la función
        storage,            //El lugar donde almacena circulos
        CV_HOUGH_GRADIENT,    //El metodo
        2,                    //Resolución del acumulador
        imagenPequeña->width/10,    //Mínima distancia entre dos circulos
        150,                //Umbral del algoritmo canny
        150,                //Acumulador del umbral
        80,                //Minimo radio
        140                    //Máximo radio
        );
    //Dibujamos las circunferencias de color rojo en la imagen en color
    for( int i = 0; i < results->total; i++ ) {
        float* p = (float*) cvGetSeqElem( results, i );
        CvPoint pt = cvPoint( cvRound( p[0] ), cvRound( p[1] ) );
        cvCircle(
            imagenPequeñaColor,
            pt,
            cvRound( p[2] ),
        CV_RGB(0xff,0x00,0x00),
        2

        );
    }
    //Creamos la ventana
    cvNamedWindow( "Imagen", CV_WINDOW_AUTOSIZE );
    //Dibujamos la imagen
    cvShowImage( "Imagen", imagenPequeñaColor);

    //Esperamos indefinidamente hasta que se cierre la ventana
    cvWaitKey(0);
    //Borramos las imagen
    cvReleaseImage(&imagen);
    cvReleaseImage(&imagenColor);
    cvReleaseImage(&imagenPequeñaColor);
    cvReleaseImage(&imagenPequeña);
    //Destruimos la ventana
    cvDestroyWindow("Imagen");
}

La imagen que me dio fue la siguiente:
Solución, encontrar las pelotas en una foto.





Lo que más trabajo me está dando es la parte de la cámara, como no tengo nada para dejar la cámara fija, ya que la distancia de la cámara al plano de la pelota es muy importante, ya veis que en el la función que llama al algoritmo de hough le digo el mínimo y el máximo radio de la pelota, pues bien este cambia si me acerco con la cámara o me alejo.  En siguientes retos intentaremos solucionar este problemilla.  
#include <cv.h>
#include <highgui.h>
#include <math.h>

void main()
{
    int width;
    int height;
    cvNamedWindow("Reco Pelota",CV_WINDOW_AUTOSIZE);  //Creamos una ventana
    CvCapture* capture= cvCreateCameraCapture(0);    //Capturamos la cámara
    assert( capture != NULL ); 
    IplImage* frame;
    IplImage* frameBN;
    IplImage* frameGrande;
    int percent=200;
    while(1)
    {
        frame=cvQueryFrame(capture);  //Capturamos la primera imagen
        if(!frame) break;  //Si no hay frame salimos
        //Tenemos que ampliar el tamaño de la imagen
        frameGrande =cvCreateImage(cvSize((int)((frame->width*percent)/100) , (int)((frame->height*percent)/100) ),frame->depth, frame->nChannels );
        cvResize(frame,frameGrande,CV_INTER_NN);
        //Transformamos la imagen en BN
        width = frameGrande->width; 
        height = frameGrande->height;
        frameBN = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U,1); 
        cvCvtColor(frameGrande,frameBN,CV_RGB2GRAY);//Transformamos la imagen en blanco y negro
        //Creamos el lugar donde se almacenaran los circulos en el algoritmo de hough
        CvMemStorage* storage = cvCreateMemStorage(0);
        //Suavizamos la imagen
        cvSmooth(frameBN, frameBN, CV_GAUSSIAN, 5, 5 );
        //Aplicamos el algoritmo de Hough para circulos
        CvSeq* results = cvHoughCircles(
            frameBN,        //Imagen en escala de grises, no hace falta aplicar ni canny ni sobel ya que lo invoca la función
            storage,            //El lugar donde almacena circulos
            CV_HOUGH_GRADIENT,    //El metodo
            2,                    //Resolución del acumulador
            frameBN->width/10,    //Mínima distancia entre dos circulos
            50,                //Umbral del algoritmo canny
                                50,                //Acumulador del umbral
            150,                //Minimo radio
            200                    //Máximo radio
            );

        for( int i = 0; i < results->total; i++ ) {
            float* p = (float*) cvGetSeqElem( results, i );
            CvPoint pt = cvPoint( cvRound( p[0] ), cvRound( p[1] ) );
            cvCircle(
                frameGrande,
                pt,
                cvRound( p[2] ),
                CV_RGB(0xff,0x00,0x00),
                2);
            }

        cvShowImage("Reco Pelota",frameGrande);
        char c = cvWaitKey(33);
        if(c==27) break;
    }
    cvReleaseCapture(&capture);
    cvDestroyWindow("Reco Pelota");
}

Más adelante iré mejorando esta solución .  Lo que hay que mejorar es que siempre detecte la pelota, o sea hacer algo para que mi cámara este quieta, je je je.  Hay que tener en cuenta que la iluminación también es muy importante, otra cosa que no controlo desde mi despacho.  También tendríamos que implementar algoritmos para decirle que hay círculos que no son la pelota, falsos positivos.   Dejo el vídeo a continuación.
En retos posteriores, intentaremos mejorar este algoritmos con otras técnicas.  



6 comentarios:

  1. Hola,soy un alumno de teleco y estoy haciendo un proyecto parecido al tuyo, tengo que detectar celulas (circulos) en una imagen microscopica, y mi problema es parecido, cvhoughcircles detecta muchos circulos que no existen y otros que si existen no los detecta...has conseguido mejorar el algoritmo? tb tengo el problea del zoom ya que hay fotos con mayor zoom (por tanto celulas mas grandes) y otras con menor zoom y tengo k cambiar los parametros de la funcion. En fin, agradeceria cualquier ayuda, si yo tb puedo servirte en algo no dudes en preguntar. Mi correo es juaiva@yahoo.es Graciass :)

    ResponderEliminar
  2. Muy buenas, bienvenido al blog. Tu proyecto me parece muy interesante, y aquí me vas a tener para poder ayudarte en todo lo que pueda.
    El principal problema que le veo al algoritmo de hough es que detecta demasiados círculos, aunque no los haya. En el reto III mejoro un poco esto, aunque para lo que es tu proyecto no lo suficiente, ni siquiera para lo mío, que simplemente es reconocer pelotas de frontenis. Creo que deberías probar con la función cvHaarDetectObjects, mira los retos 4 a 5, los algoritmos serian muy parecido, aunque tu tendrás que entrenar el algoritmo. En la página 513 del libro learning openCV te dice como hacer eso. Esto creo que te podrá servir, eso sí necesitaras un montón de imágenes. Yo voy a probar eso mismo con las pelotas de frontenis, aunque lo ampliaré también a pelotas de futbol y otras. Bueno espero haber sido de ayuda.

    ResponderEliminar
  3. Hola, yo soy estudiante de Ing. en sistemas computacionales y estoy adentrandome al procesamiento de imagenes haciendo uso de Open CV, me parece interesante tu trabajo de la deteccion de colores y lo mas interesante seguirlo, podria tener muchas aplicaciones tu algoritmo. Yo estoy intentando instalar Open CV pero es muy confuso no lo e conseguido instalar, tendras un manual para poder instalarlo?. Te lo agradecera bastante.

    ResponderEliminar
  4. Hola muy buenas. No tengo ningún manual, para instalar OpenCV, ya que con cada compilador es un mundo. Yo utilizo el Visual C++ 2008 la versión exprés. Para este utilice este tutorial, http://opencv.willowgarage.com/wiki/VisualC%2B%2B
    Si utilizas otro compilador dímelo y así te ayudo.
    En este otro link te dice como instalarlo para otros compiladores.
    http://opencv.willowgarage.com/wiki/InstallGuide

    ResponderEliminar
  5. Hola soy Gerardo, muy interesante tus implementaciones. Sería genial si complementaras la implementacion de las pelotas localizando su centroide sobre todo para la imagen que tienes segmentada en blanco y negro. Es posible hacerlo?

    ResponderEliminar
  6. Hola Gerardo, bienvenido al blog. Muy buena idea. Supongo que si que si que será posible. Lo voy a hacer en el siguiente reto. Que por cierto estaba un poco falto de ideas.

    ResponderEliminar