Ignore:
Timestamp:
04/23/2009 05:05:31 PM (12 years ago)
Author:
dave
Message:

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • foam/trunk/simple-faceident/src/FaceBank.cpp

    r64 r76  
    1818#include "ImageUtils.h" 
    1919#include "highgui.h" 
     20#include "tinyxml.h" 
    2021 
    2122#include <vector> 
     
    2930 
    3031///////////////////////////////////////////////////////////////////////////////// 
    31 // util for loading 
    32  
    33 int SplitString(const string& input, const string& delimiter, vector<string>& results, bool includeEmpties) 
    34 { 
    35     int iPos = 0; 
    36     int newPos = -1; 
    37     int sizeS2 = (int)delimiter.size(); 
    38     int isize = (int)input.size(); 
    39  
    40     if(isize == 0 || sizeS2 == 0) 
    41     { 
    42         return 0; 
    43     } 
    44  
    45     vector<int> positions; 
    46     newPos = input.find (delimiter, 0); 
    47  
    48     if( newPos < 0 ) return 0;  
    49  
    50     int numFound = 0; 
    51  
    52     while( newPos >= iPos ) 
    53     { 
    54         numFound++; 
    55         positions.push_back(newPos); 
    56         iPos = newPos; 
    57         newPos = input.find (delimiter, iPos+sizeS2); 
    58     } 
    59  
    60     if( numFound == 0 ) return 0; 
    61  
    62     for( int i=0; i <= (int)positions.size(); ++i ) 
    63     { 
    64         string s(""); 
    65         if( i == 0 )  
    66         {  
    67             s = input.substr( i, positions[i] );  
    68         } 
    69                 else 
    70                 { 
    71                 int offset = positions[i-1] + sizeS2; 
    72                 if( offset < isize ) 
    73                 { 
    74                     if( i == (int)positions.size() ) 
    75                     { 
    76                         s = input.substr(offset); 
    77                     } 
    78                     else if( i > 0 ) 
    79                     { 
    80                         s = input.substr( positions[i-1] + sizeS2,  
    81                               positions[i] - positions[i-1] - sizeS2 ); 
    82                     } 
    83                 } 
    84                 } 
    85                  
    86         if( includeEmpties || ( s.size() > 0 ) ) 
    87         { 
    88             results.push_back(s); 
    89         } 
    90     } 
    91     return numFound; 
    92 } 
    93  
    94 ///////////////////////////////////////////////////////////////////////////////// 
    95  
    96 Face::Face(IplImage *image) :  
    97 m_Image(image)  
    98 { 
    99 } 
    100  
    101 Face::~Face()  
    102 { 
    103         cvReleaseImage(&m_Image); 
    104 } 
    105  
    106 void Face::Learn(const IplImage *image, float blend) 
    107 { 
    108         CvSize sizea = cvGetSize(image); 
    109         CvSize sizeb = cvGetSize(m_Image); 
    110  
    111         assert(sizea.width == sizeb.width); 
    112         assert(sizea.height == sizeb.height); 
    113  
    114         float ret=0; 
    115  
    116     for(int y=0; y<sizea.height; y++) 
    117         { 
    118         for(int x=0; x<sizea.width; x++) 
    119                 { 
    120                         cvSet2D(m_Image,y,x,cvScalar( 
    121                                                 cvGet2D(m_Image,y,x).val[0]*(1 - blend) + cvGet2D(image,y,x).val[0]*blend, 
    122                                                 cvGet2D(m_Image,y,x).val[1]*(1 - blend) + cvGet2D(image,y,x).val[1]*blend, 
    123                                                 cvGet2D(m_Image,y,x).val[2]*(1 - blend) + cvGet2D(image,y,x).val[2]*blend)); 
    124                 } 
    125         } 
    126 } 
    127  
    128 ///////////////////////////////////////////////////////////////////////////////// 
    12932         
    13033FaceBank::FaceBank(unsigned int FaceWidth, unsigned int FaceHeight, float ErrorThresh) :  
    13134m_FaceWidth(FaceWidth), 
    13235m_FaceHeight(FaceHeight), 
    133 m_ErrorThresh(ErrorThresh) 
     36m_ErrorThresh(ErrorThresh), 
     37m_MultiFaceImages(false) 
    13438{ 
    13539} 
     
    14751        } 
    14852        m_FaceMap.clear(); 
    149 } 
    150  
    151 void FaceBank::Save(const std::string &filename) const 
    152 { 
    153         char fn[256]; 
    154         snprintf(fn,256,"%s.dat",filename.c_str()); 
    155         FILE *f=fopen(fn,"w"); 
    156          
    157         if (f==NULL) 
    158         { 
    159                 cerr<<"could not open file for saving: "<<filename<<endl; 
    160                 return; 
    161         } 
    162  
    163         char header[1024]; 
    164         snprintf(header,1024,"%d\n%d\n",0,m_FaceMap.size()); 
    165         fwrite(header,strlen(header),1,f); 
    166          
    167         for(map<unsigned int,Face*>::const_iterator i=m_FaceMap.begin(); i!=m_FaceMap.end(); ++i) 
    168         { 
    169                 char fn[256]; 
    170                 snprintf(fn,256,"%d\n%s-%d.png\n",i->first,filename.c_str(),i->first); 
    171                 fwrite(fn,strlen(fn),1,f); 
    172         } 
    173         fclose(f); 
    174          
    175         for(map<unsigned int,Face*>::const_iterator i=m_FaceMap.begin(); i!=m_FaceMap.end(); ++i) 
    176         { 
    177                 char fn[256]; 
    178                 snprintf(fn,256,"%s-%d.png",filename.c_str(),i->first); 
    179                 cvSaveImage(fn,i->second->m_Image); 
    180         } 
    181 } 
    182  
    183 void FaceBank::Load(const std::string &filename) 
    184 { 
    185         Clear(); 
    186  
    187         char fn[256]; 
    188         snprintf(fn,256,"%s.dat",filename.c_str()); 
    189         FILE *f=fopen(fn,"r"); 
    190          
    191         if (f==NULL) 
    192         { 
    193                 cerr<<"file not found: "<<filename<<endl; 
    194                 return; 
    195         } 
    196          
    197         fseek(f,0,SEEK_END); 
    198         unsigned int size=ftell(f); 
    199         fseek(f,0,SEEK_SET); 
    200          
    201         if (size==0) 
    202         { 
    203                 fclose(f); 
    204                 cerr<<"empty file: "<<filename<<endl; 
    205                 return; 
    206         } 
    207  
    208         if (size<0) 
    209         { 
    210                 fclose(f); 
    211                 cerr<<"error loading file: "<<filename<<" size: "<<size<<"??"<<endl; 
    212                 return; 
    213         } 
    214  
    215         char *data=new char[size+1];             
    216         fread(data,1,size,f); 
    217         data[size]='\0'; 
    218         fclose(f); 
    219          
    220         vector<string> items; 
    221         SplitString(data,"\n",items,true); 
    222  
    223         if (items.size()>3) 
    224         { 
    225                 int version=(int)atoi(items[0].c_str()); 
    226                 int count=(int)atoi(items[1].c_str()); 
    227                 for (int i=2; i<count*2+2; i+=2) 
    228                 { 
    229                         int ID=(int)atoi(items[i].c_str()); 
    230                         m_FaceMap[ID]=new Face(cvLoadImage(items[i+1].c_str())); 
    231                 } 
    232         } 
    23353} 
    23454 
     
    24868                // Check it doesn't look like any we have already recorded 
    24969                unsigned int checkid=0; 
    250                 if (Identify(faceresized,checkid)>0) 
    251                 { 
    252                         cerr<<"We've already seen this face: "<<checkid<<endl;   
     70                int imagenum=-1; 
     71                if (Identify(faceresized,checkid,imagenum)>0) 
     72                { 
     73                        cerr<<"We've already seen this face: "<<checkid<<":"<<imagenum<<endl;    
    25374                        return 0; 
    25475                } 
     
    26081         
    26182        // Does this face look like the one we already have for this id? 
    262         float error = Diff(faceresized,i->second->m_Image); 
     83        int facenum; 
     84        float error = i->second->FindSimilar(faceresized,facenum); 
    26385 
    26486        if (error<m_ErrorThresh)  
    26587        { 
    266                 cerr<<"adding to face "<<ID<<endl; 
     88                //cerr<<"adding to face:"<<ID<<" image:"<<facenum<<endl; 
    26789                // Blend this face into the one we have already 
    268                 i->second->Learn(faceresized,0.2); 
     90                i->second->Learn(faceresized,0.2,facenum); 
    26991                cvReleaseImage(&faceresized); 
    27092                ID=i->first; 
     
    27294        } 
    27395         
    274         cerr<<"false positive? "<<error<<" "<<ID<<endl; 
     96        if (m_MultiFaceImages) 
     97        {        
     98                // Does it look like any we have already recorded for any face? 
     99                unsigned int checkid=0; 
     100                int imagenum=-1; 
     101                if (Identify(faceresized,checkid,imagenum)>0) 
     102                { 
     103                        cerr<<"We've already seen this face: "<<checkid<<":"<<imagenum<<endl;    
     104                        return 0; 
     105                }        
     106                 
     107                cerr<<"too different - adding new image to face "<<error<<" "<<ID<<endl; 
     108                i->second->AddImage(faceresized); 
     109        } 
    275110         
    276111        return 0; 
    277112} 
    278113 
    279 float FaceBank::Identify(IplImage *face, unsigned int &ID) 
     114float FaceBank::Identify(IplImage *face, unsigned int &ID, int &imagenum) 
    280115{ 
    281116        IplImage *faceresized = cvCreateImage(cvSize(m_FaceWidth,m_FaceHeight),IPL_DEPTH_8U, face->nChannels); 
     
    293128        unsigned int best=0; 
    294129        Face* bestface=NULL; 
     130        imagenum=-1; 
    295131         
    296132        // look for the lowest error in the map of faces 
    297133        for(map<unsigned int,Face*>::iterator i=m_FaceMap.begin(); i!=m_FaceMap.end(); ++i) 
    298134        { 
    299                 float tmp = Diff(faceresized,i->second->m_Image); 
     135                int similarfacenum; 
     136                float tmp = i->second->FindSimilar(faceresized,similarfacenum); 
    300137                if (tmp<error) 
    301138                { 
     
    303140                        best=i->first; 
    304141                        bestface=i->second; 
     142                        imagenum=similarfacenum; 
    305143                } 
    306144        } 
     
    310148        { 
    311149                // blend this face into the one we have already 
    312                 bestface->Learn(faceresized,0); 
     150                bestface->Learn(faceresized,0,imagenum); 
    313151                cvReleaseImage(&faceresized); 
    314152                ID=best; 
     
    320158        return 0; 
    321159} 
     160 
     161void FaceBank::Save(const std::string &filename) const 
     162{ 
     163        char fn[256]; 
     164        snprintf(fn,256,"%s.xml",filename.c_str()); 
     165        FILE *f=fopen(fn,"w"); 
     166         
     167        if (f==NULL) 
     168        { 
     169                cerr<<"could not open file for saving: "<<filename<<endl; 
     170                return; 
     171        } 
     172         
     173        TiXmlElement facebank("facebank"); 
     174        facebank.SetAttribute("version", 1); 
     175 
     176        for(map<unsigned int,Face*>::const_iterator i=m_FaceMap.begin(); i!=m_FaceMap.end(); ++i) 
     177        { 
     178                TiXmlElement face("face"); 
     179                face.SetAttribute("id", i->first); 
     180                int imagenum=0; 
     181                 
     182                for(vector<IplImage *>::iterator im=i->second->m_ImageVec.begin(); 
     183                        im!=i->second->m_ImageVec.end(); im++) 
     184                { 
     185                        TiXmlElement image("image"); 
     186                        char fn[256]; 
     187                        snprintf(fn,256,"%s-id%04d-image%04d.png",filename.c_str(),i->first,imagenum); 
     188                         
     189                        cvSaveImage(fn,*im); 
     190                         
     191                        image.SetAttribute("filename", fn); 
     192                        face.InsertEndChild(image); 
     193                        imagenum++; 
     194                } 
     195                 
     196                facebank.InsertEndChild(face); 
     197        } 
     198 
     199        facebank.Print(f,0); 
     200        fclose(f); 
     201} 
     202 
     203void FaceBank::Load(const std::string &filename) 
     204{ 
     205        Clear(); 
     206        char fn[256]; 
     207        snprintf(fn,256,"%s.xml",filename.c_str()); 
     208         
     209        TiXmlDocument doc(fn); 
     210        if (!doc.LoadFile()) 
     211        { 
     212                cerr<<"could not load "<<fn<<" error:"<<doc.ErrorDesc()<<endl; 
     213                return; 
     214        } 
     215         
     216        TiXmlNode* root = doc.FirstChild("facebank"); 
     217        if(root!=NULL) 
     218        { 
     219                // loop over faces 
     220                TiXmlNode* face = root->FirstChild(); 
     221                while(face!=NULL) 
     222                {        
     223                        TiXmlElement* faceelem = face->ToElement(); 
     224                        if(faceelem) 
     225                        { 
     226                                unsigned int ID = atoi(faceelem->Attribute("id")); 
     227                                int count=0; 
     228                                // loop over images 
     229                                TiXmlNode* image = face->FirstChild(); 
     230                                while(image!=NULL) 
     231                                { 
     232                                        TiXmlElement* imageelem = image->ToElement(); 
     233                                        if(imageelem) 
     234                                        { 
     235                                                string filename=imageelem->Attribute("filename"); 
     236                                                if(count==0) m_FaceMap[ID]=new Face(cvLoadImage(filename.c_str())); 
     237                                                else m_FaceMap[ID]->AddImage(cvLoadImage(filename.c_str())); 
     238                                                count++; 
     239                                                image = image->NextSibling(); 
     240                                        } 
     241                                } 
     242                                face = face->NextSibling(); 
     243                        } 
     244                } 
     245        } 
     246        else 
     247        { 
     248                cerr<<"error parsing xml in "<<fn<<endl; 
     249        } 
     250} 
Note: See TracChangeset for help on using the changeset viewer.