Home | History | Annotate | Download | only in src
      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 (at) 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 
     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 
     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 List();
    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;
    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 
    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 /////
    429 ListElem::ListElem()
    430 {
    431     m_pNext = this;
    432     m_pPrev = this;
    433     m_pFace = NULL;
    434 }///ListElem::ListElem()
    435 
    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 
    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 
    456 List::List()
    457 {
    458     m_pHead = new ListElem();
    459     m_FacesCount = 0;
    460     m_pCurElem = m_pHead;
    461 }//List::List()
    462 
    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 
    474 int List::AddElem(Face * pFace)
    475 {
    476     new ListElem(pFace,m_pHead);
    477     return m_FacesCount++;
    478 }//List::AddElem(Face * pFace)
    479 
    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