基于像素的皮肤检测技术

简介: 基于像素的皮肤检测技术

基于像素的皮肤检测技术


介绍一种基于颜色空间的皮肤检测技术,可以检测亚洲人种与白人的皮肤,皮肤检测


人脸识别的基础,也是很多人像识别技术的基础操作,在实际应用中还是非常有用的。



基于像素的皮肤检测主要是寻找正确的颜色空间几何,图像处理中,常见的颜色空间


有如下几种


1.      RGB色彩空间 – R代表单色红,G代表单色绿,B代表单色蓝


2.      HSV色彩空间 – H 代表色彩, S代表饱和度,V代表强度值


3.      YCbCr色彩空间 – 是数字电视的色彩空间



RGB转换为HSV的Java代码如下:

  public static float[] rgbToHSV(int tr, int tg, int tb) {
    float min, max, delta;
    float hue, satur, value;
    min = Math.min(tr, Math.min(tg, tb));
    max = Math.max(tr, Math.max(tg, tb));
    value = max;
    delta = max - min;
    if(max != 0) {
      satur = delta/max;
    } else {
      satur = 0;
      hue = -1;
    }
    
    if(tr == max) {
      hue = (tg - tb)/delta;
    }
    else if(tg == max) {
      hue = 2 + (tb-tr)/delta;
    } else {
      hue = 4 + (tr-tg)/delta;
    }
    hue = hue * 60.0f;
    if(hue < 0) {
      hue = hue + 360;
    }
    return new float[]{hue, satur, value};
  }

RGB转换为YCbCr的Java代码如下:

  public static int[] rgbToYcrCb(int tr, int tg, int tb) {
    double sum = tr + tg + tb;
    double r = ((double)tr)/sum;
    double g = ((double)tg)/sum;
    double b = ((double)tb)/sum;
    double y = 65.481 * r + 128.553 * g + 24.966 * b + 16.0d;
    double Cr = -37.7745 * r - 74.1592 * g + 111.9337 * b + 128.0d;
    double Cb = 111.9581 * r -93.7509 * g -18.2072 * b + 128.0d;
    return new int[]{(int)y, (int)Cr, (int)Cb};
  }

一个简单的基于RGB颜色空间的皮肤算法如下:

(R, G, B) is classified as skin if


R > 95 and G > 40 and B > 20and max{R, G, B} – min{R, G, B} > 15 and |R-G| > 15


and R > G and R > B


实现代码如下:

  public boolean isSkin(int tr, int tg, int tb) {
    int max = Math.max(tr, Math.max(tg, tb));
    int min = Math.min(tr, Math.min(tg, tb));
    int rg = Math.abs(tr - tg);
    if(tr > 95 && tg > 40 && tb > 20 && rg > 15 && 
        (max - min) > 15 && tr > tg && tr > tb) {
      return true;
    } else {
      return false;
    }
  }

一个简单的基于HSV颜色空间的皮肤算法如下:

(H, S, V) will be classified as skin if

H > 0 and H < 50 and S > 0.23 andS < 0.68

实现代码如下:

  public boolean isSkin(int tr, int tg, int tb) {
    float[] HSV = ColorUtil.rgbToHSV(tr, tg, tb);
    if((HSV[0] > 0.0f && HSV[0] < 50.0f ) && (HSV[1] > 0.23f && HSV[1] < 0.68f)){
      return true;
    } else {
      return false;
    }
  }

一个简单的基于YCbCr颜色空间的皮肤算法如下:


(Y, Cb, Cr) will be classified as skin if:


Y > 80 and 85<Cb < 135 and 135 <Cr < 180, and (Y,Cb,Cr)= [0,255]


对于的Java代码如下:

  public boolean isSkin(int tr, int tg, int tb) {
    int y = (int)(tr * 0.299 + tg * 0.587 + tb * 0.114);
    int Cr = tr - y;
    int Cb = tb - y;
    if(y> 80 && y < 255 && Cr > 133 && Cr < 173 && 77 < Cb && Cb < 127) {
      return true;
    }
    return false;
  }

基于上述三个算法实现的皮肤检测的效果如下:

1334329882_3736.png

皮肤检测滤镜的源代码如下:

package com.process.blur.study;
 
import java.awt.Color;
import java.awt.image.BufferedImage;
 
import com.gloomyfish.skin.dection.DefaultSkinDetection;
import com.gloomyfish.skin.dection.FastSkinDetection;
import com.gloomyfish.skin.dection.GaussianSkinDetection;
import com.gloomyfish.skin.dection.HSVSkinDetection;
import com.gloomyfish.skin.dection.ISkinDetection;
 
public class SkinFilter extends AbstractBufferedImageOp {
  private ISkinDetection skinDetector;
  
  public SkinFilter(int type) {
    if(type == 2) {
      skinDetector = new FastSkinDetection();
    } else if(type == 4) {
      skinDetector = new HSVSkinDetection();
    } else if(type == 8) {
      skinDetector = new GaussianSkinDetection();
    } else {
      skinDetector = new DefaultSkinDetection();
    }
  }
 
  @Override
  public BufferedImage filter(BufferedImage src, BufferedImage dst) {
    int width = src.getWidth();
        int height = src.getHeight();
 
        if ( dst == null )
            dst = createCompatibleDestImage( src, null );
 
        int[] inPixels = new int[width*height];
        int[] outPixels = new int[width*height];
        getRGB( src, 0, 0, width, height, inPixels );
        if(skinDetector instanceof GaussianSkinDetection) {
          ((GaussianSkinDetection)skinDetector).setDispSample(getDispersion(src));
        }
        int index = 0;
        for(int row=0; row<height; row++) {
          int ta = 0, tr = 0, tg = 0, tb = 0;
          for(int col=0; col<width; col++) {
            index = row * width + col;
            ta = (inPixels[index] >> 24) & 0xff;
                tr = (inPixels[index] >> 16) & 0xff;
                tg = (inPixels[index] >> 8) & 0xff;
                tb = inPixels[index] & 0xff;
                if(skinDetector.isSkin(tr, tg, tb)) {
                  outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
                } else {
                  tr = tg = tb = 0;
                  outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
                }               
          }
        }
        setRGB( dst, 0, 0, width, height, outPixels );
        return dst;
  }
  
  public Color getDispersion(BufferedImage image) {
        // calculate means of pixel  
        int index = 0;
        int height = image.getHeight();
        int width = image.getWidth();
        int[] inPixels = new int[width*height];
        getRGB(image, 0, 0, width, height, inPixels );
        double redSum = 0, greenSum = 0, blueSum = 0;
        Color meanColor = getMean(image);
        double redmeans = meanColor.getRed();
        double greenmeans = meanColor.getGreen();
        double bluemeans = meanColor.getBlue();
        double total = height * width;  
        for(int row=0; row<height; row++) {  
            int ta = 0, tr = 0, tg = 0, tb = 0;  
            for(int col=0; col<width; col++) {  
                index = row * width + col;  
                ta = (inPixels[index] >> 24) & 0xff;  
                tr = (inPixels[index] >> 16) & 0xff;  
                tg = (inPixels[index] >> 8) & 0xff;  
                tb = inPixels[index] & 0xff; 
                double rd = (tr - redmeans);
                double gd = (tg - greenmeans);
                double bd = (tb - bluemeans);
                redSum += rd * rd;  
                greenSum += gd * gd;  
                blueSum += bd * bd;  
            }  
        }
        int reddiff = (int)Math.sqrt((redSum / total));
        int greendiff = (int)Math.sqrt((greenSum / total));
        int bluediff = (int)Math.sqrt(blueSum / total);
        System.out.println(" red dispersion value = " + reddiff);
        System.out.println(" green dispersion value = " + greendiff);
        System.out.println(" blue dispersion value = " + bluediff);
    return new Color(reddiff, greendiff, bluediff);
  }
  
  public Color getMean(BufferedImage image) {
        // calculate means of pixel  
        int index = 0;
        int height = image.getHeight();
        int width = image.getWidth();
        int[] inPixels = new int[width*height];
        getRGB(image, 0, 0, width, height, inPixels );
        double redSum = 0, greenSum = 0, blueSum = 0;  
        double total = height * width;  
        for(int row=0; row<height; row++) {  
            int ta = 0, tr = 0, tg = 0, tb = 0;  
            for(int col=0; col<width; col++) {  
                index = row * width + col;  
                ta = (inPixels[index] >> 24) & 0xff;  
                tr = (inPixels[index] >> 16) & 0xff;  
                tg = (inPixels[index] >> 8) & 0xff;  
                tb = inPixels[index] & 0xff;  
                redSum += tr;  
                greenSum += tg;  
                blueSum +=tb;  
            }  
        }
        int redmeans = (int)(redSum / total);
        int greenmeans = (int)(greenSum / total);
        int bluemeans = (int)(blueSum / total);
        System.out.println(" red average value = " + redmeans);
        System.out.println(" green average value = " + greenmeans);
        System.out.println(" blue average value = " + bluemeans);
    return new Color(redmeans, greenmeans, bluemeans);
  }
}

讨论:

皮肤检测中的后续处理非常重要,可以除去噪声,平滑图像,是皮肤检测的结果


更加的准确,输出的更容易接受。



参考引用:


《A New Fast Skin Color Detection Technique》 - Tarek M. Mahmoud


《Improved Automatic Skin Detection in Color Images》 - Filipe Tomaz


                                              and Tiago Candeias and Hamid Shahbazkia


《Skin Detection using HSV color space》- unknown author

相关文章
|
24天前
|
算法 API 计算机视觉
图像处理之角点检测与亚像素角点定位
图像处理之角点检测与亚像素角点定位
16 1
|
25天前
|
算法 计算机视觉
图像处理之基于像素的图像混合
图像处理之基于像素的图像混合
12 1
|
25天前
|
算法 计算机视觉
图像处理之像素格效果
图像处理之像素格效果
13 0
|
2月前
|
机器学习/深度学习 计算机视觉
用DPU像素着色器
用DPU像素着色器
17 1
|
2月前
|
算法 计算机视觉
OpenCV(四十四):亚像素级别角点位置优化
OpenCV(四十四):亚像素级别角点位置优化
75 0
|
9月前
|
前端开发 UED
什么是前端开发领域中的屏幕像素密度 Pixel Density
什么是前端开发领域中的屏幕像素密度 Pixel Density
|
12月前
|
存储 数据可视化 索引
校正图像亮度不均匀问题并分析前景对象
校正图像亮度不均匀问题并分析前景对象
71 0
|
编解码 前端开发
图文并茂带你弄懂物理分辨率、分辨率、物理像素、逻辑像素、dpr、ppi
物理分辨率和分辨率 什么是物理像素 什么是CSS像素 什么是设备像素比 什么是标清屏和高清屏 缩放 什么是PPI(DPI)
410 0
|
算法 C语言
红外热成像仪 阵列插值-由 32*24 像素到 512*384 像素
MLX90640 的 32*24=768 像素虽然比以往的 8*8 或者 16*8 像素提高了很多,但若直接用这些像素还是不能很好的形成热像图,为了使用这些像素点平滑成像就需要对其进行插值,使用更多的像素来绘制图像。 看了一些别人的算法,感觉主要就是多项式插值,仅是插值方法的组合方式不同。
红外热成像仪  阵列插值-由 32*24 像素到 512*384 像素
|
编解码 前端开发 Android开发
像素相关概念:PPI、DPI、设备像素、独立像素
像素相关概念:PPI、DPI、设备像素、独立像素
178 0
像素相关概念:PPI、DPI、设备像素、独立像素