基于像素的皮肤检测技术

基于像素的皮肤检测技术

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

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

 

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

有如下几种

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:

> 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;  
}  

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


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

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值