Muy buenas a todos, ya he conseguido hacer más robusto el algoritmo, para ello, reconocemos el color amarillo de la imagen y la segmentamos.
Para encontrar el color amarillo, nos hemos basado en el espacio de color HSV, del ingles Hue, Saturation, Value -Tonalidad, Saturación, Valor.
La tonalidad nos representa el tipo del color, por ejemplo el rojo es 0, el verde 120.
La saturación representa la pureza del color, contra menos es su valor menos tonalidad de gris tendrá.
El valor del color es el brillo.
El algoritmo que nos queda es el siguiente: Primero pasamos la imagen al espacio HSV, después buscamos los puntos donde tenemos el color de nuestra pelota y en una imagen creada en blanco y negro vamos poniendo valor blanco para los puntos de nuestra pelota y valor negro para el resto. Después dibujamos nuestro circulo donde tenemos la pelota, para esto he utilizado el algoritmo de hough, aunque lo podríamos haber hecho de muchas maneras, esta ya la tenia hecha.
El código es el siguiente
#include <cv.h>
#include <highgui.h>
#include <math.h>
void main()
{
cvNamedWindow("Reco Pelota HSV",CV_WINDOW_AUTOSIZE); //Creamos una ventana
cvNamedWindow("Reco Pelota RGB",CV_WINDOW_AUTOSIZE);
cvNamedWindow("Reco Pelota Binearizada",CV_WINDOW_AUTOSIZE);
cvNamedWindow("Reco Pelota Segmentada",CV_WINDOW_AUTOSIZE);
CvCapture* capture= cvCreateCameraCapture(0); //Capturamos la cámara
assert( capture != NULL );
IplImage* frame;
IplImage* frameBN;
IplImage* frameHSV;
IplImage* frameSeg;
int height , width , step , channels , k = 1;
int step_bn , channels_bn;
int step_fra , channels_fra;
int step_seg , channels_seg;
uchar *data_hsv , *data_bn, *data, *data_seg;
int i,j;
int percent=200;
CvSeq* results;
bool Primera= true;
int hlower =95;
int hupper =105;
int Saturation=0;
int Brightness=0;
int Dilate = 10;
int Erode = 5;
while(1)
{
frame=cvQueryFrame(capture); //Capturamos la primera imagen
if(!frame) break; //Si no hay frame salimos
if (Primera)
{
//Creamos la imagen
frameHSV = cvCreateImage( cvGetSize(frame), IPL_DEPTH_8U, 3 );
frameBN = cvCreateImage( cvGetSize(frame), IPL_DEPTH_8U, 1 );
frameSeg=cvCreateImage( cvGetSize(frame), IPL_DEPTH_8U, 3 );
// Obtenemos atributos de la imagen HSV
height= frameHSV->height;
width= frameHSV->width;
step= frameHSV->widthStep/sizeof(uchar);
channels = frameHSV->nChannels;
step_bn = frameBN->widthStep/sizeof(uchar);
channels_bn = frameBN->nChannels;
step_fra = frame->widthStep/sizeof(uchar);
channels_fra = frame->nChannels;
step_seg = frameSeg->widthStep/sizeof(uchar);
channels_seg = frameSeg->nChannels;
//Creamos el lugar donde se almacenaran los circulos en el algoritmo de hough
CvMemStorage* storage = cvCreateMemStorage(0);
Primera=false;
}
cvCvtColor(frame,frameHSV,CV_RGB2HSV);
// Obtenemos los valores RGB de la Imagen
data_hsv = (uchar *)frameHSV->imageData;
data_bn = (uchar *)frameBN->imageData;
data = (uchar *)frame->imageData;
data_seg=(uchar *)frameSeg->imageData;
// Recorremos la imagen
for(i = 0; i <height; i++ ) {
for(j = 0; j <width; j++ ) {
if (((data_hsv[i*step+j*channels])>= hlower)&& ((data_hsv[i*step+j*channels]) <= hupper)){
if (data_hsv[i*step+j*channels+1]>= Saturation) {
if (data_hsv[i*step+j*channels+2]>= Brightness) {
// Coloreamos el pixel en blanco
data_bn[i*step_bn+j*channels_bn] =255;
data_seg[i*step_seg+j*channels_seg] = data[i*step_fra+j*channels_fra] ;
data_seg[i*step_seg+j*channels_seg+1] = data[i*step_fra+j*channels_fra+1];
data_seg[i*step_seg+j*channels_seg+2] = data[i*step_fra+j*channels_fra+2];
}
else
{
// Coloreamos el pixel en negro
data_bn[i*step_bn+j*channels_bn] = 0;
data_seg[i*step_seg+j*channels_seg] = 0;
data_seg[i*step_seg+j*channels_seg+1] = 0;
data_seg[i*step_seg+j*channels_seg+2] = 0;
}
}
else{
// Coloreamos el pixel en negro
data_bn[i*step_bn+j*channels_bn] = 0;
data_seg[i*step_seg+j*channels_seg] = 0;
data_seg[i*step_seg+j*channels_seg+1] = 0;
data_seg[i*step_seg+j*channels_seg+2] = 0;
}
}
else{
// Coloreamos el pixel en negro
data_bn[i*step_bn+j*channels_bn] = 0;
data_seg[i*step_seg+j*channels_seg] = 0;
data_seg[i*step_seg+j*channels_seg+1] = 0;
data_seg[i*step_seg+j*channels_seg+2] = 0;
}
}
}
// Erocionar y Dilatar , para la eliminacion de pixeles perdidos
cvErode(frameBN,frameBN,0,Erode);
cvDilate( frameBN,frameBN,0,Dilate);
cvErode(frameSeg,frameSeg,0,Erode);
cvDilate( frameSeg,frameSeg,0,Dilate);
//Suavizamos la imagen
//cvSmooth(frameBN, frameBN, CV_GAUSSIAN, 5, 5 );
//Aplicamos el algoritmo de Hough para circulos
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
1, //Resolución del acumulador
frameBN->width/10, //Mínima distancia entre dos circulos
12, //Umbral del algoritmo canny
12, //Acumulador del umbral
1, //Minimo radio
300 //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(
frame,
pt,
cvRound( p[2] ),
CV_RGB(0xff,0x00,0x00),
2);
}
cvShowImage("Reco Pelota HSV",frameHSV);
cvShowImage("Reco Pelota RGB",frame);
cvShowImage("Reco Pelota Binearizada",frameBN);
cvShowImage("Reco Pelota Segmentada",frameSeg);
char c = cvWaitKey(33);
if(c==27) break;
}
cvReleaseCapture(&capture);
cvDestroyWindow("Reco Pelota HSV");
cvDestroyWindow("Reco Pelota RGB");
cvDestroyWindow("Reco Pelota Binearizada");
cvDestroyWindow("Reco Pelota Segmentada");
}
Los vídeos que dejo son: Pelota binearizada
Pelota en el espacio HSV
Pelota segmentada
Pelota localizada