source: foam/trunk/simple-faceident/src/FaceBank.cpp @ 14

Revision 14, 4.1 KB checked in by dave, 11 years ago (diff)

Proper calibration system, better user interface and fixes

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#include "FaceBank.h"
18#include "ImageUtils.h"
19
20using namespace std;
21
22/////////////////////////////////////////////////////////////////////////////////
23
24Face::Face(IplImage *image) :
25m_Image(image)
26{
27}
28
29Face::~Face()
30{
31        cvReleaseImage(&m_Image);
32}
33
34void Face::Learn(const IplImage *image, float blend)
35{
36        CvSize sizea = cvGetSize(image);
37        CvSize sizeb = cvGetSize(m_Image);
38
39        assert(sizea.width == sizeb.width);
40        assert(sizea.height == sizeb.height);
41
42        float ret=0;
43
44    for(int y=0; y<sizea.height; y++)
45        {
46        for(int x=0; x<sizea.width; x++)
47                {
48                        cvSet2D(m_Image,y,x,cvScalar(
49                                                cvGet2D(m_Image,y,x).val[0]*(1 - blend) + cvGet2D(image,y,x).val[0]*blend,
50                                                cvGet2D(m_Image,y,x).val[1]*(1 - blend) + cvGet2D(image,y,x).val[1]*blend,
51                                                cvGet2D(m_Image,y,x).val[2]*(1 - blend) + cvGet2D(image,y,x).val[2]*blend));
52                }
53        }
54}
55
56/////////////////////////////////////////////////////////////////////////////////
57       
58FaceBank::FaceBank(unsigned int FaceWidth, unsigned int FaceHeight, float ErrorThresh) :
59m_FaceWidth(FaceWidth),
60m_FaceHeight(FaceHeight),
61m_ErrorThresh(ErrorThresh)
62{
63}
64
65FaceBank::~FaceBank()
66{       
67        Clear();
68}
69
70void FaceBank::Clear()
71{
72        for(map<unsigned int,Face*>::iterator i=m_FaceMap.begin(); i!=m_FaceMap.end(); ++i)
73        {
74                delete i->second;
75        }
76        m_FaceMap.clear();
77}
78
79float FaceBank::Suggest(IplImage *face, unsigned int ID)
80{
81        IplImage *faceresized = cvCreateImage(cvSize(m_FaceWidth,m_FaceHeight),IPL_DEPTH_8U, face->nChannels);
82        cvResize(face, faceresized, CV_INTER_LINEAR );
83        // Subtract the mean as an attempt to deal with global lighting changes
84        SubMean(faceresized);
85       
86        // Get this face
87        map<unsigned int,Face*>::iterator i=m_FaceMap.find(ID);
88       
89        // If it's the first time we've seen this face then record it
90        if (i==m_FaceMap.end())
91        {               
92                // Check it doesn't look like any we have already recorded
93                unsigned int checkid=0;
94                if (Identify(faceresized,checkid)>0)
95                {
96                        cerr<<"We've already seen this face: "<<checkid<<endl; 
97                        return 0;
98                }
99
100                cerr<<"new face "<<ID<<endl;
101                m_FaceMap[ID]=new Face(faceresized);
102                return 1;
103        }
104       
105        // Does this face look like the one we already have for this id?
106        float error = Diff(faceresized,i->second->m_Image);
107
108        if (error<m_ErrorThresh)
109        {
110                cerr<<"adding to face "<<ID<<endl;
111                // Blend this face into the one we have already
112                i->second->Learn(faceresized,0.2);
113                cvReleaseImage(&faceresized);
114                ID=i->first;
115                return 1-error;
116        }
117       
118        cerr<<"false positive? "<<error<<" "<<ID<<endl;
119       
120        return 0;
121}
122
123float FaceBank::Identify(IplImage *face, unsigned int &ID)
124{
125        IplImage *faceresized = cvCreateImage(cvSize(m_FaceWidth,m_FaceHeight),IPL_DEPTH_8U, face->nChannels);
126        cvResize(face, faceresized, CV_INTER_LINEAR );
127        // Subtract the mean as an attempt to deal with global lighting changes
128        SubMean(faceresized);
129
130        // No faces recorded?
131        if (m_FaceMap.empty())
132        {
133                return 0;
134        }
135       
136        float error=FLT_MAX;
137        unsigned int best=0;
138        Face* bestface=NULL;
139       
140        // look for the lowest error in the map of faces
141        for(map<unsigned int,Face*>::iterator i=m_FaceMap.begin(); i!=m_FaceMap.end(); ++i)
142        {
143                float tmp = Diff(faceresized,i->second->m_Image);
144                if (tmp<error)
145                {
146                        error=tmp;
147                        best=i->first;
148                        bestface=i->second;
149                }
150        }
151       
152        // if the error is less than the threshold, return the id
153        if (error<m_ErrorThresh)
154        {
155                // blend this face into the one we have already
156                bestface->Learn(faceresized,0);
157                cvReleaseImage(&faceresized);
158                ID=best;
159                return 1-error;
160        }
161       
162        cerr<<"unrecognised face"<<endl;
163       
164        return 0;
165}
Note: See TracBrowser for help on using the repository browser.