zoukankan      html  css  js  c++  java
  • 提取肤色信息原理及操作——opencv

       网上也有很多的资料,讲述怎么提取肤色的,大致有5种方法。这几种方法转载http://blog.csdn.net/augusdi/article/details/8865275

    第一种:RGB color space

    第二种:RG color space

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

    第四种:YCrCb中133<=Cr<=173 77<=Cb<=127

    第五种:HSV中 7<H<29

        我来讲述一下提取肤色的原理。

    这几种方法都不外乎一种操作,首先将图像的各个通道分离出来,如RGB  RG Ycrcb以及HSV几种单通道,然后对在各种通道上的数据分析,数据在一定范围内的图像提取出来,其余的数据都赋值0,这其实就是所谓的阈值处理,然而这个阈值会对光照,背景甚至摄像头的性能的影响,需要自己调整参数。

    示例1:使用了opencv的cvInRangeS函数处理各个通道的数据,因为摄像头不好所以使用了高斯模糊以平滑图像,最后各处理后的通道图像按位与,合成一个图像。

    void CAIGesture::SkinDetect(IplImage* src,IplImage* dst)
    {
        IplImage* hsv = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 3);//用于存图像的一个中间变量,是用来分通道用的,分成hsv通道
        IplImage* tmpH1 = cvCreateImage( cvGetSize(src), IPL_DEPTH_8U, 1);//通道的中间变量,用于肤色检测的中间变量
        IplImage* tmpS1 = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
        IplImage* tmpH2 = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
        IplImage* tmpS3 = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
        IplImage* tmpH3 = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
        IplImage* tmpS2 = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
        IplImage* H = cvCreateImage( cvGetSize(src), IPL_DEPTH_8U, 1);
        IplImage* S = cvCreateImage( cvGetSize(src), IPL_DEPTH_8U, 1);
        IplImage* V = cvCreateImage( cvGetSize(src), IPL_DEPTH_8U, 1);   
        IplImage* src_tmp1=cvCreateImage(cvGetSize(src),8,3);
        cvSmooth(src,src_tmp1,CV_GAUSSIAN,3,3);    //高斯模糊
        cvCvtColor(src_tmp1, hsv, CV_BGR2HSV );//颜色转换
        cvCvtPixToPlane(hsv,H,S,V,0);//分为3个通道
    /*********************肤色检测部分**************/
        cvInRangeS(H,cvScalar(0.0,0.0,0,0),cvScalar(20.0,0.0,0,0),tmpH1);
        cvInRangeS(S,cvScalar(75.0,0.0,0,0),cvScalar(200.0,0.0,0,0),tmpS1);
        cvAnd(tmpH1,tmpS1,tmpH1,0);
        // Red Hue with Low Saturation
        // Hue 0 to 26 degree and Sat 20 to 90
        cvInRangeS(H,cvScalar(0.0,0.0,0,0),cvScalar(13.0,0.0,0,0),tmpH2);
        cvInRangeS(S,cvScalar(20.0,0.0,0,0),cvScalar(90.0,0.0,0,0),tmpS2);
        cvAnd(tmpH2,tmpS2,tmpH2,0);

        // Red Hue to Pink with Low Saturation
        // Hue 340 to 360 degree and Sat 15 to 90
        cvInRangeS(H,cvScalar(170.0,0.0,0,0),cvScalar(180.0,0.0,0,0),tmpH3);
        cvInRangeS(S,cvScalar(15.0,0.0,0,0),cvScalar(90.,0.0,0,0),tmpS3);
        cvAnd(tmpH3,tmpS3,tmpH3,0);

        // Combine the Hue and Sat detections
        cvOr(tmpH3,tmpH2,tmpH2,0);
        cvOr(tmpH1,tmpH2,tmpH1,0);

        cvCopy(tmpH1,dst);

    }

    示例2:

    主要原理就是通过在Cb Cr空间上找到一个可以拟合常规肤色分布的椭圆形,然后把在椭圆形区域内的像素点标记为肤色。

    其实代码很简单,就是把Y Cb Cr三个通道分开,然后用指针分别对这三个通道的每一个像素进行处理。

    需要作修改的就是if(y<100) (*pMask)=(value<700) ? 255:0; else (*pMask)=(value<850)? 255:0; 这条做阈值判断的命令

    1. void cvSkinSegment(IplImage* img, IplImage* mask){ 
    2.     CvSize imageSize = cvSize(img->width, img->height); 
    3.     IplImage *imgY = cvCreateImage(imageSize, IPL_DEPTH_8U, 1); 
    4.     IplImage *imgCr = cvCreateImage(imageSize, IPL_DEPTH_8U, 1); 
    5.     IplImage *imgCb = cvCreateImage(imageSize, IPL_DEPTH_8U, 1); 
    6.     IplImage *imgYCrCb = cvCreateImage(imageSize, img->depth, img->nChannels); 
    7.     cvCvtColor(img,imgYCrCb,CV_BGR2YCrCb); 
    8.     cvSplit(imgYCrCb, imgY, imgCr, imgCb, 0); 
    9.     int y, cr, cb, l, x1, y1, value; 
    10.     unsigned char *pY, *pCr, *pCb, *pMask; 
    11.     pY = (unsigned char *)imgY->imageData; 
    12.     pCr = (unsigned char *)imgCr->imageData; 
    13.     pCb = (unsigned char *)imgCb->imageData; 
    14.     pMask = (unsigned char *)mask->imageData; 
    15.     cvSetZero(mask); 
    16.     l = img->height * img->width; 
    17. for (int i = 0; i < l; i++){ 
    18.         y  = *pY; 
    19.         cr = *pCr; 
    20.         cb = *pCb; 
    21.         cb -= 109; 
    22.         cr -= 152 
    23.             ; 
    24.         x1 = (819*cr-614*cb)/32 + 51; 
    25.         y1 = (819*cr+614*cb)/32 + 77; 
    26.         x1 = x1*41/1024; 
    27.         y1 = y1*73/1024; 
    28.         value = x1*x1+y1*y1; 
    29. if(y<100)    (*pMask)=(value<700) ? 255:0; 
    30. else        (*pMask)=(value<850)? 255:0; 
    31.         pY++; 
    32.         pCr++; 
    33.         pCb++; 
    34.         pMask++; 
    35.     } 
    36.     cvReleaseImage(&imgY); 
    37.     cvReleaseImage(&imgCr); 
    38.     cvReleaseImage(&imgCb); 
    39.     cvReleaseImage(&imgYCrCb); 
  • 相关阅读:
    通过JavaScript垃圾回收机制来理解WeakSet/WeakMap中对象的弱引用
    json处理
    dotenv 加载本地环境变量
    各种ast库
    类型检测库
    npm 加解密库
    用计算机语言的爱情表白
    情侣在招聘会上搂抱招致企业反感
    《软件性能测试与LoadRunner实战》网上订购问题
    F1赛车的起源
  • 原文地址:https://www.cnblogs.com/hedengfeng/p/3420119.html
Copyright © 2011-2022 走看看