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 // FaceDetection.cpp: implementation of the FaceDetection class.
45 //
46 //////////////////////////////////////////////////////////////////////
47
48 #include "_cvaux.h"
49 #include "_cvfacedetection.h"
50
51
52 int CV_CDECL CompareContourRect(const void* el1, const void* el2, void* userdata);
53
54 //////////////////////////////////////////////////////////////////////
55 // Construction/Destruction
56 //////////////////////////////////////////////////////////////////////
57
FaceDetection()58 FaceDetection::FaceDetection()
59 {
60
61 m_imgGray = NULL;
62 m_imgThresh = NULL;
63 m_mstgContours = NULL;
64 memset(m_seqContours, 0, sizeof(CvSeq*) * MAX_LAYERS);
65 m_mstgRects = NULL;
66 m_seqRects = NULL;
67 m_iNumLayers = 16;
68 assert(m_iNumLayers <= MAX_LAYERS);
69 m_pFaceList = new List();
70
71
72
73 m_bBoosting = false;
74
75 }// FaceDetection()
76
~FaceDetection()77 FaceDetection::~FaceDetection()
78 {
79 if (m_imgGray)
80 cvReleaseImage(&m_imgGray);
81
82 if (m_imgThresh)
83 cvReleaseImage(&m_imgThresh);
84
85 if (m_mstgContours)
86 cvReleaseMemStorage(&m_mstgContours);
87
88 if (m_mstgRects)
89 cvReleaseMemStorage(&m_mstgRects);
90
91
92 }// ~FaceDetection()
93
FindContours(IplImage * imgGray)94 void FaceDetection::FindContours(IplImage* imgGray)
95 {
96 ReallocImage(&m_imgThresh, cvGetSize(imgGray), 1);
97 if (NULL == m_imgThresh)
98 return;
99 //
100 int iNumLayers = m_iNumLayers;
101 int iMinLevel = 0, iMaxLevel = 255, iStep = 255 / iNumLayers;
102 ThresholdingParam(imgGray, iNumLayers, iMinLevel, iMaxLevel, iStep);
103 // init
104 cvReleaseMemStorage(&m_mstgContours);
105 m_mstgContours = cvCreateMemStorage();
106 if (NULL == m_mstgContours)
107 return;
108 memset(m_seqContours, 0, sizeof(CvSeq*) * MAX_LAYERS);
109
110 cvReleaseMemStorage(&m_mstgRects);
111 m_mstgRects = cvCreateMemStorage();
112 if (NULL == m_mstgRects)
113 return;
114 m_seqRects = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvContourRect), m_mstgRects);
115 if (NULL == m_seqRects)
116 return;
117 // find contours
118 for (int l = iMinLevel, i = 0; l < iMaxLevel; l += iStep, i++)
119 {
120 cvThreshold(imgGray, m_imgThresh, (double)l, (double)255, CV_THRESH_BINARY);
121 if (cvFindContours(m_imgThresh, m_mstgContours, &m_seqContours[i], sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE))
122 AddContours2Rect(m_seqContours[i], l, i);
123 }
124 // sort rects
125 cvSeqSort(m_seqRects, CompareContourRect, NULL);
126 }// void FaceDetection::FindContours(IplImage* imgGray)
127
128 #define GIST_STEP 10
129 #define GIST_NUM (256 / GIST_STEP)
130 #define GIST_MIN 32
131
ThresholdingParam(IplImage * imgGray,int iNumLayers,int & iMinLevel,int & iMaxLevel,int & iStep)132 void FaceDetection::ThresholdingParam(IplImage *imgGray, int iNumLayers, int &iMinLevel, int &iMaxLevel, int &iStep)
133 {
134 assert(imgGray != NULL);
135 assert(imgGray->nChannels == 1);
136 int i, j;
137 // create gistogramm
138 uchar* buffImg = (uchar*)imgGray->imageData;
139 int gistImg[GIST_NUM + 1] = {0};
140
141 for (j = 0; j < imgGray->height; j ++)
142 {
143 for (i = 0; i < imgGray->width; i ++)
144 {
145 int ind = buffImg[i] / GIST_STEP;
146 gistImg[ind] ++;
147 }
148 buffImg += imgGray->widthStep;
149 }
150 // params
151
152 for (i = 0; i <= GIST_NUM; i ++)
153 {
154 if (gistImg[i] >= GIST_MIN)
155 break;
156 }
157
158 iMinLevel = i * GIST_STEP;
159
160 for (i = GIST_NUM; i >= 0; i --)
161 {
162 if (gistImg[i] >= GIST_MIN)
163 break;
164 }
165
166 iMaxLevel = i * GIST_STEP;
167
168 int dLevels = iMaxLevel - iMinLevel;
169 if (dLevels <= 0)
170 {
171 iMinLevel = 0;
172 iMaxLevel = 255;
173 }
174 else if (dLevels <= iNumLayers)
175 {
176 iMinLevel = iMaxLevel - iNumLayers;
177 if (iMinLevel < 0)
178 {
179 iMinLevel = 0;
180 iMaxLevel = iNumLayers;
181 }
182 }
183 iStep = (iMaxLevel - iMinLevel) / iNumLayers;
184
185 }// void FaceDetection::ThresholdingParam(IplImage *imgGray, int iNumLayers, int &iMinLevel, int &iMaxLevel, int &iStep)
186
187 #ifndef MAX_ERROR
188 #define MAX_ERROR 0xFFFFFFFF
189 #endif //MAX_ERROR
190
191
CreateResults(CvSeq * lpSeq)192 void FaceDetection::CreateResults(CvSeq * lpSeq)
193 {
194
195 Face * tmp;
196
197 double Max = 0;
198 double CurStat = 0;
199
200 FaceData tmpData;
201 if (m_bBoosting)
202 {
203 tmp = m_pFaceList->GetData();
204 tmp->CreateFace(&tmpData);
205
206 CvFace tmpFace;
207 tmpFace.MouthRect = tmpData.MouthRect;
208 tmpFace.LeftEyeRect = tmpData.LeftEyeRect;
209 tmpFace.RightEyeRect = tmpData.RightEyeRect;
210
211 cvSeqPush(lpSeq,&tmpFace);
212
213 }else
214 {
215 while ( (tmp = m_pFaceList->GetData()) != 0 )
216 {
217 CurStat = tmp->GetWeight();
218 if (CurStat > Max)
219 Max = CurStat;
220 }
221
222 while ( (tmp = m_pFaceList->GetData()) != 0 )
223 {
224 tmp->CreateFace(&tmpData);
225 CurStat = tmp->GetWeight();
226
227 if (CurStat == Max)
228 {
229 CvFace tmpFace;
230 tmpFace.MouthRect = tmpData.MouthRect;
231 tmpFace.LeftEyeRect = tmpData.LeftEyeRect;
232 tmpFace.RightEyeRect = tmpData.RightEyeRect;
233 cvSeqPush(lpSeq,&tmpFace);
234
235
236 }
237 }
238 }
239 }// void FaceDetection::DrawResult(IplImage* img)
240
ResetImage()241 void FaceDetection::ResetImage()
242 {
243 delete m_pFaceList;
244 m_pFaceList = new List();
245
246 }//FaceDetection::ResetImage
247
AddContours2Rect(CvSeq * seq,int color,int iLayer)248 void FaceDetection::AddContours2Rect(CvSeq *seq, int color, int iLayer)
249 {
250 assert(m_mstgRects != NULL);
251 assert(m_seqRects != NULL);
252
253 CvContourRect cr;
254 for (CvSeq* external = seq; external; external = external->h_next)
255 {
256 cr.r = cvContourBoundingRect(external, 1 );
257 cr.pCenter.x = cr.r.x + cr.r.width / 2;
258 cr.pCenter.y = cr.r.y + cr.r.height / 2;
259 cr.iNumber = iLayer;
260 cr.iType = 6;
261 cr.iFlags = 0;
262 cr.seqContour = external;
263 cr.iContourLength = external->total;
264 cr.iColor = color;
265 cvSeqPush(m_seqRects, &cr);
266 for (CvSeq* internal = external->v_next; internal; internal = internal->h_next)
267 {
268 cr.r = cvContourBoundingRect(internal, 0);
269 cr.pCenter.x = cr.r.x + cr.r.width / 2;
270 cr.pCenter.y = cr.r.y + cr.r.height / 2;
271 cr.iNumber = iLayer;
272 cr.iType = 12;
273 cr.iFlags = 0;
274 cr.seqContour = internal;
275 cr.iContourLength = internal->total;
276 cr.iColor = color;
277 cvSeqPush(m_seqRects, &cr);
278 }
279 }
280 }// void FaceDetection::AddContours2Rect(CvSeq *seq, int color, int iLayer)
281
CompareContourRect(const void * el1,const void * el2,void *)282 int CV_CDECL CompareContourRect(const void* el1, const void* el2, void* /*userdata*/)
283 {
284 return (((CvContourRect*)el1)->pCenter.y - ((CvContourRect*)el2)->pCenter.y);
285 }// int CV_CDECL CompareContourRect(const void* el1, const void* el2, void* userdata)
286
FindFace(IplImage * img)287 void FaceDetection::FindFace(IplImage *img)
288 {
289 // find all contours
290 FindContours(img);
291 //
292 ResetImage();
293
294 if (m_bBoosting)
295 PostBoostingFindCandidats(img);
296 else
297 FindCandidats();
298
299 }// void FaceDetection::FindFace(IplImage *img)
300
301
FindCandidats()302 void FaceDetection::FindCandidats()
303 {
304 bool bFound1 = false;
305 MouthFaceTemplate * lpFaceTemplate1;
306 RFace * lpFace1;
307 bool bInvalidRect1 = false;
308 CvRect * lpRect1 = NULL;
309
310 for (int i = 0; i < m_seqRects->total; i++)
311 {
312 CvContourRect* pRect = (CvContourRect*)cvGetSeqElem(m_seqRects, i);
313 CvRect rect = pRect->r;
314 if (rect.width >= 2*rect.height)
315 {
316
317 lpFaceTemplate1 = new MouthFaceTemplate(3,rect,3*(double)rect.width/(double)4,
318 3*(double)rect.width/(double)4,
319 (double)rect.width/(double)2,
320 (double)rect.width/(double)2);
321
322
323 lpFace1 = new RFace(lpFaceTemplate1);
324
325 for (int j = 0; j < m_seqRects->total; j++)
326 {
327 CvContourRect* pRect = (CvContourRect*)cvGetSeqElem(m_seqRects, j);
328
329 if ( !bInvalidRect1 )
330 {
331 lpRect1 = NULL;
332 lpRect1 = new CvRect();
333 *lpRect1 = pRect->r;
334 }else
335 {
336 delete lpRect1;
337 lpRect1 = new CvRect();
338 *lpRect1 = pRect->r;
339 }
340
341
342 if ( lpFace1->isFeature(lpRect1) )
343 {
344 bFound1 = true;
345 bInvalidRect1 = false;
346 }else
347 bInvalidRect1 = true;
348
349
350 }
351
352
353 if (bFound1)
354 {
355 m_pFaceList->AddElem(lpFace1);
356 bFound1 = false;
357 lpFace1 = NULL;
358 }else
359 {
360 delete lpFace1;
361 lpFace1 = NULL;
362 }
363
364
365 delete lpFaceTemplate1;
366 }
367
368 }
369
370 }
371
372
PostBoostingFindCandidats(IplImage * FaceImage)373 void FaceDetection::PostBoostingFindCandidats(IplImage * FaceImage)
374 {
375 BoostingFaceTemplate * lpFaceTemplate1;
376 RFace * lpFace1;
377 bool bInvalidRect1 = false;
378 CvRect * lpRect1 = NULL;
379
380 if ( ( !FaceImage->roi ) )
381 lpFaceTemplate1 = new BoostingFaceTemplate(3,cvRect(0,0,FaceImage->width,FaceImage->height));
382 else
383 lpFaceTemplate1 = new BoostingFaceTemplate(3,cvRect(FaceImage->roi->xOffset,FaceImage->roi->yOffset,
384 FaceImage->roi->width,FaceImage->roi->height));
385
386 lpFace1 = new RFace(lpFaceTemplate1);
387
388 for (int i = 0; i < m_seqRects->total; i++)
389 {
390 CvContourRect* pRect = (CvContourRect*)cvGetSeqElem(m_seqRects, i);
391
392 if ( !bInvalidRect1 )
393 {
394 lpRect1 = NULL;
395 lpRect1 = new CvRect();
396 *lpRect1 = pRect->r;
397 }else
398 {
399 delete lpRect1;
400 lpRect1 = new CvRect();
401 *lpRect1 = pRect->r;
402 }
403
404
405 if ( lpFace1->isFeature(lpRect1) )
406 {
407 //bFound1 = true;
408 bInvalidRect1 = false;
409 }else
410 bInvalidRect1 = true;
411
412
413 }
414
415 m_pFaceList->AddElem(lpFace1);
416
417 delete lpFaceTemplate1;
418
419 }//void FaceDetection::PostBoostingFindCandidats(IplImage * FaceImage)
420
421 /////////////////////////
422 //class Face
423
424
425
426 //////
427 //List Class
428 /////
ListElem()429 ListElem::ListElem()
430 {
431 m_pNext = this;
432 m_pPrev = this;
433 m_pFace = NULL;
434 }///ListElem::ListElem()
435
ListElem(Face * pFace,ListElem * pHead)436 ListElem::ListElem(Face * pFace,ListElem * pHead)
437 {
438 m_pNext = pHead;
439 m_pPrev = pHead->m_pPrev;
440 pHead->m_pPrev->m_pNext = this;
441 pHead->m_pPrev = this;
442
443 m_pFace = pFace;
444 }//ListElem::ListElem(Face * pFace)
445
446
447
~ListElem()448 ListElem::~ListElem()
449 {
450 delete m_pFace;
451 m_pNext->m_pPrev = m_pPrev;
452 m_pPrev->m_pNext = m_pNext;
453
454 }//ListElem::~ListElem()
455
List()456 List::List()
457 {
458 m_pHead = new ListElem();
459 m_FacesCount = 0;
460 m_pCurElem = m_pHead;
461 }//List::List()
462
~List()463 List::~List()
464 {
465 void * tmp;
466 while((tmp = m_pHead->m_pNext->m_pFace) != 0)
467 delete m_pHead->m_pNext;
468
469 delete m_pHead;
470
471 }//List::~List()
472
473
AddElem(Face * pFace)474 int List::AddElem(Face * pFace)
475 {
476 new ListElem(pFace,m_pHead);
477 return m_FacesCount++;
478 }//List::AddElem(Face * pFace)
479
GetData()480 Face * List::GetData()
481 {
482 m_pCurElem = m_pCurElem->m_pNext;
483 return m_pCurElem->m_pFace;
484 }//Face * List::GetData()
485
486
487