热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

基于像素的皮肤检测技术

基于像素的皮肤检测技术介绍一种基于颜色空间的皮肤检测技术,可以检测亚洲人种与白人的皮肤,皮肤检测人脸识别的基础,也是很多人像识别技术的基础操作,在实际应用中还是非常有用的。

基于像素的皮肤检测技术

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

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

 

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

有如下几种

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 基于上述三个算法实现的皮肤检测的效果如下: 
 


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

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

 


推荐阅读
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
author-avatar
周鑫先生_852
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有