65.9K
CodeProject 正在变化。 阅读更多。
Home

自适应肤色检测

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.68/5 (10投票s)

2014 年 8 月 18 日

CPOL

9分钟阅读

viewsIcon

51158

downloadIcon

1533

在本文中,我们将探讨论文“一种基于色调阈值的自适应实时皮肤检测器”中描述的自适应肤色检测技术。

引言

在本文中,我们将介绍一篇论文“一种基于色调阈值化的自适应实时肤色检测器”中描述的自适应肤色检测技术。

背景

肤色检测是图像分析中的一个重要问题。肤色检测是指在图像中查找肤色像素或区域的过程。通过检测肤色区域,通常可以识别出人脸、手臂、手部和手势。

肤色检测常用于人机交互(HCI)应用,在过去的几十年里,该领域已经进行了大量的研究。迄今为止,还没有一种通用的实时肤色检测器能够在所有光照条件、肤色等条件下工作。

有几种方法可以构建肤色检测器。最基本的一种是基于固定肤色的阈值化。

全局肤色检测器

RBG彩色图像的每个像素通常表示为红-绿-蓝通道或颜色内容的组合。基于固定肤色的阈值将指定RGB值的范围。设L=(R1,G1,B1)和H=(R2,G2,B2)表示范围。

设图像每个像素的颜色表示为**C=(R,G,B)**。现在我们检查图像的每个像素,如果发现**R1<R<R2**,以及**G1<G<G2**和**B1<B<B2**,即像素的颜色在指定的范围内。则该像素被标记为肤色像素,否则被标记为非肤色像素。

基于固定肤色的阈值化阶段的输出是一个二值图像,像素被赋予值1表示肤色像素,被赋予值0表示非肤色像素。

然而,颜色的RGB表示有许多缺点。主要原因是图像中颜色的外观取决于捕获图像时的光照条件(光照几何和颜色)。颜色检测中的重要挑战是以一种对光照条件变化不变或最不敏感的方式来表示感知到的颜色。

RGB颜色空间不满足此标准。然而,HSV颜色空间为颜色检测提供了良好的特性。在HSV颜色空间中,图像的每个像素都以色调-饱和度-亮度(Hue-Saturation-Value)表示。H和S分量表征颜色(与光照无关),V分量指定光照。因此,通过以H-S阈值表示肤色阈值,我们可以实现对光照不变或至少对光照变化鲁棒的颜色表示。

理想情况下,肤色检测器应该只检测肤色像素并拒绝属于其他对象或背景的像素。然而,由于我们使用的是简单的基于阈值的方法,而没有考虑图像中的其他信息,因此固定肤色检测器也会错误地检测到一些属于背景或具有与肤色相似色调的对象(如木材等)的非肤色像素。

在某些情况下,错误检测的像素量可能很大,相对于实际的肤色像素,如果场景中有很大一部分包含色调与肤色相似的对象。

图像采集系统、光照条件、预处理等都会影响色调阈值的选择。

因此,最优阈值需要自适应地确定。

自适应肤色检测器的第一个组成部分是静态全局肤色检测器。它将使用预定义的阈值来检测肤色。

人们发现,肤色在HSV颜色空间的H通道中位于一个非常窄的范围内。低色调阈值和高色调阈值分别选为(0,33)。提供的色调范围是通用的阈值,将涵盖所有可能的肤色。

由于肤色阈值的通用性,一些色调与肤色相似或落在指定阈值内的背景对象也可能被检测到。

而且,我们不希望选择图像中曝光过度和曝光不足的区域(暗、亮的区域)。因此,我们将亮度阈值指定为(15,250)。

全局肤色检测器将图像中色调值在(0,33)范围内且亮度值在(15,250)范围内的所有像素分类。

#include "adaptiveskindetector.hpp"

AdaptiveSkinDetector::AdaptiveSkinDetector()
{
    //static skin color thresholds
    _hueLower=3;
    _hueUpper=33;

    //initialising the global skin color thresholds
    lower=Scalar(_hueLower,50,50);
    higher=Scalar(_hueUpper,255,255);

    ......
    .......

}
void AdaptiveSkinDetector::run(Mat image,Mat &mask)
{

    //converting the image to HSV color space
    cv::cvtColor(image,image,CV_BGR2HSV);
    //applying the static skin color thresholds
    cv::inRange(image,lower,higher,mask);


    .....
    .....

我们将使用OpenCV图像处理库来开发代码。如上所述,阈值化阶段的输出是一个名为“mask”的图像。

这是一个二值图像,像素值为1的被分类为肤色像素,像素值为0的被分类为非肤色像素。

在下图中,我们可以看到大多数肤色像素是通过阈值检测到的,但一些曝光过度(明亮)的区域被忽略了,而一些不是肤色的区域,如嘴唇、墙壁等也被选中了。

肤色直方图

检测到的肤色像素可用于构建肤色直方图,该直方图表示场景中肤色像素的统计分布。

图像的直方图仅仅是图像各个H-S-V通道的直方图。直方图是图像分析中的一个重要工具,有助于理解数据,而不考虑图像的上下文内容。

我们仅考虑前一阶段标记为肤色的像素来构建直方图。

   //setting the mask for histogram
    h.setMask(mask);

   //build histogram based on global skin color threshols
    Mat hist=h.BuildHistogram(hue,false);

    //normalize the histogram
    cv::normalize(hist,hist,0,1,NORM_MINMAX);
    //update the histograms
    h.setHist(hist);

在上面的代码中,“h”是一个类对象,封装了直方图计算。我们指定直方图应仅通过考虑图像中值为(255)的像素来计算,该图像由“mask”表示。

接下来,我们假设有人告诉我们图像中的一些像素确实是肤色。这是我们通过其他方式获得的信息。

我们再次考虑这些像素来构建直方图。

因此,我们有两个直方图:一个是通过考虑全局肤色检测结果得到的,另一个直方图是通过考虑真正属于图像肤色区域的像素得到的。

接下来,为了获得图像颜色内容的平均表示,我们对两个直方图进行加权平均。

通过为权重选择0.02-0.05范围内的值可以获得良好的结果。

统计方法中的一个典型步骤是剔除数据中的异常值。

通过仅考虑直方图中占有显著部分的数��或对应于相对频率分量高于某个阈值的分量的数��来剔除数据中的异常值。

用于选择下限和上限阈值的标准是使直方图下的面积覆盖\(f % \)

因此,我们选择一个下限和上限阈值,使得直方图下的面积是\(f% 的直方图总面积\)。在论文中使用了90-96%的标准。

    //mmask is the binary image representing true skin colored pixels
    //set the new histogram mask
    h.setMask(mmask);

    //compute the histogram based on updated mask
    Mat shist=h.BuildHistogram(hue,false);
    //normalize the histogram
    cv::normalize(shist,shist,0,1,NORM_MINMAX);

    //merge both the histograms with weight of 0.02
    h.mergeHistogram(shist,0.02);

    //get the final histogram
    hist=h.getHist();

    //get the histogram thresholds so that 90% or 10% does not lie within the thresholds
    h.getThreshHist(hist,0.05,0.05);

    //update the histogram thresholds
    _hueLower=range1[0];
    _hueUpper=range1[1];

最终的肤色检测器输出是基于在直方图中剔除异常值后计算出的新阈值。这些_hueLower和_hueUpper用作阈值,并再次进行肤色阈值化。

下面是自适应肤色检测技术的输出。可以看到,一些先前检测到的非肤色区域在使用了修改后的阈值后被拒绝了。因此,自适应肤色检测技术有助于拒绝图像中肤色像素的假阳性,从而表示图像中真正的肤色像素。

在没有任何额外信息的情况下,用于选择下限和上限阈值的标准只是有助于剔除异常值。

在显示的图中,一些背景像素、属于头发、嘴唇等的像素也显示为肤色像素。

现在让我们考虑属于人脸的像素。在上面的例子中,真正的肤色像素是手动提供的。这是通过指定一个掩模手动给出的。ROI(168,63,50,50)中的像素被明确指定为肤色像素。

通过仅考虑ROI中的像素来计算直方图。

显然,在整个图像上计算的直方图中的像素比在小ROI中计算的像素要多。为了避免由于用于构建直方图的像素数量而产生的偏差,在计算线性组合之前,直方图被归一化为0到1。

然后我们确定90%的像素所在的区间。

对应的色调范围为(13,16)。

考虑新范围的肤色检测如图1所示。

因此,整合有关肤色的线索,可以提高肤色像素的检测性能。

在上面的例子中,线索是手动整合的,但如果我们能够自动整合线索,那么我们就可以使肤色检测过程完全自适应。

使用运动线索

论文中提出的一些技术基于使用运动线索,如帧差法和光流跟踪。这些技术适用于HCI应用,假设感兴趣的对象在运动。帧差法提供了一种简单的方法来确定发生运动的区域并使用这些像素。

在HCI应用中,手或脸部区域用于与计算机通信,并假设场景中的主导运动属于手和肤色像素。

检测属于肤色区域的一种方法是运动跟踪。我们跟踪图像中发生运动的区域,并假设这些区域属于手/脸部区域。在检测到这些区域后,我们可以确定这些像素的HSV阈值范围。

通过观察图像中肤色像素的运动来动态调整色调阈值。

因此,第一步是确定运动中的肤色像素。

    //obseve the pixels encountering motion
    Mat mmask=Mat();
    if(!p1.empty())
    {

        Mat motion;
        //computing the different in present and past frames
        cv::absdiff(p1,ch[2],motion);
        //consider the pixels with motion threshold above 8
        cv::inRange(motion,Scalar(8,0,0),Scalar(255,0,0),mmask);
        //filering the mask by performing morphological operations
        cv::erode(mmask,mmask,Mat());
        cv::dilate(mmask,mmask,Mat());
    }

使用代码

#include "ImgProc/adaptiveskindetector.hpp"
//...
AdaptiveSkinDetector ss1;
...
Mat hmask;
ss1.run(image,hmask);
//...

代码

相应的代码可以在OpenVision Repository中找到 https://github.com/pi19404/OpenVision 类AdaptiveSkinDetector封装了实现肤色检测器的类方法。相应的代码可以在文件 ImgProc/adaptiveskindetector.cpp 和IgmProc/adaptiveskindetector.hpp 中找到。对于直方图计算,使用了Histogram类,可以在文件ImgProc/Histogram.cppImgProc/Histogram.hpp中找到。

参考文献

  1. Farhad Dadgostar and Abdolhossein Sarrafzadeh. An Adaptive Real-time Skin Detector Based on Hue Thresholding: A Comparison on Two Motion Tracking Methods . In: Pattern Recogn. Lett. 27.12 (Sept. 2006), pp. 1342 1352.  issn:0167-8655. doi: 10.1016/j.patrec.2006.01.007. url: http://dx.doi. org/10.1016/j.patrec.2006.01.007.

文章下载

本文档的PDF版本可以在这里找到。
© . All rights reserved.