X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Fcvaux%2Fcvfacedetection.cpp;fp=src%2Fcvaux%2Fcvfacedetection.cpp;h=da04df7b0205c5fb99d113cad7628b718f415e64;hb=e4c14cdbdf2fe805e79cd96ded236f57e7b89060;hp=0000000000000000000000000000000000000000;hpb=454138ff8a20f6edb9b65a910101403d8b520643;p=opencv diff --git a/src/cvaux/cvfacedetection.cpp b/src/cvaux/cvfacedetection.cpp new file mode 100644 index 0000000..da04df7 --- /dev/null +++ b/src/cvaux/cvfacedetection.cpp @@ -0,0 +1,486 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ +/////////////////////////////////////////////// +//// Created by Khudyakov V.A. bober@gorodok.net +////////////////////////////////////////////// +// FaceDetection.cpp: implementation of the FaceDetection class. +// +////////////////////////////////////////////////////////////////////// + +#include "_cvaux.h" +#include "_cvfacedetection.h" + + +int CV_CDECL CompareContourRect(const void* el1, const void* el2, void* userdata); + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +FaceDetection::FaceDetection() +{ + + m_imgGray = NULL; + m_imgThresh = NULL; + m_mstgContours = NULL; + memset(m_seqContours, 0, sizeof(CvSeq*) * MAX_LAYERS); + m_mstgRects = NULL; + m_seqRects = NULL; + m_iNumLayers = 16; + assert(m_iNumLayers <= MAX_LAYERS); + m_pFaceList = new List(); + + + + m_bBoosting = false; + +}// FaceDetection() + +FaceDetection::~FaceDetection() +{ + if (m_imgGray) + cvReleaseImage(&m_imgGray); + + if (m_imgThresh) + cvReleaseImage(&m_imgThresh); + + if (m_mstgContours) + cvReleaseMemStorage(&m_mstgContours); + + if (m_mstgRects) + cvReleaseMemStorage(&m_mstgRects); + + +}// ~FaceDetection() + +void FaceDetection::FindContours(IplImage* imgGray) +{ + ReallocImage(&m_imgThresh, cvGetSize(imgGray), 1); + if (NULL == m_imgThresh) + return; + // + int iNumLayers = m_iNumLayers; + int iMinLevel = 0, iMaxLevel = 255, iStep = 255 / iNumLayers; + ThresholdingParam(imgGray, iNumLayers, iMinLevel, iMaxLevel, iStep); + // init + cvReleaseMemStorage(&m_mstgContours); + m_mstgContours = cvCreateMemStorage(); + if (NULL == m_mstgContours) + return; + memset(m_seqContours, 0, sizeof(CvSeq*) * MAX_LAYERS); + + cvReleaseMemStorage(&m_mstgRects); + m_mstgRects = cvCreateMemStorage(); + if (NULL == m_mstgRects) + return; + m_seqRects = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvContourRect), m_mstgRects); + if (NULL == m_seqRects) + return; + // find contours + for (int l = iMinLevel, i = 0; l < iMaxLevel; l += iStep, i++) + { + cvThreshold(imgGray, m_imgThresh, (double)l, (double)255, CV_THRESH_BINARY); + if (cvFindContours(m_imgThresh, m_mstgContours, &m_seqContours[i], sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE)) + AddContours2Rect(m_seqContours[i], l, i); + } + // sort rects + cvSeqSort(m_seqRects, CompareContourRect, NULL); +}// void FaceDetection::FindContours(IplImage* imgGray) + +#define GIST_STEP 10 +#define GIST_NUM (256 / GIST_STEP) +#define GIST_MIN 32 + +void FaceDetection::ThresholdingParam(IplImage *imgGray, int iNumLayers, int &iMinLevel, int &iMaxLevel, int &iStep) +{ + assert(imgGray != NULL); + assert(imgGray->nChannels == 1); + int i, j; + // create gistogramm + uchar* buffImg = (uchar*)imgGray->imageData; + int gistImg[GIST_NUM + 1] = {0}; + + for (j = 0; j < imgGray->height; j ++) + { + for (i = 0; i < imgGray->width; i ++) + { + int ind = buffImg[i] / GIST_STEP; + gistImg[ind] ++; + } + buffImg += imgGray->widthStep; + } + // params + + for (i = 0; i <= GIST_NUM; i ++) + { + if (gistImg[i] >= GIST_MIN) + break; + } + + iMinLevel = i * GIST_STEP; + + for (i = GIST_NUM; i >= 0; i --) + { + if (gistImg[i] >= GIST_MIN) + break; + } + + iMaxLevel = i * GIST_STEP; + + int dLevels = iMaxLevel - iMinLevel; + if (dLevels <= 0) + { + iMinLevel = 0; + iMaxLevel = 255; + } + else if (dLevels <= iNumLayers) + { + iMinLevel = iMaxLevel - iNumLayers; + if (iMinLevel < 0) + { + iMinLevel = 0; + iMaxLevel = iNumLayers; + } + } + iStep = (iMaxLevel - iMinLevel) / iNumLayers; + +}// void FaceDetection::ThresholdingParam(IplImage *imgGray, int iNumLayers, int &iMinLevel, int &iMaxLevel, int &iStep) + +#ifndef MAX_ERROR +#define MAX_ERROR 0xFFFFFFFF +#endif //MAX_ERROR + + +void FaceDetection::CreateResults(CvSeq * lpSeq) +{ + + Face * tmp; + + double Max = 0; + double CurStat = 0; + + FaceData tmpData; + if (m_bBoosting) + { + tmp = m_pFaceList->GetData(); + tmp->CreateFace(&tmpData); + + CvFace tmpFace; + tmpFace.MouthRect = tmpData.MouthRect; + tmpFace.LeftEyeRect = tmpData.LeftEyeRect; + tmpFace.RightEyeRect = tmpData.RightEyeRect; + + cvSeqPush(lpSeq,&tmpFace); + + }else + { + while ( (tmp = m_pFaceList->GetData()) != 0 ) + { + CurStat = tmp->GetWeight(); + if (CurStat > Max) + Max = CurStat; + } + + while ( (tmp = m_pFaceList->GetData()) != 0 ) + { + tmp->CreateFace(&tmpData); + CurStat = tmp->GetWeight(); + + if (CurStat == Max) + { + CvFace tmpFace; + tmpFace.MouthRect = tmpData.MouthRect; + tmpFace.LeftEyeRect = tmpData.LeftEyeRect; + tmpFace.RightEyeRect = tmpData.RightEyeRect; + cvSeqPush(lpSeq,&tmpFace); + + + } + } + } +}// void FaceDetection::DrawResult(IplImage* img) + +void FaceDetection::ResetImage() +{ + delete m_pFaceList; + m_pFaceList = new List(); + +}//FaceDetection::ResetImage + +void FaceDetection::AddContours2Rect(CvSeq *seq, int color, int iLayer) +{ + assert(m_mstgRects != NULL); + assert(m_seqRects != NULL); + + CvContourRect cr; + for (CvSeq* external = seq; external; external = external->h_next) + { + cr.r = cvContourBoundingRect(external, 1 ); + cr.pCenter.x = cr.r.x + cr.r.width / 2; + cr.pCenter.y = cr.r.y + cr.r.height / 2; + cr.iNumber = iLayer; + cr.iType = 6; + cr.iFlags = 0; + cr.seqContour = external; + cr.iContourLength = external->total; + cr.iColor = color; + cvSeqPush(m_seqRects, &cr); + for (CvSeq* internal = external->v_next; internal; internal = internal->h_next) + { + cr.r = cvContourBoundingRect(internal, 0); + cr.pCenter.x = cr.r.x + cr.r.width / 2; + cr.pCenter.y = cr.r.y + cr.r.height / 2; + cr.iNumber = iLayer; + cr.iType = 12; + cr.iFlags = 0; + cr.seqContour = internal; + cr.iContourLength = internal->total; + cr.iColor = color; + cvSeqPush(m_seqRects, &cr); + } + } +}// void FaceDetection::AddContours2Rect(CvSeq *seq, int color, int iLayer) + +int CV_CDECL CompareContourRect(const void* el1, const void* el2, void* /*userdata*/) +{ + return (((CvContourRect*)el1)->pCenter.y - ((CvContourRect*)el2)->pCenter.y); +}// int CV_CDECL CompareContourRect(const void* el1, const void* el2, void* userdata) + +void FaceDetection::FindFace(IplImage *img) +{ + // find all contours + FindContours(img); + // + ResetImage(); + + if (m_bBoosting) + PostBoostingFindCandidats(img); + else + FindCandidats(); + +}// void FaceDetection::FindFace(IplImage *img) + + +void FaceDetection::FindCandidats() +{ + bool bFound1 = false; + MouthFaceTemplate * lpFaceTemplate1; + RFace * lpFace1; + bool bInvalidRect1 = false; + CvRect * lpRect1 = NULL; + + for (int i = 0; i < m_seqRects->total; i++) + { + CvContourRect* pRect = (CvContourRect*)cvGetSeqElem(m_seqRects, i); + CvRect rect = pRect->r; + if (rect.width >= 2*rect.height) + { + + lpFaceTemplate1 = new MouthFaceTemplate(3,rect,3*(double)rect.width/(double)4, + 3*(double)rect.width/(double)4, + (double)rect.width/(double)2, + (double)rect.width/(double)2); + + + lpFace1 = new RFace(lpFaceTemplate1); + + for (int j = 0; j < m_seqRects->total; j++) + { + CvContourRect* pRect = (CvContourRect*)cvGetSeqElem(m_seqRects, j); + + if ( !bInvalidRect1 ) + { + lpRect1 = NULL; + lpRect1 = new CvRect(); + *lpRect1 = pRect->r; + }else + { + delete lpRect1; + lpRect1 = new CvRect(); + *lpRect1 = pRect->r; + } + + + if ( lpFace1->isFeature(lpRect1) ) + { + bFound1 = true; + bInvalidRect1 = false; + }else + bInvalidRect1 = true; + + + } + + + if (bFound1) + { + m_pFaceList->AddElem(lpFace1); + bFound1 = false; + lpFace1 = NULL; + }else + { + delete lpFace1; + lpFace1 = NULL; + } + + + delete lpFaceTemplate1; + } + + } + +} + + +void FaceDetection::PostBoostingFindCandidats(IplImage * FaceImage) +{ + BoostingFaceTemplate * lpFaceTemplate1; + RFace * lpFace1; + bool bInvalidRect1 = false; + CvRect * lpRect1 = NULL; + + if ( ( !FaceImage->roi ) ) + lpFaceTemplate1 = new BoostingFaceTemplate(3,cvRect(0,0,FaceImage->width,FaceImage->height)); + else + lpFaceTemplate1 = new BoostingFaceTemplate(3,cvRect(FaceImage->roi->xOffset,FaceImage->roi->yOffset, + FaceImage->roi->width,FaceImage->roi->height)); + + lpFace1 = new RFace(lpFaceTemplate1); + + for (int i = 0; i < m_seqRects->total; i++) + { + CvContourRect* pRect = (CvContourRect*)cvGetSeqElem(m_seqRects, i); + + if ( !bInvalidRect1 ) + { + lpRect1 = NULL; + lpRect1 = new CvRect(); + *lpRect1 = pRect->r; + }else + { + delete lpRect1; + lpRect1 = new CvRect(); + *lpRect1 = pRect->r; + } + + + if ( lpFace1->isFeature(lpRect1) ) + { + //bFound1 = true; + bInvalidRect1 = false; + }else + bInvalidRect1 = true; + + + } + + m_pFaceList->AddElem(lpFace1); + + delete lpFaceTemplate1; + +}//void FaceDetection::PostBoostingFindCandidats(IplImage * FaceImage) + +///////////////////////// +//class Face + + + +////// +//List Class +///// +ListElem::ListElem() +{ + m_pNext = this; + m_pPrev = this; + m_pFace = NULL; +}///ListElem::ListElem() + +ListElem::ListElem(Face * pFace,ListElem * pHead) +{ + m_pNext = pHead; + m_pPrev = pHead->m_pPrev; + pHead->m_pPrev->m_pNext = this; + pHead->m_pPrev = this; + + m_pFace = pFace; +}//ListElem::ListElem(Face * pFace) + + + +ListElem::~ListElem() +{ + delete m_pFace; + m_pNext->m_pPrev = m_pPrev; + m_pPrev->m_pNext = m_pNext; + +}//ListElem::~ListElem() + +List::List() +{ + m_pHead = new ListElem(); + m_FacesCount = 0; + m_pCurElem = m_pHead; +}//List::List() + +List::~List() +{ + void * tmp; + while((tmp = m_pHead->m_pNext->m_pFace) != 0) + delete m_pHead->m_pNext; + + delete m_pHead; + +}//List::~List() + + +int List::AddElem(Face * pFace) +{ + new ListElem(pFace,m_pHead); + return m_FacesCount++; +}//List::AddElem(Face * pFace) + +Face * List::GetData() +{ + m_pCurElem = m_pCurElem->m_pNext; + return m_pCurElem->m_pFace; +}//Face * List::GetData() + +