Muy buenas, ya tenemos una solución al reto de contar caras. Para esta solución me he modificado la estructura,y en vez de utilizar listas he utilizado un vector. La estructura es la siguiente:
struct Rostro {
bool HayCara; // Número total de elementos
centro Pcentral;
IplImage* Cara; //Aqui guardamos la cara
bool HayConincidencia;
int ContadorCoincidencia;
int ContadorNoCoincidencia;
};
Esta estructura contiene las siguientes variables hay cara, para saber si hay cara en esa posición del vector o no, Pcentral para conocer el punto central de la cara, Cara es la imagen de la cara, realmente esta para contar caras no lo necesitamos, pero por si en un futuro queremos visualizarla. HayCoincidencia es una variable que me dice si anteriormente ha estado esta cara, en base a su posición. Contador de NoCoincidencia es por si no está, y antes si. Esto es por si nos pierde la imagen por lo que sea que no se olvide de esa cara.
Pcentral es una variable de tipo centro. Este tipo lo he definido así:
struct centro{
int x;
int y;
};
Principalmente en el algoritmo lo que hacemos es lo siguiente.
- Comparamos la distancia entre la imagen anterior y la imagen actual, si es menor a un determinado valor suponemos que es la misma.
- Si es la misma contamos una coincidencia.
- Sin no es la misma contamos una no coincidencia
- Si hay un numero de veces coincidencia es una cara que nos interesa.
- Si ha pasado varias veces y no hay coincidencia suponemos que se ha ido la cara.
El algoritmo en lenguaje C es el siguiente:
for( l = 0; l < 10; l++ )
{
//Comprobamos si hay coincidencia, si hay coincidencia y esta se ha repetido una serie de veces contamos cara
for( m = 0; m < 10 ; m++ )
{
if ((ListaRostros[l].HayCara==true)&& (ListaRostrosAnterior[m].HayCara==true))
{
if(((((ListaRostros[l].Pcentral.x-ListaRostrosAnterior[m].Pcentral.x)^2+(ListaRostros[l].Pcentral.y-ListaRostrosAnterior[m].Pcentral.y)^2)^(1/2))<750)&& !ListaRostros[l].HayConincidencia&& !ListaRostrosAnterior[m].HayConincidencia)
{
ListaRostros[l].HayConincidencia=true;
ListaRostrosAnterior[m].HayConincidencia=true;
ListaRostros[l].ContadorCoincidencia=ListaRostrosAnterior[m].ContadorCoincidencia+1;
if (ListaRostros[l].ContadorCoincidencia==5)
{
NumeroCaras++;
}
}
}
}
//Si no hay coincidencia contamos
if (!ListaRostros[l].HayConincidencia)
{
ListaRostros[l].ContadorCoincidencia=0;
ListaRostros[l].ContadorNoCoincidencia++;
}
}
//Si no hay coincidencia y esta es menor de 3 entonces guardamos la imagen
for( m = 0; m < 10; m++ )
{
if (!ListaRostrosAnterior[m].HayConincidencia)
{
ListaRostrosAnterior[m].ContadorNoCoincidencia++;
ListaRostrosAnterior[m].ContadorCoincidencia=0;
if (ListaRostrosAnterior[m].ContadorNoCoincidencia<3)
{
l=0;
while ((ListaRostros[l].HayCara)&& l<10) l++;
if (l<10) ListaRostros[l]=ListaRostrosAnterior[m];
}
}
}
//Copiamos la imagen en imagen anterior
for( i = 0; i < 10; i++ )
{
ListaRostrosAnterior[i]=ListaRostros[i];
}
{
//Comprobamos si hay coincidencia, si hay coincidencia y esta se ha repetido una serie de veces contamos cara
for( m = 0; m < 10 ; m++ )
{
if ((ListaRostros[l].HayCara==true)&& (ListaRostrosAnterior[m].HayCara==true))
{
if(((((ListaRostros[l].Pcentral.x-ListaRostrosAnterior[m].Pcentral.x)^2+(ListaRostros[l].Pcentral.y-ListaRostrosAnterior[m].Pcentral.y)^2)^(1/2))<750)&& !ListaRostros[l].HayConincidencia&& !ListaRostrosAnterior[m].HayConincidencia)
{
ListaRostros[l].HayConincidencia=true;
ListaRostrosAnterior[m].HayConincidencia=true;
ListaRostros[l].ContadorCoincidencia=ListaRostrosAnterior[m].ContadorCoincidencia+1;
if (ListaRostros[l].ContadorCoincidencia==5)
{
NumeroCaras++;
}
}
}
}
//Si no hay coincidencia contamos
if (!ListaRostros[l].HayConincidencia)
{
ListaRostros[l].ContadorCoincidencia=0;
ListaRostros[l].ContadorNoCoincidencia++;
}
}
//Si no hay coincidencia y esta es menor de 3 entonces guardamos la imagen
for( m = 0; m < 10; m++ )
{
if (!ListaRostrosAnterior[m].HayConincidencia)
{
ListaRostrosAnterior[m].ContadorNoCoincidencia++;
ListaRostrosAnterior[m].ContadorCoincidencia=0;
if (ListaRostrosAnterior[m].ContadorNoCoincidencia<3)
{
l=0;
while ((ListaRostros[l].HayCara)&& l<10) l++;
if (l<10) ListaRostros[l]=ListaRostrosAnterior[m];
}
}
}
//Copiamos la imagen en imagen anterior
for( i = 0; i < 10; i++ )
{
ListaRostrosAnterior[i]=ListaRostros[i];
}
Los resultados de este algoritmo no los he evaluado todavía, tasas de acierto y de fallo. Parece que funciona bastante bien, aunque habría que mejorarlo, sobre todo en los falsos positivos, a veces me reconoce caras donde no las hay, para esto miraremos algoritmos que nos quitan el fondo con openCV. También comentar que el algoritmo es parametrizable, podemos cambiar la distancia para comprobar si es la misma cara, y el numero de veces que cuenta coincidencia y el numero de veces que no.
Pongo un vídeo
En le vídeo podemos ver, que reconoce una vez y me cuenta una sola vez. También se ve la aparición de falsos positivos, esto nos puede fastidiar un poco la cuenta, hay que ver como los eliminamos, probaremos, eliminando el fondo. Además luego desaparezco de la imagen y vuelvo, como me he ido y el vuelto pues me cuenta otra vez.