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");
}
#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");
}
#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.
En retos posteriores, intentaremos mejorar este algoritmos con otras técnicas.
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 :)
ResponderEliminarMuy buenas, bienvenido al blog. Tu proyecto me parece muy interesante, y aquí me vas a tener para poder ayudarte en todo lo que pueda.
ResponderEliminarEl 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.
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.
ResponderEliminarHola 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
ResponderEliminarSi 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
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?
ResponderEliminarHola 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