source: foam/trunk/simple-faceident/src/main.cpp @ 76

Revision 76, 11.0 KB checked in by dave, 12 years ago (diff)

changed file format to xml, experimental multiple image/face matching, better makefile

Line 
1// Copyright (C) 2009 foam
2//
3// This program is free software; you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation; either version 2 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with this program; if not, write to the Free Software
15// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16
17// this is a hacked version of the opencv face detection sample code
18
19#include "cv.h"
20#include "highgui.h"
21#include <yarp/os/all.h>
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <assert.h>
27#include <math.h>
28#include <float.h>
29#include <limits.h>
30#include <time.h>
31#include <ctype.h>
32
33#include "FaceBank.h"
34#include "ImageUtils.h"
35#include "SceneState.h"
36
37using namespace std;
38using namespace yarp::os;
39
40#ifdef _EiC
41#define WIN32
42#endif
43
44#ifdef WIN32
45#include <string>
46#define snprintf _snprintf
47#else
48#include <unistd.h>
49#endif
50
51static CvMemStorage* storage = 0;
52static CvHaarClassifierCascade* cascade = 0;
53static CvHaarClassifierCascade* nested_cascade = 0;
54int use_nested_cascade = 0;
55
56void detect_and_draw( IplImage* image );
57
58const char* cascade_name = "haarcascade_frontalface_alt.xml";
59// "/usr/local/share/opencv/haarcascades/haarcascade_frontalface_alt.xml";
60/*    "haarcascade_profileface.xml";*/
61const char* nested_cascade_name = "haarcascade_eye_tree_eyeglasses.xml";
62//"/usr/local/share/opencv/haarcascades/haarcascade_eye_tree_eyeglasses.xml";
63//    "../../data/haarcascades/haarcascade_eye.xml";
64double scale = 1;
65
66//////////////////////////////////////////////////////////
67// These are the tweakable bits - see comments in FaceBank.h
68FaceBank facebank(30, 40, 0.15);
69SceneState scenestate;
70
71// show all faces currently detected
72#define SHOW_FACES
73//#define SAVE_FRAMES
74
75// globals
76bool learn=false;
77bool idle=false;
78int facenum=0;
79int framenum=0;
80
81BufferedPort<Bottle> ctrlport;   
82
83//////////////////////////////////////////////////////////
84
85int main( int argc, char** argv )
86{
87        CvCapture* capture = 0;
88        IplImage *frame, *frame_copy = 0;
89        IplImage *image = 0;
90        const char* scale_opt = "--scale=";
91        int scale_opt_len = (int)strlen(scale_opt);
92        const char* cascade_opt = "--cascade=";
93        int cascade_opt_len = (int)strlen(cascade_opt);
94        const char* nested_cascade_opt = "--nested-cascade";
95        int nested_cascade_opt_len = (int)strlen(nested_cascade_opt);
96        int i;
97        const char* input_name = 0;
98
99        /////////////////////////
100        // yarp bit, would like to move this somewhere else
101
102        ctrlport.open("/faceident-ctrl");     
103
104        /////////////////////////
105
106        for( i = 1; i < argc; i++ )
107        {
108                if( strncmp( argv[i], cascade_opt, cascade_opt_len) == 0 )
109                        cascade_name = argv[i] + cascade_opt_len;
110                else if( strncmp( argv[i], nested_cascade_opt, nested_cascade_opt_len ) == 0 )
111                {
112                        if( argv[i][nested_cascade_opt_len] == '=' )
113                                nested_cascade_name = argv[i] + nested_cascade_opt_len + 1;
114                        nested_cascade = (CvHaarClassifierCascade*)cvLoad( nested_cascade_name, 0, 0, 0 );
115                        if( !nested_cascade )
116                                fprintf( stderr, "WARNING: Could not load classifier cascade for nested objects\n" );
117                }
118                else if( strncmp( argv[i], scale_opt, scale_opt_len ) == 0 )
119                {
120                        if( !sscanf( argv[i] + scale_opt_len, "%lf", &scale ) || scale < 1 )
121                                scale = 1;
122                }
123                else if( argv[i][0] == '-' )
124                {
125                        fprintf( stderr, "WARNING: Unknown option %s\n", argv[i] );
126                }
127                else
128                        input_name = argv[i];
129        }
130
131        cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );
132
133        if( !cascade )
134        {
135                fprintf( stderr, "ERROR: Could not load classifier cascade\n" );
136                fprintf( stderr,
137                        "Usage: facedetect [--cascade=\"<cascade_path>\"]\n"
138                        "   [--nested-cascade[=\"nested_cascade_path\"]]\n"
139                        "   [--scale[=<image scale>\n"
140                        "   [filename|camera_index]\n" );
141                return -1;
142        }
143        storage = cvCreateMemStorage(0);
144
145        if( !input_name || (isdigit(input_name[0]) && input_name[1] == '\0') )
146                capture = cvCaptureFromCAM( !input_name ? 0 : input_name[0] - '0' );
147        else if( input_name )
148        {
149                image = cvLoadImage( input_name, 1 );
150                if( !image )
151                        capture = cvCaptureFromAVI( input_name );
152        }
153        else
154                image = cvLoadImage( "lena.jpg", 1 );
155
156        cvNamedWindow( "result", 1 );
157
158        if( capture )
159        {
160                for(;;)
161                {
162                        if( !cvGrabFrame( capture ))
163                                break;
164                        frame = cvRetrieveFrame( capture );
165                        if( !frame )
166                                break;
167                        if( !frame_copy )
168                                frame_copy = cvCreateImage( cvSize(frame->width,frame->height),
169                                IPL_DEPTH_8U, frame->nChannels );
170                        if( frame->origin == IPL_ORIGIN_TL )
171                                cvCopy( frame, frame_copy, 0 );
172                        else
173                                cvFlip( frame, frame_copy, 0 );
174
175                        detect_and_draw( frame_copy );
176                }
177
178_cleanup_:
179                cvReleaseImage( &frame_copy );
180                cvReleaseCapture( &capture );
181        }
182        else
183        {
184                if( image )
185                {
186                        detect_and_draw( image );
187                        cvReleaseImage( &image );
188                }
189                else if( input_name )
190                {
191                        // assume it is a text file containing the
192                        //   list of the image filenames to be processed - one per line
193                        FILE* f = fopen( input_name, "rt" );
194                        if( f )
195                        {
196                                char buf[1000+1];
197                                while( fgets( buf, 1000, f ) )
198                                {
199                                        int len = (int)strlen(buf), c;
200                                        while( len > 0 && isspace(buf[len-1]) )
201                                                len--;
202                                        buf[len] = '\0';
203                                        printf( "file %s\n", buf );
204                                        image = cvLoadImage( buf, 1 );
205                                        if( image )
206                                        {
207                                                detect_and_draw( image );                       
208                                                cvReleaseImage( &image );
209                                        }
210                                }
211                                fclose(f);
212                        }
213                }
214        }
215
216        cvDestroyWindow("result");
217        return 0;
218}
219
220void detect_and_draw( IplImage* img )
221{
222        static CvScalar colors[] =
223        {
224                {{0,0,255}},
225                {{0,128,255}},
226                {{0,255,255}},
227                {{0,255,0}},
228                {{255,128,0}},
229                {{255,255,0}},
230                {{255,0,0}},
231                {{255,0,255}}
232        };
233
234        IplImage *small_img;
235        int j;
236
237        small_img = cvCreateImage( cvSize( cvRound (img->width/scale),
238                cvRound (img->height/scale)), 8, 3 );
239        CvSize imgsize = cvGetSize(small_img);
240        cvResize( img, small_img, CV_INTER_LINEAR );
241        cvClearMemStorage( storage );
242
243        CvFont font;
244        cvInitFont( &font, CV_FONT_HERSHEY_PLAIN, 2, 2, 0, 1, CV_AA );
245
246        CvFont infofont;
247        cvInitFont( &infofont, CV_FONT_HERSHEY_PLAIN, 1, 1, 0, 1, CV_AA );
248
249        CvFont helpfont;
250        cvInitFont( &helpfont, CV_FONT_HERSHEY_PLAIN, 0.5, 0.5, 0, 1, CV_AA );
251
252        if( cascade )
253        {
254                double t = (double)cvGetTickCount();
255                CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage,
256                        1.1, 2, 0
257                        //|CV_HAAR_FIND_BIGGEST_OBJECT
258                        //|CV_HAAR_DO_ROUGH_SEARCH
259                        //|CV_HAAR_DO_CANNY_PRUNING
260                        //|CV_HAAR_SCALE_IMAGE
261                        ,
262                        cvSize(30, 30) );
263                t = (double)cvGetTickCount() - t;
264                //printf( "detection time = %gms\n", t/((double)cvGetTickFrequency()*1000.) );
265
266                /*framenum++;
267                if (framenum==100)
268                {
269                cerr<<"next face"<<endl;
270                facenum++;
271                }
272
273                if (framenum==220)
274                {
275                cerr<<"stopped learning"<<endl;
276                cerr<<facebank.GetFaceMap().size()<<" faces recorded"<<endl;
277                learn=false; 
278                }*/
279
280                ///////////////////////////////////
281                // dispatch from input
282
283                int key=cvWaitKey(10);
284
285                switch (key)
286                {
287                case 'd': learn=false; break;
288                case '1': facenum=1; learn=true; break;
289                case '2': facenum=2; learn=true; break;
290                case '3': facenum=3; learn=true; break;
291                case '4': facenum=4; learn=true; break;
292                case '5': facenum=5; learn=true; break;
293                case '6': facenum=6; learn=true; break;
294                case '7': facenum=7; learn=true; break;
295                case '8': facenum=8; learn=true; break;
296                case '9': facenum=9; learn=true; break;
297                case '0': facenum=0; learn=true; break;
298                case 'c': facebank.Clear(); break;
299                }
300
301                ///////////////////////////////////
302                // read from yarp
303
304                Bottle *b=ctrlport.read(false);
305                if (b!=NULL)
306                {
307                        if (b->get(0).asString()=="train")
308                        {
309                                facenum=b->get(1).asInt();
310                                learn=true;
311                                idle=false;
312                        }
313                        if (b->get(0).asString()=="idle")
314                        {
315                                facenum=b->get(1).asInt();
316                                idle=true;
317                        }
318                        else if (b->get(0).asString()=="clear")
319                        {
320                                facebank.Clear();
321                        }
322                        else if (b->get(0).asString()=="detect")
323                        {
324                                learn=false;
325                                idle=false;
326                        }
327                        else if (b->get(0).asString()=="load")
328                        {
329                                facebank.Load(b->get(1).asString().c_str());
330                        }
331                        else if (b->get(0).asString()=="save")
332                        {
333                                facebank.Save(b->get(1).asString().c_str());
334                        }
335                        else if (b->get(0).asString()=="multiimage")
336                        {
337                                facebank.AllowMultiFaceImages(b->get(1).asInt());
338                        }
339                }
340
341                ///////////////////////////////////
342
343                if (!idle)
344                {
345                        for(int i = 0; i < (faces ? faces->total : 0); i++ )
346                        {
347                                CvRect* r = (CvRect*)cvGetSeqElem( faces, i );
348                                CvMat small_img_roi;
349
350                                unsigned int ID=999;
351                                int imagenum=-1;
352                                float confidence=0;
353                                // get the face area as a sub image
354                                IplImage *face = SubImage(small_img, *r);
355                                // pass it into the face bank
356                                if (learn)
357                                {
358                                        confidence=facebank.Suggest(face,facenum);
359                                        ID=facenum;
360                                }
361                                else
362                                {       
363                                        confidence=facebank.Identify(face,ID,imagenum);
364                                }
365
366                                cvReleaseImage(&face);
367                                CvScalar color = colors[ID%8];
368
369                                // if it's recognised the face (should really check the confidence)
370                                if (ID!=999)
371                                {
372                                        char s[32];
373                                        sprintf(s,"%d %0.2f",ID,confidence);
374                                        cvPutText(small_img, s, cvPoint(r->x,r->y+25), &font, color);
375                                        int x=(facebank.GetFaceWidth()+1)*ID;
376                                        int y=imgsize.height-facebank.GetFaceHeight();
377                                        y-=(facebank.GetFaceHeight()+2)*imagenum;
378                                        cvLine(small_img, cvPoint(r->x+r->width/2,r->y+r->height/2),
379                                                cvPoint(x+facebank.GetFaceWidth()/2,y), color);                 
380
381                                        if (!learn)
382                                        {
383                                                scenestate.AddPresent(ID, SceneState::User(confidence));
384                                        }
385                                }
386
387                                cvRectangle(small_img, cvPoint(r->x,r->y), cvPoint(r->x+r->width,r->y+r->height), color);
388                        }
389                }
390                else
391                {
392                        // idling, so free up some cpu
393                #ifdef WIN32
394                        Sleep(2000);
395                #else
396                        usleep(200000);
397                #endif
398                }
399        }
400
401        scenestate.Update();
402
403        char info[256];
404        if (learn)
405        {
406                snprintf(info,256,"learning user %d",facenum);
407        }
408        else
409        {
410                snprintf(info,256,"detecting faces");
411        }
412        cvPutText(small_img, info, cvPoint(20,30), &infofont, CV_RGB(0,0,0));
413
414        snprintf(info,256,"keys:");
415        cvPutText(small_img, info, cvPoint(20,50), &helpfont, CV_RGB(0,0,0));
416        snprintf(info,256,"number key 0-9 : learn face");
417        cvPutText(small_img, info, cvPoint(20,60), &helpfont, CV_RGB(0,0,0));
418        snprintf(info,256,"'d' : face detect mode");
419        cvPutText(small_img, info, cvPoint(20,70), &helpfont, CV_RGB(0,0,0));
420        snprintf(info,256,"'c' : clear all faces");
421        cvPutText(small_img, info, cvPoint(20,80), &helpfont, CV_RGB(0,0,0));
422
423#ifdef SHOW_FACES
424        for(map<unsigned int,Face*>::iterator ii=facebank.GetFaceMap().begin();
425                ii!=facebank.GetFaceMap().end(); ++ii)
426        {
427                int x=(facebank.GetFaceWidth()+1)*ii->first;
428                int y=imgsize.height-facebank.GetFaceHeight();
429                for(vector<IplImage *>::iterator im=ii->second->m_ImageVec.begin();
430                        im!=ii->second->m_ImageVec.end(); im++)
431                {
432                        BlitImage(*im,small_img,cvPoint(x,y));
433                        y-=facebank.GetFaceHeight()+2;
434                }
435        }
436#endif
437
438        cvShowImage( "result", small_img );
439
440#ifdef SAVE_FRAMES
441        char name[256];
442        sprintf(name,"out-%0.4d.jpg",framenum);
443        cvSaveImage(name,small_img);
444#endif
445
446        cvReleaseImage( &small_img );
447}
Note: See TracBrowser for help on using the repository browser.