1d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org/*M///////////////////////////////////////////////////////////////////////////////////////
245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//
345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//
545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//  By downloading, copying, installing or using the software you agree to this license.
645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//  If you do not agree to this license, do not download, install,
745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//  copy or use the software.
845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//
945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//
1045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//                        Intel License Agreement
1145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//                For Open Source Computer Vision Library
1245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//
1345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// Copyright (C) 2000, Intel Corporation, all rights reserved.
1445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// Third party copyrights are property of their respective owners.
1545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//
1645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// Redistribution and use in source and binary forms, with or without modification,
1745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// are permitted provided that the following conditions are met:
1845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//
1945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//   * Redistribution's of source code must retain the above copyright notice,
2045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//     this list of conditions and the following disclaimer.
2145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//
2245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//   * Redistribution's in binary form must reproduce the above copyright notice,
2345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//     this list of conditions and the following disclaimer in the documentation
2445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//     and/or other materials provided with the distribution.
2545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//
2645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//   * The name of Intel Corporation may not be used to endorse or promote products
2745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//     derived from this software without specific prior written permission.
2845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//
2945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// This software is provided by the copyright holders and contributors "as is" and
3045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// any express or implied warranties, including, but not limited to, the implied
3145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// warranties of merchantability and fitness for a particular purpose are disclaimed.
3245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// In no event shall the Intel Corporation or contributors be liable for any direct,
3345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// indirect, incidental, special, exemplary, or consequential damages
3445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// (including, but not limited to, procurement of substitute goods or services;
3545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// loss of use, data, or profits; or business interruption) however caused
3645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// and on any theory of liability, whether in contract, strict liability,
3745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// or tort (including negligence or otherwise) arising in any way out of
3845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org// the use of this software, even if advised of the possibility of such damage.
3945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//
4045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//M*/
4145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org///////////////////////////////////////////////
4245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//// Created by Khudyakov V.A. bober@gorodok.net
4345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//////////////////////////////////////////////
4445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
4545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "_cvaux.h"
4645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "_cvfacedetection.h"
4745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
4845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgFace::Face(FaceTemplate * lpFaceTemplate)
4945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
5045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    //init number of face elements;
5145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    m_lFaceFeaturesNumber = lpFaceTemplate->GetCount();
5245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
5345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    //init array of numbers of foundet face elements of each type
5445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    m_lplFaceFeaturesCount = new long[m_lFaceFeaturesNumber];
5545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    memset(m_lplFaceFeaturesCount,0,m_lFaceFeaturesNumber*sizeof(long));
5645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
5745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    //init array of ideal face features
5845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    m_lpIdealFace = new FaceFeature[m_lFaceFeaturesNumber];
5945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
6045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    //init array of founded features
6145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    m_lppFoundedFaceFeatures = new FaceFeature*[m_lFaceFeaturesNumber];
6245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
6345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (int i = 0;i < m_lFaceFeaturesNumber;i ++)
6445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    {
6545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        m_lppFoundedFaceFeatures[i] = (new FaceFeature[3*MAX_LAYERS]);
6645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
6745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
6845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    //set start weight 0
6945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    m_dWeight = 0;
7045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
7145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}//Face::Face(FaceTemplate * lpFaceTemplate)
7245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
7345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgFace::~Face()
7445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
7545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (int i = 0;i < m_lFaceFeaturesNumber;i ++)
7645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    {
7745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        delete [] (m_lppFoundedFaceFeatures[i]);
7845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
7945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    delete [] m_lppFoundedFaceFeatures;
8045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
8145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
8245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    delete [] m_lplFaceFeaturesCount;
8345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    delete [] m_lpIdealFace;
8445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
8545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}//Face::~Face()
8645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
8745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
8845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#define UP_SCALE    1
8945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#define DOWN_SCALE  2
9045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
9145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
9245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org////////////
9345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org//class RFace(rect based face)
9445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org////////////
9545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgRFace::RFace(FaceTemplate * lpFaceTemplate):Face(lpFaceTemplate)
9645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
9745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    //init ideal face
9845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    FaceFeature * lpTmp = lpFaceTemplate->GetFeatures();
9945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
10045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (int j = 0;j < m_lFaceFeaturesNumber;j ++)
10145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    {
10245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        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
115RFace::~RFace()
116{
117
118}//RFace::~RFace()
119
120inline 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
128double RFace::GetWeight()
129{
130    return m_dWeight;
131}//double RFace::GetWeight()
132
133
134bool 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
176void 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
200void  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
297void 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
315void 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
327inline 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
355