b93d9aa6b2dd8074a430fbcc06398944ae2f463d
[platform/upstream/opencv.git] / modules / legacy / src / facedetection.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 // FaceDetection.cpp: implementation of the FaceDetection class.
45 //
46 //////////////////////////////////////////////////////////////////////
47
48 #include "precomp.hpp"
49 #include "_facedetection.h"
50
51
52 int CV_CDECL CompareContourRect(const void* el1, const void* el2, void* userdata);
53
54 //////////////////////////////////////////////////////////////////////
55 // Construction/Destruction
56 //////////////////////////////////////////////////////////////////////
57
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 FaceDetectionList();
70
71
72
73     m_bBoosting = false;
74
75 }// FaceDetection()
76
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
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
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
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
241 void FaceDetection::ResetImage()
242 {
243         delete m_pFaceList;
244         m_pFaceList = new FaceDetectionList();
245
246 }//FaceDetection::ResetImage
247
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
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
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
302 void FaceDetection::FindCandidats()
303 {
304     bool bFound1 = false;
305     MouthFaceTemplate * lpFaceTemplate1 = 0;
306     RFace * lpFace1 = 0;
307     bool bInvalidRect1 = false;
308     CvRect * lpRect1  = NULL;
309
310     try
311     {
312         for (int i = 0; i < m_seqRects->total; i++)
313         {
314             CvContourRect* pRect = (CvContourRect*)cvGetSeqElem(m_seqRects, i);
315             CvRect rect = pRect->r;
316             if (rect.width >= 2*rect.height)
317             {
318
319                 lpFaceTemplate1 = new MouthFaceTemplate(3,rect,3*(double)rect.width/(double)4,
320                                                                3*(double)rect.width/(double)4,
321                                                                  (double)rect.width/(double)2,
322                                                                  (double)rect.width/(double)2);
323
324
325                 lpFace1 = new RFace(lpFaceTemplate1);
326
327                 for (int j = 0; j < m_seqRects->total; j++)
328                 {
329                     CvContourRect* prect = (CvContourRect*)cvGetSeqElem(m_seqRects, j);
330
331                     if ( !bInvalidRect1 )
332                     {
333                         lpRect1 = NULL;
334                         lpRect1 = new CvRect();
335                         *lpRect1 = prect->r;
336                     }else
337                     {
338                         delete lpRect1;
339                         lpRect1 = new CvRect();
340                         *lpRect1 = prect->r;
341                     }
342
343
344                     if ( lpFace1->isFeature(lpRect1) )
345                     {
346                         bFound1 = true;
347                         bInvalidRect1 = false;
348                     }else
349                         bInvalidRect1 = true;
350
351
352                 }
353
354
355                 if (bFound1)
356                 {
357                     m_pFaceList->AddElem(lpFace1);
358                     bFound1 = false;
359                     lpFace1 = NULL;
360                 }else
361                 {
362                     delete lpFace1;
363                     lpFace1 = NULL;
364                 }
365
366
367                 delete lpFaceTemplate1;
368             }
369
370         }
371     }
372     catch(...)
373     {
374         delete lpFaceTemplate1;
375         delete lpFace1;
376         throw;
377     }
378 }
379
380
381 void FaceDetection::PostBoostingFindCandidats(IplImage * FaceImage)
382 {
383     BoostingFaceTemplate * lpFaceTemplate1 = 0;
384     RFace * lpFace1 = 0;
385     bool bInvalidRect1 = false;
386     CvRect * lpRect1  = NULL;
387
388     try
389     {
390         if ( ( !FaceImage->roi ) )
391             lpFaceTemplate1 = new BoostingFaceTemplate(3,cvRect(0,0,FaceImage->width,FaceImage->height));
392         else
393             lpFaceTemplate1 = new BoostingFaceTemplate(3,cvRect(FaceImage->roi->xOffset,FaceImage->roi->yOffset,
394                                                                 FaceImage->roi->width,FaceImage->roi->height));
395
396         lpFace1 = new RFace(lpFaceTemplate1);
397
398         for (int i = 0; i < m_seqRects->total; i++)
399         {
400             CvContourRect* pRect = (CvContourRect*)cvGetSeqElem(m_seqRects, i);
401
402             if ( !bInvalidRect1 )
403             {
404                 lpRect1 = NULL;
405                 lpRect1 = new CvRect();
406                 *lpRect1 = pRect->r;
407             }else
408             {
409                 delete lpRect1;
410                 lpRect1 = new CvRect();
411                 *lpRect1 = pRect->r;
412             }
413
414
415             if ( lpFace1->isFeature(lpRect1) )
416             {
417                 //bFound1 = true;
418                 bInvalidRect1 = false;
419             }else
420                 bInvalidRect1 = true;
421
422
423         }
424
425         m_pFaceList->AddElem(lpFace1);
426         lpFace1 = NULL;
427
428         delete lpFaceTemplate1;
429     }
430     catch(...)
431     {
432         delete lpFace1;
433         delete lpFaceTemplate1;
434         throw;
435     }
436 }//void FaceDetection::PostBoostingFindCandidats(IplImage * FaceImage)
437
438 /////////////////////////
439 //class Face
440
441
442
443 //////
444 //FaceDetectionList Class
445 /////
446 FaceDetectionListElem::FaceDetectionListElem()
447 {
448     m_pNext = this;
449     m_pPrev = this;
450     m_pFace = NULL;
451 }///FaceDetectionListElem::FaceDetectionListElem()
452
453 FaceDetectionListElem::FaceDetectionListElem(Face * pFace,FaceDetectionListElem * pHead)
454 {
455     m_pNext = pHead;
456     m_pPrev = pHead->m_pPrev;
457     pHead->m_pPrev->m_pNext = this;
458     pHead->m_pPrev = this;
459
460     m_pFace = pFace;
461 }//FaceDetectionListElem::FaceDetectionListElem(Face * pFace)
462
463
464
465 FaceDetectionListElem::~FaceDetectionListElem()
466 {
467     delete m_pFace;
468     m_pNext->m_pPrev = m_pPrev;
469     m_pPrev->m_pNext = m_pNext;
470
471 }//FaceDetectionListElem::~FaceDetectionListElem()
472
473 FaceDetectionList::FaceDetectionList()
474 {
475     m_pHead = new FaceDetectionListElem();
476     m_FacesCount = 0;
477     m_pCurElem = m_pHead;
478 }//FaceDetectionList::FaceDetectionList()
479
480 FaceDetectionList::~FaceDetectionList()
481 {
482     void * tmp;
483     while((tmp = m_pHead->m_pNext->m_pFace) != 0)
484         delete m_pHead->m_pNext;
485
486     delete m_pHead;
487
488 }//FaceDetectionList::~FaceDetectionList()
489
490
491 int FaceDetectionList::AddElem(Face * pFace)
492 {
493     new FaceDetectionListElem(pFace,m_pHead);
494     return m_FacesCount++;
495 }//FaceDetectionList::AddElem(Face * pFace)
496
497 Face * FaceDetectionList::GetData()
498 {
499     m_pCurElem = m_pCurElem->m_pNext;
500     return m_pCurElem->m_pFace;
501 }//Face * FaceDetectionList::GetData()