///////////////////////////////////////////////////////////////////////////// // Name: crvskindetection.cpp // Purpose: // Author: Cesar Mauri Loba (cesar at crea-si dot com) // Modified by: // Created: 23/02/2008 // Copyright: (C) 2008 Cesar Mauri Loba - CREA Software Systems // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . ///////////////////////////////////////////////////////////////////////////// #include "crvmisc.h" #include "crvskindetection.h" #include #include void CSkinRegionModel::crvBinarizeSkin_KToyama (IplImage *pIpl, float &krg_min, float &krg_max, float &krb_min, float &krb_max) { int x, y, xIni, yIni, xLim, yLim; float krg, krb; unsigned char *pSrc; assert (pIpl); crvGetROILimits (pIpl, xIni, yIni, xLim, yLim); for (y= yIni; y< yLim; y++) { pSrc= (unsigned char *) crvImgOffset (pIpl, xIni, y); for (x= xIni; x< xLim; x++) { krg= (float) pSrc[0] / (float) pSrc[1]; krb= (float) pSrc[0] / (float) pSrc[2]; if (krg_min<= krg && krg_max>= krg && krb_min<= krb && krb_max>= krb) { pSrc[0]= pSrc[1]= pSrc[2]= 255; } else pSrc[0]= pSrc[1]= pSrc[2]= 0; pSrc+= 4; } } } // // Skin Models Definition // #define min(x,y) (x< y? x : y) #define max(x,y) (x> y? x : y) #define min3(x,y,z) (min(min(x,y),z)) #define max3(x,y,z) (max(max(x,y),z)) // The skin colour at uniform daylight illumination #define IS_SKIN_PEER(R,G,B) (R> 95 && G> 40 && B> 20 && R> G && R> B && \ (max3(R,G,B) - min3(R,G,B))> 15 && \ ((R-G)> 15 || (G-R)> 15)) // The skin colour under flashlight or (light) daylight // lateral illumination #define IS_SKIN_PEER2(R,G,B) (R> 220 && G> 210 && B> 170 && \ ((R-G)< 15 || (G-R)< 15) && \ R> B && G> B) inline bool IsSkin_GomezMorales_1 (int R, int G, int B) { float r, g, b, rgb, rgb2; r= (float) R / 255.0f; g= (float) G / 255.0f; b= (float) B / 255.0f; rgb= r + g + b; rgb2= rgb * rgb; return ( ((r/g)> 1.185) && (((r*b)/rgb2)> 0.107) && (((r*g)/rgb2)> 0.112) ); } inline bool IsSkin_GomezMorales_2 (int R, int G, int B) { float r, g, b, rgb; r= (float) R / 255.0f; g= (float) G / 255.0f; b= (float) B / 255.0f; rgb= r + g + b; return ( (b/g)< 1.249 && (rgb / (3*r))> 0.696 && ((1.0/3.0) - (b/rgb))> 0.014 && (g / (3*rgb))< 0.108 ); } void CSkinRegionModel::crvBinarizeSkin (IplImage *pSrc, IplImage *pDst) { int x, y, xIni, yIni, xLim, yLim, srcBytesPPixel, dstBytesPPixel; unsigned char *pSrcB, *pDstB; bool isBGR= false; assert (pSrc && pSrc->imageData && pDst && pDst->imageData); if (!strncmp (pSrc->channelSeq, "BGR", 4) || !strncmp (pSrc->channelSeq, "BGRA", 4)) isBGR= true; else if (!strncmp (pSrc->channelSeq, "RGB", 4) || !strncmp (pSrc->channelSeq, "RGBA", 4)) isBGR= false; else assert (false); assert (!strncmp (pDst->channelSeq, "GRAY", 4) || !strncmp (pDst->channelSeq, "BGRA", 4)); // Get depth srcBytesPPixel= pSrc->nChannels; dstBytesPPixel= pDst->depth / 8; cvSetZero(pDst); crvGetROILimits (pSrc, xIni, yIni, xLim, yLim); if (isBGR) for (y= yIni; y< yLim; y++) { pSrcB= (unsigned char *) crvImgOffset (pSrc, xIni, y); pDstB= (unsigned char *) crvImgOffset (pDst, xIni, y); for (x= xIni; x< xLim; x++) { if (IS_SKIN_PEER(pSrcB[2],pSrcB[1],pSrcB[0])) { // Color acceptat pDstB[0]= 255; if (dstBytesPPixel> 1) { pDstB[1]= 255; if (dstBytesPPixel> 2) { pDstB[2]= 255; } } } pSrcB+= srcBytesPPixel; pDstB+= dstBytesPPixel; } } else for (y= yIni; y< yLim; y++) { pSrcB= (unsigned char *) crvImgOffset (pSrc, xIni, y); pDstB= (unsigned char *) crvImgOffset (pDst, xIni, y); for (x= xIni; x< xLim; x++) { if (IS_SKIN_PEER(pSrcB[0],pSrcB[1],pSrcB[2])) { // Color acceptat pDstB[0]= 255; if (dstBytesPPixel> 1) { pDstB[1]= 255; if (dstBytesPPixel> 2) { pDstB[2]= 255; } } } pSrcB+= srcBytesPPixel; pDstB+= dstBytesPPixel; } } }