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

Revision 62, 11.8 KB checked in by dave, 11 years ago (diff)

added idle mode

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