1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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, copy or use the software.
8 // Copyright (C) 2009, Farhad Dadgostar
9 // Intel Corporation and third party copyrights are property of their respective owners.
11 // Redistribution and use in source and binary forms, with or without modification,
12 // are permitted provided that the following conditions are met:
14 // * Redistribution's of source code must retain the above copyright notice,
15 // this list of conditions and the following disclaimer.
17 // * Redistribution's in binary form must reproduce the above copyright notice,
18 // this list of conditions and the following disclaimer in the documentation
19 // and/or other materials provided with the distribution.
21 // * The name of Intel Corporation may not be used to endorse or promote products
22 // derived from this software without specific prior written permission.
24 // This software is provided by the copyright holders and contributors "as is" and
25 // any express or implied warranties, including, but not limited to, the implied
26 // warranties of merchantability and fitness for a particular purpose are disclaimed.
27 // In no event shall the Intel Corporation or contributors be liable for any direct,
28 // indirect, incidental, special, exemplary, or consequential damages
29 // (including, but not limited to, procurement of substitute goods or services;
30 // loss of use, data, or profits; or business interruption) however caused
31 // and on any theory of liability, whether in contract, strict liability,
32 // or tort (including negligence or otherwise) arising in any way out of
33 // the use of this software, even if advised of the possibility of such damage.
37 #include "precomp.hpp"
38 #include "opencv2/imgproc/imgproc_c.h"
39 #include "opencv2/contrib/compat.hpp"
41 #define ASD_INTENSITY_SET_PIXEL(pointer, qq) {(*pointer) = (unsigned char)qq;}
43 #define ASD_IS_IN_MOTION(pointer, v, threshold) ((abs((*(pointer)) - (v)) > (threshold)) ? true : false)
45 void CvAdaptiveSkinDetector::initData(IplImage *src, int widthDivider, int heightDivider)
47 CvSize imageSize = cvSize(src->width/widthDivider, src->height/heightDivider);
49 imgHueFrame = cvCreateImage(imageSize, IPL_DEPTH_8U, 1);
50 imgShrinked = cvCreateImage(imageSize, IPL_DEPTH_8U, src->nChannels);
51 imgSaturationFrame = cvCreateImage(imageSize, IPL_DEPTH_8U, 1);
52 imgMotionFrame = cvCreateImage(imageSize, IPL_DEPTH_8U, 1);
53 imgTemp = cvCreateImage(imageSize, IPL_DEPTH_8U, 1);
54 imgFilteredFrame = cvCreateImage(imageSize, IPL_DEPTH_8U, 1);
55 imgGrayFrame = cvCreateImage(imageSize, IPL_DEPTH_8U, 1);
56 imgLastGrayFrame = cvCreateImage(imageSize, IPL_DEPTH_8U, 1);
57 imgHSVFrame = cvCreateImage(imageSize, IPL_DEPTH_8U, 3);
60 CvAdaptiveSkinDetector::CvAdaptiveSkinDetector(int samplingDivider, int morphingMethod)
62 nSkinHueLowerBound = GSD_HUE_LT;
63 nSkinHueUpperBound = GSD_HUE_UT;
65 fHistogramMergeFactor = 0.05; // empirical result
66 fHuePercentCovered = 0.95; // empirical result
68 nMorphingMethod = morphingMethod;
69 nSamplingDivider = samplingDivider;
75 imgMotionFrame = NULL;
77 imgFilteredFrame = NULL;
80 imgLastGrayFrame = NULL;
81 imgSaturationFrame = NULL;
85 CvAdaptiveSkinDetector::~CvAdaptiveSkinDetector()
87 cvReleaseImage(&imgHueFrame);
88 cvReleaseImage(&imgSaturationFrame);
89 cvReleaseImage(&imgMotionFrame);
90 cvReleaseImage(&imgTemp);
91 cvReleaseImage(&imgFilteredFrame);
92 cvReleaseImage(&imgShrinked);
93 cvReleaseImage(&imgGrayFrame);
94 cvReleaseImage(&imgLastGrayFrame);
95 cvReleaseImage(&imgHSVFrame);
98 void CvAdaptiveSkinDetector::process(IplImage *inputBGRImage, IplImage *outputHueMask)
100 IplImage *src = inputBGRImage;
107 if (imgHueFrame == NULL)
110 initData(src, nSamplingDivider, nSamplingDivider);
113 unsigned char *pShrinked, *pHueFrame, *pMotionFrame, *pLastGrayFrame, *pFilteredFrame, *pGrayFrame;
114 pShrinked = (unsigned char *)imgShrinked->imageData;
115 pHueFrame = (unsigned char *)imgHueFrame->imageData;
116 pMotionFrame = (unsigned char *)imgMotionFrame->imageData;
117 pLastGrayFrame = (unsigned char *)imgLastGrayFrame->imageData;
118 pFilteredFrame = (unsigned char *)imgFilteredFrame->imageData;
119 pGrayFrame = (unsigned char *)imgGrayFrame->imageData;
121 if ((src->width != imgHueFrame->width) || (src->height != imgHueFrame->height))
123 cvResize(src, imgShrinked);
124 cvCvtColor(imgShrinked, imgHSVFrame, CV_BGR2HSV);
128 cvCvtColor(src, imgHSVFrame, CV_BGR2HSV);
131 cvSplit(imgHSVFrame, imgHueFrame, imgSaturationFrame, imgGrayFrame, 0);
133 cvSetZero(imgMotionFrame);
134 cvSetZero(imgFilteredFrame);
136 l = imgHueFrame->height * imgHueFrame->width;
138 for (i = 0; i < l; i++)
141 if ((v >= GSD_INTENSITY_LT) && (v <= GSD_INTENSITY_UT))
144 if ((h >= GSD_HUE_LT) && (h <= GSD_HUE_UT))
146 if ((h >= nSkinHueLowerBound) && (h <= nSkinHueUpperBound))
147 ASD_INTENSITY_SET_PIXEL(pFilteredFrame, h);
149 if (ASD_IS_IN_MOTION(pLastGrayFrame, v, 7))
150 ASD_INTENSITY_SET_PIXEL(pMotionFrame, h);
162 cvCalcHist(&imgHueFrame, skinHueHistogram.fHistogram);
164 cvCopy(imgGrayFrame, imgLastGrayFrame);
166 cvErode(imgMotionFrame, imgTemp); // eliminate disperse pixels, which occur because of the camera noise
167 cvDilate(imgTemp, imgMotionFrame);
169 cvCalcHist(&imgMotionFrame, histogramHueMotion.fHistogram);
171 skinHueHistogram.mergeWith(&histogramHueMotion, fHistogramMergeFactor);
173 skinHueHistogram.findCurveThresholds(nSkinHueLowerBound, nSkinHueUpperBound, 1 - fHuePercentCovered);
175 switch (nMorphingMethod)
177 case MORPHING_METHOD_ERODE :
178 cvErode(imgFilteredFrame, imgTemp);
179 cvCopy(imgTemp, imgFilteredFrame);
181 case MORPHING_METHOD_ERODE_ERODE :
182 cvErode(imgFilteredFrame, imgTemp);
183 cvErode(imgTemp, imgFilteredFrame);
185 case MORPHING_METHOD_ERODE_DILATE :
186 cvErode(imgFilteredFrame, imgTemp);
187 cvDilate(imgTemp, imgFilteredFrame);
191 if (outputHueMask != NULL)
192 cvCopy(imgFilteredFrame, outputHueMask);
196 //------------------------- Histogram for Adaptive Skin Detector -------------------------//
198 CvAdaptiveSkinDetector::Histogram::Histogram()
200 int histogramSize[] = { HistogramSize };
201 float range[] = { GSD_HUE_LT, GSD_HUE_UT };
202 float *ranges[] = { range };
203 fHistogram = cvCreateHist(1, histogramSize, CV_HIST_ARRAY, ranges, 1);
204 cvClearHist(fHistogram);
207 CvAdaptiveSkinDetector::Histogram::~Histogram()
209 cvReleaseHist(&fHistogram);
212 int CvAdaptiveSkinDetector::Histogram::findCoverageIndex(double surfaceToCover, int defaultValue)
215 for (int i = 0; i < HistogramSize; i++)
217 s += cvGetReal1D( fHistogram->bins, i );
218 if (s >= surfaceToCover)
226 void CvAdaptiveSkinDetector::Histogram::findCurveThresholds(int &x1, int &x2, double percent)
230 for (int i = 0; i < HistogramSize; i++)
232 sum += cvGetReal1D( fHistogram->bins, i );
235 x1 = findCoverageIndex(sum * percent, -1);
236 x2 = findCoverageIndex(sum * (1-percent), -1);
249 void CvAdaptiveSkinDetector::Histogram::mergeWith(CvAdaptiveSkinDetector::Histogram *source, double weight)
251 float myweight = (float)(1-weight);
252 float maxVal1 = 0, maxVal2 = 0, *f1, *f2, ff1, ff2;
254 cvGetMinMaxHistValue(source->fHistogram, NULL, &maxVal2);
258 cvGetMinMaxHistValue(fHistogram, NULL, &maxVal1);
261 for (int i = 0; i < HistogramSize; i++)
263 f1 = (float*)cvPtr1D(fHistogram->bins, i);
264 f2 = (float*)cvPtr1D(source->fHistogram->bins, i);
270 for (int i = 0; i < HistogramSize; i++)
272 f1 = (float*)cvPtr1D(fHistogram->bins, i);
273 f2 = (float*)cvPtr1D(source->fHistogram->bins, i);
275 ff1 = ((*f1)/maxVal1)*myweight;
279 ff2 = (float)(((*f2)/maxVal2)*weight);