Android端肤色检测

      当今流行各种美颜美肤,而美颜美肤的前提是检测出人的皮肤。有科学家提出基于RGB颜色空间模型实现肤色检测算法,本篇文章主要讨论在Android端如何实现肤色检测。

      参考该篇博客引用的算法:https://blog.csdn.net/wj080211140/article/details/23384927


      根以上算法公式,实现肤色检测,需要考虑均匀光照和侧面光照两种情况:

/**
     * 肤色检测,基于RGB颜色模型
     * 在均匀光照下应满足以下判别式:
     * R>95 AND G>40 B>20 AND MAX(R,G,B)-MIN(R,G,B)>15 AND ABS(R-G)>15 AND R>G AND R>B
     * 在侧光拍摄环境下:
     * R>220 AND G>210 AND B>170 AND ABS(R-G)<=15 AND R>B AND G>B
     * @param pixels pixels
     * @param width width
     * @param height height
     * @return pixels
     */
    private int[] detectSkin(int[] pixels, int width, int height){
        for(int i=0; i<width; i++){
            for(int j=0; j<height; j++){
                int pixel = pixels[j*width + i];
                int red = (pixel>>16) & 0xff;
                int green = (pixel>>8) & 0xff;
                int blue = pixel & 0xff;
                //判断RGB分量是否符合肤色范围
                if ((red>95 && green>40 && blue>20 && Math.abs(red-green)>15 &&
                        ((max(red, green, blue) - min(red, green, blue))>15) &&
                        red > green && red > blue) ||
                        (red>220 && green>210 && blue>170 &&
                         Math.abs(red-green)<=15 && red>blue && green>blue)) {
                    //white=255
                    pixels[j*width + i] = 255;
                }
            }
        }
        return pixels;
    }

      算法中使用到的比较三者最大值、三者最小值方法:

/**
     * 计算三者最大值
     * @param x x
     * @param y y
     * @param z z
     * @return 最大值
     */
    private static int max(int x, int y, int z){
        int max = x;
        if(y > max){
            max = y;
        }
        if(z > max){
            max = z;
        }
        return max;
    }

    /**
     * 计算最小值
     * @param x x
     * @param y y
     * @param z z
     * @return 最小值
     */
    private static int min(int x, int y, int z){
        int min = x;
        if(y < min){
            min = y;
        }
        if(z < min){
            min = z;
        }
        return min;
    }

      最终是调用上述算法,进行肤色检测,并且使用白色标记检测出的皮肤:

    /**
     * 执行肤色检测,并使用特定颜色标记
     * @param bitmap bitmap
     */
    private void doDetect(Bitmap bitmap){
        if(bitmap == null){
            return;
        }
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        int[] pixels = new int[width*height];
        bitmap.getPixels(pixels, 0, width, 0, 0, width, height);

        pixels = detectSkin(pixels, width, height);
        Bitmap dst = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        dst.setPixels(pixels, 0, width, 0,0, width, height);
        mHandler.obtainMessage(CODE_SHOW, dst).sendToTarget();
    }
private void init(){
        img_skin = (ImageView) findViewById(R.id.img_skin);

        final Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.yuan);
        //开启线程,执行肤色检测
        new Thread(new Runnable() {
            @Override
            public void run() {
                doDetect(bitmap);
            }
        }).start();
    }

      肤色检测结果,通过Handler在主线程显示标记皮肤的图像:

    //handler中显示肤色检测后的图像
    @SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(msg.what == CODE_SHOW){
                Bitmap bitmap = (Bitmap)msg.obj;
                img_skin.setImageBitmap(bitmap);
            }
        }
    };

最后来看下肤色检测效果图,使用白色标记检测结果:


      补充:如果照片背景有人体肤色相似颜色,会导致误识别。这时,我们可以结合人体检测或者人脸检测,来针对图片的特定区域进行肤色检测,也就是排除外部背景环境干扰。

      如果大家有问题或者有更好的肤色检测算法,可以互相讨论,相互学习。


  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

徐福记456

您的鼓励和肯定是我创作动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值