domingo, 13 de marzo de 2011
RETO IX: OBTENER EL CENTROIDE DE UNA PELOTA
Muy buenas en el próximo reto vamos a volver con las pelotas de frontenis, y vamos a intentar hallar la posición del centroide de las pelotas. En una primera idea, primero obtendremos como siempre el perímetro de la pelota, para posteriormente calcular el centroide. Bueno como siempre si a alguien se le ocurre formas de como hacerlo que escriba un comentario.
domingo, 6 de marzo de 2011
SOLUCIÓN RETO VIII 2:QUITAR EL FONDO
Bueno al final lo he conseguido. El método que voy a contar ahora aparece en el libro learning openCV de Gary Bradski &Adrian kaehler, es el Averaging Background Method (Método de promedio de fondo). Básicamente aprende la media y la desviación estándar de cada pixel como su modelo del fondo.
En primer lugar se crean punteros a varias imágenes de ceros y estadísticas de mantenimiento que se utilizaran a lo largo del proceso.
Después creamos todas estas imagenes, esto lo hacemos con esta función a la cual le pasamos nuestra imagen.
Después aprendemos la estadística del fondo para más de una imagen. O sea llamaremos esta función unas cuantas veces. Yo la he llamado unas 500. Al principio del algoritmo, así aprendemos el fondo. En este momento no debe aparecer ningún primer plano.
A partir de aquí ya podemos ir evaluando frame a frame nuestras imagenes e ir separando el fondo del primer plano. Para esto nos crearemos una máscara, negro fondo y blanco primer plano, y a partir de aquí lo podremos utilizar.
Con esta función es con la que creamos la máscara que discrimina el fondo del primer plano.
void backgroundDiff(IplImage *I, IplImage *Imask)
{
cvCvtScale(I,Iscratch,1,0); // To float;
cvSplit( Iscratch, Igray1,Igray2,Igray3, 0 );
//Canal 1
//
cvInRange(Igray1,Ilow1,Ihi1,Imask);
//Canal 2
//
cvInRange(Igray2,Ilow2,Ihi2,Imaskt);
cvOr(Imask,Imaskt,Imask);
//Canal 3
//
cvInRange(Igray3,Ilow3,Ihi3,Imaskt);
cvOr(Imask,Imaskt,Imask);
//Invertimos el resultado
//
cvSubRS( Imask, cvScalar(255,255,255), Imask);
}
Al final del todo liberamos la memoria de todas las imágenes.
Si queréis saber más sobre este método está descrito en el libro Learning OpenCV de Gary Bradski y Adrian Kaehler
En primer lugar se crean punteros a varias imágenes de ceros y estadísticas de mantenimiento que se utilizaran a lo largo del proceso.
//Almacenamiento global
//
//Float,Imagen de tres canales
//
//Float,Imagen de tres canales
//
IplImage *IavgF,*IdiffF, *IprevF, *IhiF, *IlowF;
IplImage *Iscratch,*Iscratch2;
//Float, Imagen de un canal
//
IplImage *Igray1,*Igray2, *Igray3;
IplImage *Ilow1, *Ilow2, *Ilow3;
IplImage *Ihi1, *Ihi2, *Ihi3;
// Byte, Imagen de un canal
//
IplImage *Imaskt;
//Cuenta el numero de imágenes para la media posterior
//
float Icount; IplImage *IavgF,*IdiffF, *IprevF, *IhiF, *IlowF;
IplImage *Iscratch,*Iscratch2;
//Float, Imagen de un canal
//
IplImage *Igray1,*Igray2, *Igray3;
IplImage *Ilow1, *Ilow2, *Ilow3;
IplImage *Ihi1, *Ihi2, *Ihi3;
// Byte, Imagen de un canal
//
IplImage *Imaskt;
//Cuenta el numero de imágenes para la media posterior
//
Después creamos todas estas imagenes, esto lo hacemos con esta función a la cual le pasamos nuestra imagen.
void AllocateImages( IplImage* I )
{
CvSize sz = cvGetSize( I );
IavgF = cvCreateImage( sz, IPL_DEPTH_32F, 3 );
IdiffF = cvCreateImage( sz, IPL_DEPTH_32F, 3 );
IprevF = cvCreateImage( sz, IPL_DEPTH_32F, 3 );
IhiF = cvCreateImage( sz, IPL_DEPTH_32F, 3 );
IlowF = cvCreateImage( sz, IPL_DEPTH_32F, 3 );
Ilow1 = cvCreateImage( sz, IPL_DEPTH_32F, 1 );
Ilow2 = cvCreateImage( sz, IPL_DEPTH_32F, 1 );
Ilow3 = cvCreateImage( sz, IPL_DEPTH_32F, 1 );
Ihi1 = cvCreateImage( sz, IPL_DEPTH_32F, 1 );
Ihi2 = cvCreateImage( sz, IPL_DEPTH_32F, 1 );
Ihi3 = cvCreateImage( sz, IPL_DEPTH_32F, 1 );
cvZero( IavgF );
cvZero( IdiffF );
cvZero( IprevF );
cvZero( IhiF );
cvZero( IlowF );
Icount = 0.00001; //Protección contra la división por cero
Iscratch = cvCreateImage( sz, IPL_DEPTH_32F, 3 );
Iscratch2 = cvCreateImage( sz, IPL_DEPTH_32F, 3 );
Igray1 = cvCreateImage( sz, IPL_DEPTH_32F, 1 );
Igray2 = cvCreateImage( sz, IPL_DEPTH_32F, 1 );
Igray3 = cvCreateImage( sz, IPL_DEPTH_32F, 1 );
Imaskt = cvCreateImage( sz, IPL_DEPTH_8U, 1 );
cvZero( Iscratch );
cvZero( Iscratch2 );
}
{
CvSize sz = cvGetSize( I );
IavgF = cvCreateImage( sz, IPL_DEPTH_32F, 3 );
IdiffF = cvCreateImage( sz, IPL_DEPTH_32F, 3 );
IprevF = cvCreateImage( sz, IPL_DEPTH_32F, 3 );
IhiF = cvCreateImage( sz, IPL_DEPTH_32F, 3 );
IlowF = cvCreateImage( sz, IPL_DEPTH_32F, 3 );
Ilow1 = cvCreateImage( sz, IPL_DEPTH_32F, 1 );
Ilow2 = cvCreateImage( sz, IPL_DEPTH_32F, 1 );
Ilow3 = cvCreateImage( sz, IPL_DEPTH_32F, 1 );
Ihi1 = cvCreateImage( sz, IPL_DEPTH_32F, 1 );
Ihi2 = cvCreateImage( sz, IPL_DEPTH_32F, 1 );
Ihi3 = cvCreateImage( sz, IPL_DEPTH_32F, 1 );
cvZero( IavgF );
cvZero( IdiffF );
cvZero( IprevF );
cvZero( IhiF );
cvZero( IlowF );
Icount = 0.00001; //Protección contra la división por cero
Iscratch = cvCreateImage( sz, IPL_DEPTH_32F, 3 );
Iscratch2 = cvCreateImage( sz, IPL_DEPTH_32F, 3 );
Igray1 = cvCreateImage( sz, IPL_DEPTH_32F, 1 );
Igray2 = cvCreateImage( sz, IPL_DEPTH_32F, 1 );
Igray3 = cvCreateImage( sz, IPL_DEPTH_32F, 1 );
Imaskt = cvCreateImage( sz, IPL_DEPTH_8U, 1 );
cvZero( Iscratch );
cvZero( Iscratch2 );
}
Después aprendemos la estadística del fondo para más de una imagen. O sea llamaremos esta función unas cuantas veces. Yo la he llamado unas 500. Al principio del algoritmo, así aprendemos el fondo. En este momento no debe aparecer ningún primer plano.
void accumulateBackground( IplImage *I )
{
static int first = 1; // nb. Not thread safe
cvCvtScale( I, Iscratch, 1, 0 ); // convert to float
if( !first )
{
cvAcc( Iscratch, IavgF );
cvAbsDiff( Iscratch, IprevF, Iscratch2 );
cvAcc( Iscratch2, IdiffF );
Icount += 1.0;
}
first = 0;
cvCopy( Iscratch, IprevF );
}
Una vez que tenemos acumulados unos cuantos frames, creamos nuestro modelo estadístico del fondo de la imagen.{
static int first = 1; // nb. Not thread safe
cvCvtScale( I, Iscratch, 1, 0 ); // convert to float
if( !first )
{
cvAcc( Iscratch, IavgF );
cvAbsDiff( Iscratch, IprevF, Iscratch2 );
cvAcc( Iscratch2, IdiffF );
Icount += 1.0;
}
first = 0;
cvCopy( Iscratch, IprevF );
}
void createModelsfromStats()
{
cvConvertScale( IavgF, IavgF,( double)(1.0/Icount) );
cvConvertScale( IdiffF, IdiffF,(double)(1.0/Icount) );
//Nos aseguramos de que la diferencia siempre es a alguna cosa
cvAddS( IdiffF, cvScalar( 1.0, 1.0, 1.0), IdiffF );
setHighThreshold( 7.0 );
setLowThreshold( 6.0 );
}
{
cvConvertScale( IavgF, IavgF,( double)(1.0/Icount) );
cvConvertScale( IdiffF, IdiffF,(double)(1.0/Icount) );
//Nos aseguramos de que la diferencia siempre es a alguna cosa
cvAddS( IdiffF, cvScalar( 1.0, 1.0, 1.0), IdiffF );
setHighThreshold( 7.0 );
setLowThreshold( 6.0 );
}
A partir de aquí ya podemos ir evaluando frame a frame nuestras imagenes e ir separando el fondo del primer plano. Para esto nos crearemos una máscara, negro fondo y blanco primer plano, y a partir de aquí lo podremos utilizar.
void setHighThreshold( float scale )
{
cvConvertScale( IdiffF, Iscratch, scale );
cvAdd( Iscratch, IavgF, IhiF );
cvSplit( IhiF, Ihi1, Ihi2, Ihi3, 0 );
}
void setLowThreshold( float scale )
{
cvConvertScale( IdiffF, Iscratch, scale );
cvSub( IavgF, Iscratch, IlowF );
cvSplit( IlowF, Ilow1, Ilow2, Ilow3, 0 );
{
cvConvertScale( IdiffF, Iscratch, scale );
cvAdd( Iscratch, IavgF, IhiF );
cvSplit( IhiF, Ihi1, Ihi2, Ihi3, 0 );
}
void setLowThreshold( float scale )
{
cvConvertScale( IdiffF, Iscratch, scale );
cvSub( IavgF, Iscratch, IlowF );
cvSplit( IlowF, Ilow1, Ilow2, Ilow3, 0 );
}
void backgroundDiff(IplImage *I, IplImage *Imask)
{
cvCvtScale(I,Iscratch,1,0); // To float;
cvSplit( Iscratch, Igray1,Igray2,Igray3, 0 );
//Canal 1
//
cvInRange(Igray1,Ilow1,Ihi1,Imask);
//Canal 2
//
cvInRange(Igray2,Ilow2,Ihi2,Imaskt);
cvOr(Imask,Imaskt,Imask);
//Canal 3
//
cvInRange(Igray3,Ilow3,Ihi3,Imaskt);
cvOr(Imask,Imaskt,Imask);
//Invertimos el resultado
//
cvSubRS( Imask, cvScalar(255,255,255), Imask);
}
Al final del todo liberamos la memoria de todas las imágenes.
void DeallocateImages()
{
cvReleaseImage( &IavgF);
cvReleaseImage( &IdiffF );
cvReleaseImage( &IprevF );
cvReleaseImage( &IhiF );
cvReleaseImage( &IlowF );
cvReleaseImage( &Ilow1 );
cvReleaseImage( &Ilow2 );
cvReleaseImage( &Ilow3 );
cvReleaseImage( &Ihi1 );
cvReleaseImage( &Ihi2 );
cvReleaseImage( &Ihi3 );
cvReleaseImage( &Iscratch );
cvReleaseImage( &Iscratch2 );
cvReleaseImage( &Igray1 );
cvReleaseImage( &Igray2 );
cvReleaseImage( &Igray3 );
cvReleaseImage( &Imaskt);
}
{
cvReleaseImage( &IavgF);
cvReleaseImage( &IdiffF );
cvReleaseImage( &IprevF );
cvReleaseImage( &IhiF );
cvReleaseImage( &IlowF );
cvReleaseImage( &Ilow1 );
cvReleaseImage( &Ilow2 );
cvReleaseImage( &Ilow3 );
cvReleaseImage( &Ihi1 );
cvReleaseImage( &Ihi2 );
cvReleaseImage( &Ihi3 );
cvReleaseImage( &Iscratch );
cvReleaseImage( &Iscratch2 );
cvReleaseImage( &Igray1 );
cvReleaseImage( &Igray2 );
cvReleaseImage( &Igray3 );
cvReleaseImage( &Imaskt);
}
Si queréis saber más sobre este método está descrito en el libro Learning OpenCV de Gary Bradski y Adrian Kaehler
Suscribirse a:
Entradas (Atom)