Move the sources to trunk
[opencv] / cvaux / src / cvface.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41 ///////////////////////////////////////////////
42 //// Created by Khudyakov V.A. bober@gorodok.net
43 //////////////////////////////////////////////
44
45 #include "_cvaux.h"
46 #include "_cvfacedetection.h"
47
48 Face::Face(FaceTemplate * lpFaceTemplate)
49 {
50     //init number of face elements;
51     m_lFaceFeaturesNumber = lpFaceTemplate->GetCount();
52     
53     //init array of numbers of foundet face elements of each type
54     m_lplFaceFeaturesCount = new long[m_lFaceFeaturesNumber];   
55     memset(m_lplFaceFeaturesCount,0,m_lFaceFeaturesNumber*sizeof(long));
56     
57     //init array of ideal face features
58     m_lpIdealFace = new FaceFeature[m_lFaceFeaturesNumber];
59
60     //init array of founded features
61     m_lppFoundedFaceFeatures = new FaceFeature*[m_lFaceFeaturesNumber];
62     
63     for (int i = 0;i < m_lFaceFeaturesNumber;i ++)
64     {
65         m_lppFoundedFaceFeatures[i] = (new FaceFeature[3*MAX_LAYERS]);
66     }
67
68     //set start weight 0
69     m_dWeight = 0;  
70
71 }//Face::Face(FaceTemplate * lpFaceTemplate)
72
73 Face::~Face()
74 {
75     for (int i = 0;i < m_lFaceFeaturesNumber;i ++)
76     {
77         delete [] (m_lppFoundedFaceFeatures[i]);
78     }
79     delete [] m_lppFoundedFaceFeatures;
80     
81     
82     delete [] m_lplFaceFeaturesCount;
83     delete [] m_lpIdealFace;
84
85 }//Face::~Face()
86
87
88 #define UP_SCALE    1
89 #define DOWN_SCALE  2
90
91
92 ////////////
93 //class RFace(rect based face) 
94 ////////////
95 RFace::RFace(FaceTemplate * lpFaceTemplate):Face(lpFaceTemplate)
96 {
97     //init ideal face
98     FaceFeature * lpTmp = lpFaceTemplate->GetFeatures();
99     
100     for (int j = 0;j < m_lFaceFeaturesNumber;j ++)
101     {
102         CvRect * lpTmpRect = NULL;
103         lpTmpRect = new CvRect;
104         *lpTmpRect = *(CvRect*)lpTmp[j].GetContour(); 
105         
106         m_lpIdealFace[j].SetContour( lpTmpRect );
107         m_lpIdealFace[j].SetWeight( lpTmp[j].GetWeight() );
108         m_lpIdealFace[j].SetFeature( lpTmp[j].isFaceFeature() );
109
110     }
111
112     m_bIsGenerated = false;
113 }//RFace::RFace(FaceTemplate * lpFaceTemplate)
114
115 RFace::~RFace()
116 {
117
118 }//RFace::~RFace()
119
120 inline bool RFace::isPointInRect(CvPoint p,CvRect rect)
121 {
122     if ( (p.x >= rect.x) && (p.y >= rect.y) && (p.x <= rect.x + rect.width) && (p.y <= rect.y + rect.height) )
123         return true;
124
125     return false;
126 }//inline bool RFace::isPointInRect(CvPoint,CvRect rect)
127
128 double RFace::GetWeight()
129 {
130     return m_dWeight;
131 }//double RFace::GetWeight()
132
133
134 bool RFace::CheckElem(void * lpCandidat,void * lpIdeal)
135 {
136     
137     CvRect IdealRect = *(CvRect*)lpIdeal;
138     CvRect Rect = *(CvRect*)lpCandidat;
139
140     if (Rect.height > Rect.width)
141         return false;
142     
143     long SizeIdeal = IdealRect.width*IdealRect.height;
144     long Size = Rect.width*Rect.height;
145     
146     if ( (Size > SizeIdeal) || ( Size < (SizeIdeal/5) ) )
147         return false;
148
149 //  CvRect UpRect;
150 //  CvRect DownRect;
151 //  ResizeRect(IdealRect,&UpRect,UP_SCALE,7);
152 //  ResizeRect(IdealRect,&DownRect,DOWN_SCALE,7);
153
154     long x = Rect.x + cvRound(Rect.width/2);  
155     long y = Rect.y + cvRound(Rect.height/2);
156
157     if ( isPointInRect(cvPoint(x,y),IdealRect) )
158         return true;
159     
160 //  if ( isPointInRect(cvPoint(Rect.x,Rect.y),UpRect) && 
161 //       isPointInRect(cvPoint(Rect.x + Rect.width,Rect.y + Rect.height),UpRect ) &&
162 //       isPointInRect(cvPoint(DownRect.x,DownRect.y),Rect) &&
163 //       isPointInRect(cvPoint(DownRect.x + DownRect.width,DownRect.y + DownRect.height),Rect) )
164 //      return true;
165     
166     
167 //  if ( isPointInRect(cvPoint(Rect.x,Rect.y),IdealRect) && 
168 //       isPointInRect(cvPoint(Rect.x + Rect.width,Rect.y + Rect.height),IdealRect ) )
169 //      return true;
170             
171     return false;
172 }//inline bool RFace::CheckElem(CvRect rect)
173
174
175
176 void RFace::CalculateError(FaceData * lpFaceData)
177 {
178     CvRect LeftEyeRect = lpFaceData->LeftEyeRect;
179     CvRect RightEyeRect = lpFaceData->RightEyeRect;
180     CvRect MouthRect = lpFaceData->MouthRect;
181     
182     long LeftSquare = LeftEyeRect.width*LeftEyeRect.height;
183     long RightSquare = RightEyeRect.width*RightEyeRect.height;
184
185     long dy = LeftEyeRect.y - RightEyeRect.y;
186     
187     long dx1 = LeftEyeRect.x + LeftEyeRect.width/2 - MouthRect.x;
188     long dx2 = RightEyeRect.x + RightEyeRect.width/2 - MouthRect.x - MouthRect.width;
189
190
191     lpFaceData->Error = (double)(LeftSquare - RightSquare)*(double)(LeftSquare - RightSquare)/((double)(LeftSquare + RightSquare)*(LeftSquare + RightSquare)) + 
192                         (double)(dy*dy)/((double)(LeftEyeRect.height + RightEyeRect.height)*(LeftEyeRect.height + RightEyeRect.height)) + 
193                         (double)(dx1*dx1)/((double)MouthRect.width*MouthRect.width) + 
194                         (double)(dx2*dx2)/((double)MouthRect.width*MouthRect.width);
195                         
196 }//void RFace::CalculateError(FaceData * lpFaceData)
197
198 #define MAX_ERROR 0xFFFFFFFF
199
200 void  RFace::CreateFace(void * lpData)
201 {
202     FaceData Data;
203     
204     double Error = MAX_ERROR;
205     double CurError = MAX_ERROR;
206     
207     FaceData * lpFaceData = (FaceData*)lpData;
208     
209     int im = 0;//mouth was find
210     int jl = 0;//left eye was find
211     int kr = 0;//right eye was find
212     
213     long MouthNumber = 0;
214     long LeftEyeNumber = 0;
215     long RightEyeNumber = 0;
216
217     for (int i = 0;i < m_lplFaceFeaturesCount[0] + 1;i ++)
218     {
219         
220         if ( !m_lplFaceFeaturesCount[0] )
221             Data.MouthRect = *(CvRect*)m_lpIdealFace[0].GetContour();
222         else
223         {
224             if ( i != m_lplFaceFeaturesCount[0] )
225                 Data.MouthRect = *(CvRect*)m_lppFoundedFaceFeatures[0][i].GetContour();
226             im = 1;
227         }
228             
229         
230         for (int j = 0;j < m_lplFaceFeaturesCount[1] + 1;j ++)
231         {
232             
233             if ( !m_lplFaceFeaturesCount[1] )
234                 Data.LeftEyeRect = *(CvRect*)m_lpIdealFace[1].GetContour();
235             else
236             {
237                 if (j != m_lplFaceFeaturesCount[1] )
238                     Data.LeftEyeRect = *(CvRect*)m_lppFoundedFaceFeatures[1][j].GetContour();
239                 jl = 1;
240             }
241             
242             
243             for (int k = 0;k < m_lplFaceFeaturesCount[2] + 1;k ++)
244             {
245
246                 if ( !m_lplFaceFeaturesCount[2] )
247                     Data.RightEyeRect = *(CvRect*)m_lpIdealFace[2].GetContour();
248                 else
249                 {
250                     if (k != m_lplFaceFeaturesCount[2] )
251                         Data.RightEyeRect = *(CvRect*)m_lppFoundedFaceFeatures[2][k].GetContour();
252                     kr = 1;
253                 }
254         
255                 CalculateError(&Data);      
256         
257                 if ( (im + jl + kr) )
258                 {
259                     Error = Data.Error/(im + jl + kr);
260                 }else
261                     Error = MAX_ERROR;
262                 
263                 if (CurError > Error)
264                 {
265                     CurError = Error;
266                     MouthNumber = i;
267                     LeftEyeNumber = j;
268                     RightEyeNumber = k;
269                 }
270
271             }
272         
273         
274         }
275
276     }
277
278     if ( m_lplFaceFeaturesCount[0] )
279         lpFaceData->MouthRect = *(CvRect*)m_lppFoundedFaceFeatures[0][MouthNumber].GetContour();
280     else
281         lpFaceData->MouthRect = *(CvRect*)m_lpIdealFace[0].GetContour();
282
283     if ( m_lplFaceFeaturesCount[1] )
284         lpFaceData->LeftEyeRect = *(CvRect*)m_lppFoundedFaceFeatures[1][LeftEyeNumber].GetContour();
285     else
286         lpFaceData->LeftEyeRect = *(CvRect*)m_lpIdealFace[1].GetContour();
287     
288     if ( m_lplFaceFeaturesCount[2] )
289         lpFaceData->RightEyeRect = *(CvRect*)m_lppFoundedFaceFeatures[2][RightEyeNumber].GetContour();
290     else
291         lpFaceData->RightEyeRect = *(CvRect*)m_lpIdealFace[2].GetContour();
292
293     lpFaceData->Error = CurError;
294
295 }//void * RFace::CreateFace()
296
297 void RFace::Show(IplImage * Image)
298 {
299     for (int i = 0;i < m_lFaceFeaturesNumber;i ++)
300     {
301         if (m_lplFaceFeaturesCount[i])
302         {
303             for (int j = 0;j < m_lplFaceFeaturesCount[i];j ++)
304             {
305                 CvRect rect = *(CvRect*)m_lppFoundedFaceFeatures[i][j].GetContour();
306                 CvPoint p1 = cvPoint(rect.x,rect.y);
307                 CvPoint p2 = cvPoint(rect.x + rect.width,rect.y + rect.height);
308                 cvRectangle(Image,p1,p2,CV_RGB(255,0,0),1);
309             }
310         }
311     }
312
313 }//void RFace::Show(IplImage * Image)
314
315 void RFace::ShowIdeal(IplImage* Image)
316 {
317     for (int i = 0;i < m_lFaceFeaturesNumber;i ++)
318     {
319         CvRect Rect = *(CvRect*)m_lpIdealFace[i].GetContour();
320         CvPoint p1 = cvPoint(Rect.x,Rect.y);
321         CvPoint p2 = cvPoint(Rect.x + Rect.width,Rect.y + Rect.height);
322         cvRectangle(Image,p1,p2,CV_RGB(0,0,255),1);
323     }
324 }//void RFace::ShowIdeal(IplImage* Image)
325
326
327 inline void RFace::ResizeRect(CvRect Rect,CvRect * lpRect,long lDir,long lD)
328 {
329     if (lDir == UP_SCALE)
330     {
331         lpRect->x = Rect.x - lD;
332         lpRect->y = Rect.y - lD;
333         lpRect->width = Rect.width + 2*lD;
334         lpRect->height = Rect.height + 2*lD;
335     }
336     if (lDir == DOWN_SCALE)
337     {
338         lpRect->x = Rect.x + lD;
339         lpRect->y = Rect.y + lD;
340         if (Rect.width - 2*lD >= 0)
341         {
342             lpRect->width = Rect.width - 2*lD;
343         }else
344             lpRect->width = 0;
345         
346         if (Rect.height - 2*lD >= 0)
347         {
348             lpRect->height = Rect.height - 2*lD;
349         }else
350             lpRect->height = 0;
351     }
352
353 }// inline void RFace::ResizeRect(CvRect * lpRect,long lDir,long lD)
354