• 基础学习笔记之opencv(21):一个简单有趣的皮肤检测代码


      前言 

      最近课题研究上想采用皮肤信息,但是个人总是对皮肤信息应用在目标检测和目标识别上有排斥,认为皮肤信息完全不足以胜任这个工作。其实计算机视觉的最终实现是一个长期的过程,是AI领域一个经典的问题,所以在AI完全突破之前,任何对CV有用的信息都值得去深入研究,除非有一种算法能够在所有情况下都工作。好了,废话不扯了,进入正题,有偏见但是还是得使用它。皮肤模型中有单高斯,混合高斯,贝叶斯模型和椭圆模型等。经过前人学者大量的皮肤统计信息可以知道,如果将皮肤信息映射到YCrCb空间,则在CrCb二维空间中这些皮肤像素点近似成一个椭圆分布。因此如果我们得到了一个CrCb的椭圆,下次来一个坐标(Cr, Cb)我们只需判断它是否在椭圆内(包括边界),如果是,则可以判断其为皮肤,否则就是非皮肤像素点。

      开发环境:OpenCV2.4.3+QtCreator2.5.1

      实验基础

      本实验是参考小短文A super-simple skin detector in OpenCV,该文章里面首先直接给出了一个比较合理的椭圆,即该椭圆能够代表大部分人的皮肤信息CrCb的分布。椭圆的分布如下:

      

      说它比较有趣是因为我们是用一副图像来存储上面的椭圆的,而不是直接采用椭圆数学方程。该图像是二值图像,即椭圆区域内部为白色,其它地方为黑色。所以当其需要判断其它像素点时,只需将该像素点转换成Cr,Cb两个坐标,然后在上面的椭圆中找到该坐标的值,如果非0,则为皮肤,反之亦然。

      在实际代码中,该椭圆是采用绘画函数绘制到图片上的,一句代码而已:

    ellipse(skinCrCbHist, Point(113, 155.6), Size(23.4, 15.2), 43.0, 0.0, 360.0, Scalar(255, 255, 255), -1);

      void ellipse(Mat& img, Point center, Size axes, double angle, double startAngle, double endAngle, const Scalar&color, int thickness=1, int lineType=8, int shift=0)

      该函数是用来在指定图片上绘制椭圆弧线的。

      参数image为需要绘制椭圆的图像;

      参数center是该椭圆的中心点坐标;

      参数axes是该椭圆的长半轴和短半轴;

      参数angle是该椭圆和水平方向上的旋转夹角;

      参数startAngle表示绘制椭圆弧线相对该椭圆自己的水平轴的起始角度;

      参数endAngel表示绘制椭圆弧线相对该椭圆自己的水平轴的终止角度;

      后面的参数比较普通就不介绍了。

      绘制椭圆曲线的示意图如下所示:

      

      实验结果

      检测前的图像:

      

      利用该算法进行皮肤检测后的二值图:

      

      实验代码及注释

      main.cpp:

    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/contrib/contrib.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    #include <iostream>
    
    using namespace std;
    using namespace cv;
    
    Mat input_image;
    Mat output_mask;
    Mat output_image;
    
    void main()
    {
        VideoCapture cam(0);
        if(!cam.isOpened())
            return;
    
        namedWindow("input image");
        namedWindow("output mask");
        namedWindow("output image");
        /*椭圆皮肤模型*/
        Mat skinCrCbHist = Mat::zeros(Size(256, 256), CV_8UC1);
        ellipse(skinCrCbHist, Point(113, 155.6), Size(23.4, 15.2), 43.0, 0.0, 360.0, Scalar(255, 255, 255), -1);
    
        while(true) {
            cam >> input_image;
            if(input_image.empty())
                return ;
    
            Mat ycrcb_image;
            output_mask = Mat::zeros(input_image.size(), CV_8UC1);
            cvtColor(input_image, ycrcb_image, CV_BGR2YCrCb); //首先转换成到YCrCb空间
            for(int i = 0; i < input_image.cols; i++)   //利用椭圆皮肤模型进行皮肤检测
                for(int j = 0; j < input_image.rows; j++){
                Vec3b ycrcb = ycrcb_image.at<Vec3b>(j, i);
                if(skinCrCbHist.at<uchar>(ycrcb[1], ycrcb[2]) > 0)
                    output_mask.at<uchar>(j, i) = 255;
            }
            input_image.copyTo(output_image, output_mask);
    
            imshow("input image", input_image);
            imshow("output mask", output_mask);
            imshow("output image", output_image);
            output_image.setTo(0);
            if(27 == waitKey(30))
                return;
        }
        return;
    }

      实验总结: 皮肤的椭圆模型确实可以用来做皮肤检测,一旦确定好了该椭圆就可以用来做皮肤检测了。

      参考文献:

         A super-simple skin detector in OpenCV

         皮肤检测与克服光线影响的连通域寻找

     http://docs.opencv.org/modules/core/doc/drawing_functions.html?highlight=ellipse#cv.Ellipse

  • 相关阅读:
    给博客园编辑器完善个插件及简单产品化工作
    在Visual Studio中新增生成项目
    用了三星Dex,我已经快一个月回家没开过电脑了
    BizTalk证书相关操作
    定长文本格式编辑神器
    B2B相关编码说明
    OFTP简介
    Apigee 简介与简单试用
    重置BizTalk RosettaNet
    BizTalk Map 累积连接字符串
  • 原文地址:https://www.cnblogs.com/tornadomeet/p/2802428.html
Copyright © 2020-2023  润新知