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 52int CV_CDECL CompareContourRect(const void* el1, const void* el2, void* userdata); 53 54////////////////////////////////////////////////////////////////////// 55// Construction/Destruction 56////////////////////////////////////////////////////////////////////// 57 58FaceDetection::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 77FaceDetection::~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 94void 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 132void 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 192void 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 241void FaceDetection::ResetImage() 242{ 243 delete m_pFaceList; 244 m_pFaceList = new List(); 245 246}//FaceDetection::ResetImage 247 248void 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 282int 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 287void 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 302void 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 373void 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///// 429ListElem::ListElem() 430{ 431 m_pNext = this; 432 m_pPrev = this; 433 m_pFace = NULL; 434}///ListElem::ListElem() 435 436ListElem::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 448ListElem::~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 456List::List() 457{ 458 m_pHead = new ListElem(); 459 m_FacesCount = 0; 460 m_pCurElem = m_pHead; 461}//List::List() 462 463List::~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 474int List::AddElem(Face * pFace) 475{ 476 new ListElem(pFace,m_pHead); 477 return m_FacesCount++; 478}//List::AddElem(Face * pFace) 479 480Face * List::GetData() 481{ 482 m_pCurElem = m_pCurElem->m_pNext; 483 return m_pCurElem->m_pFace; 484}//Face * List::GetData() 485 486 487