肤色检测合集

来源:互联网 发布:韩语键盘软件 编辑:程序博客网 时间:2024/04/28 21:05

1 HSV 颜色空间

from: http://blog.csdn.net/onezeros/article/details/5930520

把rgb转换到hsv空间,用h分量 进行识别,像素值在7~29之间 是肤色的几乎全部范围

识别会受到光照的影响。但是整体上准确度是较高的。

在白天 正常的明亮的光照下,效果非常好。

这是我在晚上拍摄的一张图像的处理

肤色模型处理示例

对于不同的环境(主要是光照条件),阈值应相应 变动以提高精确度

程序源码下载 http://download.csdn.net/source/2744062


2 YCrCb


源码下下载 http://download.csdn.net/source/2873223

效果图


3 3种模型

今天是地球日,就选了张相关主题的图像做测试

 

第一种:RGB color space

第二种:RG color space

第三种:Ycrcb之cr分量+otsu阈值化

 

还有别的一些模型,效果不太好就不贴了

 

1.rgb model

[cpp] view plain copy
  1. // skin region location using rgb limitation  
  2. void SkinRGB(IplImage* rgb,IplImage* _dst)  
  3. {  
  4.     assert(rgb->nChannels==3&& _dst->nChannels==3);  
  5.   
  6.     static const int R=2;  
  7.     static const int G=1;  
  8.     static const int B=0;  
  9.   
  10.     IplImage* dst=cvCreateImage(cvGetSize(_dst),8,3);  
  11.     cvZero(dst);  
  12.   
  13.     for (int h=0;h<rgb->height;h++) {  
  14.         unsigned char* prgb=(unsigned char*)rgb->imageData+h*rgb->widthStep;  
  15.         unsigned char* pdst=(unsigned char*)dst->imageData+h*dst->widthStep;  
  16.         for (int w=0;w<rgb->width;w++) {  
  17.             if ((prgb[R]>95 && prgb[G]>40 && prgb[B]>20 &&  
  18.                 prgb[R]-prgb[B]>15 && prgb[R]-prgb[G]>15/*&& 
  19.                 !(prgb[R]>170&&prgb[G]>170&&prgb[B]>170)*/)||//uniform illumination   
  20.                 (prgb[R]>200 && prgb[G]>210 && prgb[B]>170 &&  
  21.                 abs(prgb[R]-prgb[B])<=15 && prgb[R]>prgb[B]&& prgb[G]>prgb[B])//lateral illumination  
  22.                 ) {  
  23.                     memcpy(pdst,prgb,3);  
  24.             }             
  25.             prgb+=3;  
  26.             pdst+=3;  
  27.         }  
  28.     }  
  29.     cvCopyImage(dst,_dst);  
  30.     cvReleaseImage(&dst);  
  31. }  

 

2.rg model

[cpp] view plain copy
  1. // skin detection in rg space  
  2. void cvSkinRG(IplImage* rgb,IplImage* gray)  
  3. {  
  4.     assert(rgb->nChannels==3&&gray->nChannels==1);  
  5.       
  6.     const int R=2;  
  7.     const int G=1;  
  8.     const int B=0;  
  9.   
  10.     double Aup=-1.8423;  
  11.     double Bup=1.5294;  
  12.     double Cup=0.0422;  
  13.     double Adown=-0.7279;  
  14.     double Bdown=0.6066;  
  15.     double Cdown=0.1766;  
  16.     for (int h=0;h<rgb->height;h++) {  
  17.         unsigned char* pGray=(unsigned char*)gray->imageData+h*gray->widthStep;  
  18.         unsigned char* pRGB=(unsigned char* )rgb->imageData+h*rgb->widthStep;  
  19.         for (int w=0;w<rgb->width;w++) {  
  20.             int s=pRGB[R]+pRGB[G]+pRGB[B];  
  21.             double r=(double)pRGB[R]/s;  
  22.             double g=(double)pRGB[G]/s;  
  23.             double Gup=Aup*r*r+Bup*r+Cup;  
  24.             double Gdown=Adown*r*r+Bdown*r+Cdown;  
  25.             double Wr=(r-0.33)*(r-0.33)+(g-0.33)*(g-0.33);  
  26.             if (g<Gup && g>Gdown && Wr>0.004){  
  27.                 *pGray=255;  
  28.             }else{   
  29.                 *pGray=0;  
  30.             }  
  31.             pGray++;  
  32.             pRGB+=3;  
  33.         }  
  34.     }  
  35.   
  36. }  

 

3.cr+otsu

[c-sharp] view plain copy
  1. // implementation of otsu algorithm  
  2. // author: onezeros#yahoo.cn  
  3. // reference: Rafael C. Gonzalez. Digital Image Processing Using MATLAB  
  4. void cvThresholdOtsu(IplImage* src, IplImage* dst)  
  5. {  
  6.     int height=src->height;  
  7.     int width=src->width;  
  8.   
  9.     //histogram  
  10.     float histogram[256]={0};  
  11.     for(int i=0;i<height;i++) {  
  12.         unsigned char* p=(unsigned char*)src->imageData+src->widthStep*i;  
  13.         for(int j=0;j<width;j++) {  
  14.             histogram[*p++]++;  
  15.         }  
  16.     }  
  17.     //normalize histogram  
  18.     int size=height*width;  
  19.     for(int i=0;i<256;i++) {  
  20.         histogram[i]=histogram[i]/size;  
  21.     }  
  22.   
  23.     //average pixel value  
  24.     float avgValue=0;  
  25.     for(int i=0;i<256;i++) {  
  26.         avgValue+=i*histogram[i];  
  27.     }  
  28.   
  29.     int threshold;    
  30.     float maxVariance=0;  
  31.     float w=0,u=0;  
  32.     for(int i=0;i<256;i++) {  
  33.         w+=histogram[i];  
  34.         u+=i*histogram[i];  
  35.   
  36.         float t=avgValue*w-u;  
  37.         float variance=t*t/(w*(1-w));  
  38.         if(variance>maxVariance) {  
  39.             maxVariance=variance;  
  40.             threshold=i;  
  41.         }  
  42.     }  
  43.   
  44.     cvThreshold(src,dst,threshold,255,CV_THRESH_BINARY);  
  45. }  
  46.   
  47. void cvSkinOtsu(IplImage* src, IplImage* dst)  
  48. {  
  49.     assert(dst->nChannels==1&& src->nChannels==3);  
  50.   
  51.     IplImage* ycrcb=cvCreateImage(cvGetSize(src),8,3);  
  52.     IplImage* cr=cvCreateImage(cvGetSize(src),8,1);  
  53.     cvCvtColor(src,ycrcb,CV_BGR2YCrCb);  
  54.     cvSplit(ycrcb,0,cr,0,0);  
  55.   
  56.     cvThresholdOtsu(cr,cr);  
  57.     cvCopyImage(cr,dst);  
  58.     cvReleaseImage(&cr);  
  59.     cvReleaseImage(&ycrcb);  
  60. }  

 

原图像

 

rgb model

 

rg model

 

otsu+cr

4 RGB YCrCb


本文涉及的很多算法,在网络上也有不少同类型的文章,但是肯定的一点就是,很多都是不配代码的,或者所附带的代码都是象征性的,速度慢,不优雅,不具有实用价值,本文努力解决这些问题。

      文中各算法出现的顺序并不代表算法的优越性,仅仅是作者随机排布的而已。

      2、基于RGB颜色空间的简单阈值肤色识别

       在human skin color clustering for face detection一文中提出如下简单的判别算式:

      R>95 And G>40 And B>20 And R>G And R>B And Max(R,G,B)-Min(R,G,B)>15 And Abs(R-G)>15 

    算法非常之简单,同样主要把复杂的判断条件放到后面去判断,能有效的降低程序的执行时间,参考代码:

 

复制代码
for (Y = 0; Y < Height; Y++){    Pointer = Scan0 + Y * Stride;    SkinP = SkinScan0 + Y * SkinStride;    for (X = 0; X < Width; X++)    {        Blue = *Pointer; Green = *(Pointer + 1); Red = *(Pointer + 2);        if (Red > 95 && Green > 40 && Blue > 20 && Red > Blue && Red > Green && Math.Abs(Red - Green) > 15)        {            if (Blue >= Green)                 {                Max = Blue;                Min = Green;            }            else            {                Max = Green;                Min = Blue;            }            if (Red > Max)                Max = Red;            else if (Red < Min)                Min = Red;            if (Max - Min > 15) *SkinP = 255;        }        Pointer += 3;        SkinP++;    }
复制代码

  算法效果:

               

        原图                     识别结果图                                                   原图                识别结果图

     由上述结果似乎该算法得到了过多的皮肤区域,然后就是算法更喜欢美女一些(^_^)。

     3、基于YCbCr颜色空间的简单阈值肤色识别

  该算法则更为简单,将图像转换到YCbCr颜色空间,然后按下述计算式判断是否属于皮肤区域:

    (Cb > 77 And Cb < 127)  And (Cr > 133 And Cr < 173)

      关于RGB和YCbCr颜色空间的转换的优化算法,可参考本博客相关文章。

      由于当初写这方面的时候没有注明该算法的出处,现在也没从提起了。

      代码参考:

for (Y = 0; Y < Height; Y++){    Pointer = Scan0 + Y * Stride;    SkinP = SkinScan0 + Y * SkinStride;    for (X = 0; X < Width; X++)    {        Blue = *Pointer; Green = *(Pointer + 1); Red = *(Pointer + 2);        Cb = (-176933 * Red - 347355 * Green + 524288 * Blue + 134217728) >> 20;        if (Cb > 77 && Cb < 127)        {            Cr = (524288 * Red - 439026 * Green - 85262 * Blue + 134217728) >> 20;            if (Cr > 133 && Cr < 173) *SkinP = 255;        }        Pointer += 3;        SkinP++;    }}

 

      

 

                

              原图                         识别结果图                                                   原图                识别结果图

     误判的区域还是很大的。

     还有一种是基于YUV颜色空间进行的肤色识别,似乎也不太准确,可参考http://www.doc88.com/p-97381067005.html。




0 0