domingo, 29 de agosto de 2010

RETO II: RECONOCER UNA PELOTA Y SEGUIRLA

Para este segundo reto, he pensado en que podríamos reconocer una pelota, de estas de frontenis.  Primero esto lo haremos con una fotografía, para posteriormente, con la ayuda de una cámara, hacer un algoritmo que nos siga la pelota en la imagen.
Dos pelotas de frontón.

Para realizar este reto, en la primera parte, buscaremos las dos pelotas de frontón en la imagen, utilizaremos el algoritmo de hough, igual que en el reto 1.  Para la segunda parte conectaremos una cámara al ordenador y buscaremos la pelota e iremos dibujando las posiciones dentro de la imagen por las que ha pasado.

sábado, 28 de agosto de 2010

TRANSFORMADA DE HOUGH

Durante la resolución de nuestro primer reto, hemos utilizado una función de OpenCV CvHoughCircles, que es la encargada de buscar el contorno de la moneda.  ¿Pero realmente que hace esta función?.  Esta función realmente sirve para encontrar circunferencias en una imagen, primero aplica un detector de contornos, como pueden ser los algoritmos de Sobel o Canny, más adelante ablaremos de ellos, y después aplica la transformada de Hough para circulos.

¿Qué es la transformada de Hough?

Esta transformada intenta buscar figuras geometricas simples en una imagen.  Cuando se procesa emplea toda la imagen, haciendola robusta ante la presencia de ruido o las discontinuidades de las etapas previas, ya que para hacer esta transformada primero hemos de binearizar la imagen con los bordes seleccionados, o sea tenemos que aplicar un detector de bordes.  A partir de aqui el algoritmo intentará buscar figuras geometricas, como pueden ser linea, circulos elipses.


DETECCIÓN DE LÍNEAS

Considerando un punto de coordenadas (Xi,Yi), como elemento que representa un borde; sobre éste pasarán infinitas rectas:
                  Yi=aXi+b   (1)
Que es la ecuación de una recta, en la cual . En la que tendremos que calcular los parámetros a y b.  Si despejamos b.
                 b=Yi-aXi  (2)
Al variar el parámetro a desde menos infinito hasta mas infinito se obtendrá los infinitos valores de b. La representación geométrica de  b = Yi − aXi , es una recta. La característica interesante de esta presentación consiste que si dos puntos que pertenezcan a una misma recta (1) implicará que tengan el mismo valor de a y b. 

Entonces la transformada de Hough aplica este concepto a las líenas rectas de la imagen.  Discretizando la imagen desde un valor de "a minimo" hasta un valor de "a maximo" y desde "b minimo" hasta "b máximo" creando unas rejillas de acumulación.  Por cada punto, considerado como borde, se hace recorrer el rángo de a obteniedo b.  Por cada valor de a y b se pone un voto.  Al finalizar, aquellos valores con más votos indicaran la presencia de rectas en la imagen, cuyo modelo corresponderá con los valores de a y b.

DETECCIÓN DE CIRCULOS
En este caso utilizaremos la ecuación de la circunferencia.
                  (Xi-Xo)^2+(Yi-Yo)^2=r^2
Las votaciones  se realizarán variando la posición del centro del círculo, (Xo, Yo, para cada píxel etiquetado, (xi,yi), obteniendo los distintos valores del radio, r.  Los círculos seleccionados serán aquellos que superen un cierto umbral de votos recibidos. El mayor inconveniente es su alto coste computacional. Una forma de ahorro en el cálculo es prefijar el valor del radio del círculo. Si se conoce el radio, junto con la información de la orientación del gradiente del píxel etiquetado, (Xi,Yi), las posibles coordenadas del centro del círculo darán una nube de puntos limitados.
La ventaja de esta detección de los círculos proviene de las características inherentes de las transformadas de Houhg, la inmunidad al ruido y que es capaz de detectar círculos, aunque exista oclusión del mismo. Por otro lado, en este tipo de curvas, al ser cerradas, no hay problemas del carácter infinito de las líneas rectas. Los círculos están definidos en la imagen, sin ninguna expansión.


martes, 24 de agosto de 2010

SOLUCIÓN RETO I: DETECCIÓN DE MONEDAS

Hola muy buenas a todos, ya se que daba una semana para resolver el primer reto, pero bueno, al final ha sido más fácil de lo que pensaba.  Esto ha sido así gracias a que la librería OpenCV ya tiene implementados un montón de algoritmos, y entre ellos el de reconocer círculos en una imagen, el algoritmo de openCVHough para círculos. utilizado es la transformada de

La primitiva de esta función se la siguiente:
CvSeq* cvHoughCircles(
CvArr* image,
void* circle_storage,
int method,
double dp,
double min_dist,
double param1 = 100,
double param2 = 300,
int min_radius = 0,
int max_radius = 0
);
Esta función nos devuelve un puntero con los datos de la circunferencias encontradas, punto central y radio.
Los parámetros son en este orden, la imagen, esto indica si es un array de almacenamiento o una memoria (realmente esto no lo entiendo muy bien, continuaré estudiandolo je je je), el siguiente parámetro es el método, normalmente es CV_HOUGH_GRADIENT, el parámetro dp es la resolución del acumulador, y el siguiente parámetro es la distancia mínima entre dos círculos.  Los dos parámetros siguientes son el umbral y el acumulador del umbral del algoritmo de canny, y los dos últimos parámetros son el mínimo y el máximo radio de las circunferencias.
Bien vale, para resolver el problema he seguido esta estructura,
  1. Leer imagen, la imagen en escala de grises.
  2. Suavizar imagen
  3. Aplicar el algoritmo de hough para circulos
  4. Dibujar los círculos de la imagen.
A parte he leído también la imagen en color para así dibujar los círculos sobre esta, y he tenido que escalarla, ya que si no las imagenes se me hacían muy grandes.
El código en C que he creado es el siguiente:

#include <cv.h>
#include <highgui.h>
#include <math.h>
void main ()
{   
    int percent=25;
    // Leemos la imagen
    IplImage* imagen = cvLoadImage("DSCN1882.jpg", CV_LOAD_IMAGE_GRAYSCALE);
    //Leemos imagen en color
    IplImage* imagenColor = cvLoadImage("DSCN1882.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
        100,                //Umbral del algoritmo canny
        100,                //Acumulador del umbral
        100,                //Minimo radio
        200                    //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)
        );
    }
    //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 he obtenido es:
Imagen con las dos monedas detectadas



Bueno esta es mi solución, os invito a proponer otras soluciones, seguramente mucho mejores que esta.

lunes, 23 de agosto de 2010

RETO I: DETECCIÓN DE MONEDAS

Para el primer reto vamos a intentar detectar monedas en una fotografía, no pretendemos conocer su valor ni nada de eso, pero si que el ordenador sea capaz de detectar una moneda, o una circunferencia que al caso va a ser lo mismo.  Mas adelante iremos complicandolo para que detecte el valor de la moneda.  De momento lo vamos a hacer con imágenes, y en un futuro con una cámara.
Monedas de 20 y 50 centimos

En el blog cada semana iré poniendo un reto, de esa forma entre todos lo solucionamos y aprendemos un poco todos juntos.

Para resolver este reto yo voy a utilizar las librerías de OpenCV y voy a programarlo en C.  El algoritmo que voy a seguir es el siguiente.  Primero intentar buscar los bordes de la fotografía con un algoritmo de detección de bordes como puede ser el algoritmo de Sobel o el de Canny, después binearizaré la imagen, para posteriormente intenta buscar algo que se parezca a la ecuación de la circunferencia (Algoritmo de hough).    Parece fácil, pero de momento ni pajolera idea de como solucionarlo, bueno tenemos una semana, a lo largo de esta semana iré presentando resultados.

domingo, 22 de agosto de 2010

Presentación

Desde hace varios años, me he dedicado al mundo de la automatización industrial y robótica, y desde hace unos meses me he adentrado en un mundo increíble, que es la visión artificial.  En este blog he decidido comentar mis retos y trabajos desarrollados en este mundo.  En principio en este blog hablaré de visión, aunque no descarto hablar de otro temas relacionados con el mundo de la automatización industrial, la robótica, la inmótica y la domótica.
Las librerías que utilizo en el mis pequeños proyectos de visión, son las OpenCV, es este blog intentaré desglosaralas para ir explicando que es lo que hacen y para que sirven las diferentes funciones que esta integra, como capturar las imágenes de una cámara, como detectar los bordes de una imagen, mediante los algoritmos de canny, etc.
Bueno poco a poco iré comentando mis experiencias y como voy resolviendo los problemas que me vayan surgiendo.