typedef struct _Rostro {
struct _Rostro* Anterior; // secuencia previa
struct _Rostro* Siguiente; // secuencia siguiente
struct _Rostro* Primero; //Primer elemento de la lista
int Nodo;
int total; // Número total de elementos
IplImage* Cara; //Aqui guardamos la cara
}Rostro;
typedef Rostro *pRostro;
typedef Rostro *Rostros;
struct _Rostro* Anterior; // secuencia previa
struct _Rostro* Siguiente; // secuencia siguiente
struct _Rostro* Primero; //Primer elemento de la lista
int Nodo;
int total; // Número total de elementos
IplImage* Cara; //Aqui guardamos la cara
}Rostro;
typedef Rostro *pRostro;
typedef Rostro *Rostros;
Podemos ver que nuestra intención es realizar una lista con las caras, para he definido una serie de funciones para tratar esta lista.
int ListaVacia(Rostros R);
void Insertar(Rostros *R, IplImage* Cara);
IplImage* MostrarRostro(Rostros *R,int nodo);
Con estas funciones controlaremos la lista.
El código fuente de estas funciones será el siguiente.
int ListaVacia(Rostros R) {
return (R == NULL);
}
void Insertar(Rostros *R, IplImage* Cara){
pRostro nuevo, anterior;
/* Crear un nodo nuevo */
nuevo = (pRostro)malloc(sizeof(Rostro));
nuevo->Cara= Cara;
if (ListaVacia(*R)){
*R=nuevo;
(*R)->Siguiente=NULL;
(*R)->Anterior=NULL;
(*R)->Cara=Cara;
(*R)->Nodo=0;
(*R)->total=1;
(*R)->Primero=*R;
}
else
{
anterior=(*R)->Primero;
while (anterior->Siguiente!=NULL){
anterior->total++;
anterior=anterior->Siguiente;
}
anterior->total++;
anterior->Siguiente=nuevo;
nuevo->Anterior=anterior;
nuevo->Siguiente=NULL;
nuevo->Nodo=anterior->Nodo+1;
nuevo->total=anterior->total;
nuevo->Cara=Cara;
}
}
IplImage* MostrarRostro(Rostros *R,int nodo){
pRostro Caras = *R;
if(ListaVacia(*R)) {
printf("ERROR: Lista Vacia\n");
return NULL;
}
else {
while(Caras->Nodo<nodo) {
Caras = Caras->Siguiente;
}
return Caras->Cara;
}
}
return (R == NULL);
}
void Insertar(Rostros *R, IplImage* Cara){
pRostro nuevo, anterior;
/* Crear un nodo nuevo */
nuevo = (pRostro)malloc(sizeof(Rostro));
nuevo->Cara= Cara;
if (ListaVacia(*R)){
*R=nuevo;
(*R)->Siguiente=NULL;
(*R)->Anterior=NULL;
(*R)->Cara=Cara;
(*R)->Nodo=0;
(*R)->total=1;
(*R)->Primero=*R;
}
else
{
anterior=(*R)->Primero;
while (anterior->Siguiente!=NULL){
anterior->total++;
anterior=anterior->Siguiente;
}
anterior->total++;
anterior->Siguiente=nuevo;
nuevo->Anterior=anterior;
nuevo->Siguiente=NULL;
nuevo->Nodo=anterior->Nodo+1;
nuevo->total=anterior->total;
nuevo->Cara=Cara;
}
}
IplImage* MostrarRostro(Rostros *R,int nodo){
pRostro Caras = *R;
if(ListaVacia(*R)) {
printf("ERROR: Lista Vacia\n");
return NULL;
}
else {
while(Caras->Nodo<nodo) {
Caras = Caras->Siguiente;
}
return Caras->Cara;
}
}
Bueno pero, como separamos nuestra cara de la imagen. Para esto utilizaremos las siguientes funciones de OpenCV:
cvSetImageROI(IplImage*,CvSeq);
cvCopy(IplImage* src,IplImage* des,NULL);
cvResetImageROI(IplImage*);
cvResetImageROI(IplImage*);
Todo lo demás es exactamente igual al reto anterior.
El código fuente lo dejo aquí.
#include "cv.h"
#include "highgui.h"
#include <iostream>
#include <cstdio>
#include <string>
#include "Funciones.h"
#include "Estructuras.h"
using namespace std;
void main()
{
static CvScalar colores[] = {
{{0,0,255}}, {{0,128,255}},{{0,255,255}},{{0,255,0}},
{{255,128,0}},{{255,255,0}},{{255,0,0}}, {{255,0,255}}};//Colores para dibujar
double t;
bool Primera= true;
CvHaarClassifierCascade* cascade = (CvHaarClassifierCascade*)cvLoad( "haarcascade_frontalface_alt.xml",0, 0, 0 );
CvMemStorage* storage = cvCreateMemStorage(0);
//Creamos la ventana
cvNamedWindow( "Imagen", CV_WINDOW_AUTOSIZE );
//Capturamos la cámara
CvCapture* capture= cvCreateCameraCapture(0);
assert( capture != NULL );
IplImage* Frame;
IplImage* gris;
IplImage* RostroDetectado;
Rostros ListaRostros=NULL;
CvSeq* objects;
int i,j,k,l;
string nombreVentana;
cvSetCaptureProperty(capture,CV_CAP_PROP_FRAME_WIDTH,300);
cvSetCaptureProperty(capture,CV_CAP_PROP_FRAME_HEIGHT,300);
Frame=cvQueryFrame(capture); //Capturamos la primera imagen
if(Frame) //Si hay frame
{
gris = cvCreateImage( cvSize(Frame->width,Frame->height), 8, 1 );
while(1)
{
//Preparación de la imagen
cvCvtColor( Frame, gris, CV_BGR2GRAY );
//Capturamos el tiempo inicial
t = (double)cvGetTickCount();
objects= Deteccion_y_dibujo(gris, cascade, storage); //Aqui ya no me rellena el objects la segunda vez
//Capturamos el tiempo final y le restamos el inicial
t = (double)cvGetTickCount() - t;
//Dibujamos cuadros al rededor de los objetos
//Con lo cual este for no me lo hace
for( i = 0; i < (objects ? objects->total : 0); i++ ) {
CvRect* r = (CvRect*)cvGetSeqElem( objects, i );
cvRectangle(
Frame,
cvPoint(r->x,r->y),
cvPoint(r->x+r->width,r->y+r->height),
colores[i%8],
2
);
RostroDetectado = cvCreateImage(cvSize(r->width, r->height), gris->depth, gris->nChannels);
cvSetImageROI(gris,*r);
cvCopy(gris,RostroDetectado,NULL);
cvResetImageROI(gris);
Insertar(&ListaRostros, RostroDetectado);
}
//Visualizamos el tiempo
printf( "Tiempo deteccion = %g ms\n",t/((double) cvGetTickFrequency() *1000.) );
//Dibujamos la imagen
cvShowImage( "Imagen", Frame);
for( l = 0; l < (ListaRostros ? ListaRostros->total : 0); l++ )
{
nombreVentana="Imagen";
j=l;
do
{
k=j%10;
nombreVentana+=(char)(k+48);
j=j/10;
}
while (j/10!=0);
cvNamedWindow(nombreVentana.data(), CV_WINDOW_AUTOSIZE );
cvShowImage( nombreVentana.data(), MostrarRostro(&ListaRostros,l));
}
char c = cvWaitKey
if(c==27) break;
BorrarLista(&ListaRostros);
Frame=cvQueryFrame(capture); //Capturamos el resto de las imagenes
}
cvReleaseImage( &gris );
}
cvReleaseImage(&Frame);
CvSeq* Deteccion_y_dibujo( IplImage* gris,CvHaarClassifierCascade* cascade,CvMemStorage* storage )
{
CvSeq* objects;
cvEqualizeHist( gris, gris );
//Detección si las hay
cvClearMemStorage( storage );
objects = cvHaarDetectObjects(
gris,
cascade,
storage,
1.1,
2,
0 /*CV_HAAR_DO_CANNY_PRUNING*/,
cvSize(30, 30));
return objects;
}
#include "highgui.h"
#include <iostream>
#include <cstdio>
#include <string>
#include "Funciones.h"
#include "Estructuras.h"
using namespace std;
void main()
{
static CvScalar colores[] = {
{{0,0,255}}, {{0,128,255}},{{0,255,255}},{{0,255,0}},
{{255,128,0}},{{255,255,0}},{{255,0,0}}, {{255,0,255}}};//Colores para dibujar
double t;
bool Primera= true;
CvHaarClassifierCascade* cascade = (CvHaarClassifierCascade*)cvLoad( "haarcascade_frontalface_alt.xml",0, 0, 0 );
CvMemStorage* storage = cvCreateMemStorage(0);
//Creamos la ventana
cvNamedWindow( "Imagen", CV_WINDOW_AUTOSIZE );
//Capturamos la cámara
CvCapture* capture= cvCreateCameraCapture(0);
assert( capture != NULL );
IplImage* Frame;
IplImage* gris;
IplImage* RostroDetectado;
Rostros ListaRostros=NULL;
CvSeq* objects;
int i,j,k,l;
string nombreVentana;
cvSetCaptureProperty(capture,CV_CAP_PROP_FRAME_WIDTH,300);
cvSetCaptureProperty(capture,CV_CAP_PROP_FRAME_HEIGHT,300);
Frame=cvQueryFrame(capture); //Capturamos la primera imagen
if(Frame) //Si hay frame
{
gris = cvCreateImage( cvSize(Frame->width,Frame->height), 8, 1 );
while(1)
{
//Preparación de la imagen
cvCvtColor( Frame, gris, CV_BGR2GRAY );
//Capturamos el tiempo inicial
t = (double)cvGetTickCount();
objects= Deteccion_y_dibujo(gris, cascade, storage); //Aqui ya no me rellena el objects la segunda vez
//Capturamos el tiempo final y le restamos el inicial
t = (double)cvGetTickCount() - t;
//Dibujamos cuadros al rededor de los objetos
//Con lo cual este for no me lo hace
for( i = 0; i < (objects ? objects->total : 0); i++ ) {
CvRect* r = (CvRect*)cvGetSeqElem( objects, i );
cvRectangle(
Frame,
cvPoint(r->x,r->y),
cvPoint(r->x+r->width,r->y+r->height),
colores[i%8],
2
);
RostroDetectado = cvCreateImage(cvSize(r->width, r->height), gris->depth, gris->nChannels);
cvSetImageROI(gris,*r);
cvCopy(gris,RostroDetectado,NULL);
cvResetImageROI(gris);
Insertar(&ListaRostros, RostroDetectado);
}
//Visualizamos el tiempo
printf( "Tiempo deteccion = %g ms\n",t/((double) cvGetTickFrequency() *1000.) );
//Dibujamos la imagen
cvShowImage( "Imagen", Frame);
for( l = 0; l < (ListaRostros ? ListaRostros->total : 0); l++ )
{
nombreVentana="Imagen";
j=l;
do
{
k=j%10;
nombreVentana+=(char)(k+48);
j=j/10;
}
while (j/10!=0);
cvNamedWindow(nombreVentana.data(), CV_WINDOW_AUTOSIZE );
cvShowImage( nombreVentana.data(), MostrarRostro(&ListaRostros,l));
}
char c = cvWaitKey
if(c==27) break;
BorrarLista(&ListaRostros);
Frame=cvQueryFrame(capture); //Capturamos el resto de las imagenes
}
cvReleaseImage( &gris );
}
cvReleaseImage(&Frame);
CvSeq* Deteccion_y_dibujo( IplImage* gris,CvHaarClassifierCascade* cascade,CvMemStorage* storage )
{
CvSeq* objects;
cvEqualizeHist( gris, gris );
//Detección si las hay
cvClearMemStorage( storage );
objects = cvHaarDetectObjects(
gris,
cascade,
storage,
1.1,
2,
0 /*CV_HAAR_DO_CANNY_PRUNING*/,
cvSize(30, 30));
return objects;
}
En este código se puede ver el empleo de la función
cvSetCaptureProperty(capture,CV_CAP_PROP_FRAME_WIDTH,300); la cual uso para cambiar el ancho del frame, y la función.
cvSetCaptureProperty(capture,CV_CAP_PROP_FRAME_HEIGHT,300); la cual utilizo para cambiar el alto, del frame.
Así de esta forma puedo llegar a un compromiso entre reconocimiento y velocidad de procesado.
Bueno como siempre si alguien tiene una solución mejor que la proponga, así aprendemos todos.
Hola. soy el Juan Carlos de la bici. La verdad es que tienen buena pinta los artículos el problema es que yo programo un poquito en ASM y tardaré un poco en aprender C pero así tendré un aliciente para estudiar.
ResponderEliminarMuy buenas Juan Carlos, eso está bien siempre es bueno tener alicientes para aprender. Y no te preocupes tengo en mente hacer algo que algun PIC algun dia, en esa nos podras enseñar.
ResponderEliminar