网上看到各种语言的抓图(采集照片)的程序段,拿来跑一跑,都是爬虫的机制,而地址一般都是固定的,格式固定,才能抓到想要的图,这显示不够智能,于是把作者的代码改掉,变成了个下载图片的爬虫。然后问题就来了,大量的图片,不都是我们想要的,这就想到了图像识别,目前主要的分支有,找相似图,人脸识别,鉴黄等。
今天要说说肤色提取,即提取你个人喜爱的肤色(无种族歧视哦)。最开始使用了CSDN上某大神写的一段JAVA代码(用于检测黄色图片,此处指颜色为黄色的图像),代码如下,使用了YUV色彩空间。效果还是很不错的。
public static boolean isFlesh(final Color c) {
if ((c.getRed() > 230) && (c.getGreen() > 170) && (c.getBlue() > 190)) {
return false;
}
LDialyzer yuv = LDialyzer.getYuv(c.getRed(), c.getGreen(), c.getBlue());
return ((c.getRed() > 40) && (c.getGreen() > 40) && (yuv.y + 16 > 145)
&& (yuv.v + 128 < 173) && (yuv.v + 128 > 133)
&& (yuv.u + 128 < 127) && (yuv.u + 128 > 77));
}
但是这段代码,上半部分的依据RGB范围直接PASS掉一部分,这确定是有点果断的,仔细观察RGB色彩空间,会发现还是有一部分的偏黄色被排除了。于是考虑使用HSV色彩空间。
1、这里科普一下RGB和HSV的区别,
所谓RGB就是:红(Red)、绿(Green)、蓝(Blue)三种色光原色。RGB色彩模型的混色属于加法混色。每种原色的数值越高,色彩越明亮。 R、G、B都为0时是黑色,都为255时是白色。RGB虽然表示直接,但是R、G、B数值和色彩的三属性没有直接的联系,不能揭示色彩之间的关系。所以在进行配色设计时,RGB模型就不是那么合适了。HSV是指Hue(色相)、Saturation(饱和度)和Value(值)。RGB和CMY颜色模型都是面向硬件的,而HSV颜色模型是面向用户的。
2、HSV六棱锥
H参数表示色彩信息,即所处的光谱颜色的位置。该参数用一角度量来表示,红、绿、蓝分别相隔120度。互补色分别相差180度。
纯度S为一比例值,范围从0到1,它表示成所选颜色的纯度和该颜色最大的纯度之间的比率。S=0时,只有灰度。
V表示色彩的明亮程度,范围从0到1。有一点要注意:它和光强度之间并没有直接的联系。
3、RGB和HSV的转换算法
max=max(R,G,B)
min=min(R,G,B)
if R = max, H = (G-B)/(max-min)
if G = max, H = 2 + (B-R)/(max-min)
if B = max, H = 4 + (R-G)/(max-min)
H = H * 60
if H < 0, H = H + 360
V=max(R,G,B)
S=(max-min)/max
if s = 0
R=G=B=V
else
H /= 60;
i = INTEGER(H)
f = H - i
a = V * ( 1 - s )
b = V * ( 1 - s * f )
c = V * ( 1 - s * (1 - f ) )
switch(i)
case 0: R = V; G = c; B = a;
case 1: R = b; G = v; B = a;
case 2: R = a; G = v; B = c;
case 3: R = a; G = b; B = v;
case 4: R = c; G = a; B = v;
case 5: R = v; G = a; B = b;
4、RGB转化为HSV的算法的实现:
public static HSV RGB2HSV(RGB rgb){
float r = (float)rgb.getR()/255;
float g = (float)rgb.getG()/255;
float b = (float)rgb.getB()/255;
float max = max(r, g, b);
float min = min(r, g, b);
float h = 0;
if(r==max)
h = (g-b)/(max-min);
if(g==max)
h = 2+(b-r)/(max-min);
if(b==max)
h= 4+(r-g)/(max-min);
h *=60;
if(h<0) h +=360;
HSV hsv = new HSV(h,(max-min)/max,max);
return hsv;
}
对于肤色识别 饱和度(S)和亮度(V)就无关紧要了,这样只需得到一个色调(H)的取值范围。
从网上找了找H的取值范围,大概在25~50,为了近一步确定这个数值,做了如下实验。
先截取了一些照片,只要能体现此人的肤色,尽量选择有差异的。
5、JAVA实现统计
public static int[] vessel = new int[360];
public static int[] vesselIndex = new int[360];
public static void main(String[] args) throws IOException {
File file = new File("D:\\培养材料");
File[] listFiles = file.listFiles();
ArrayList list = new ArrayList();
for (int i = 0; i < listFiles.length; i++) {
transition(listFiles[i]);
}
for (int i = 0; i < vesselIndex.length; i++) {
vesselIndex[i] = i;
}
for (int i = 0; i < vessel.length; i++) {
for (int j = i+1; j < vessel.length; j++) {
if(vessel[i]int temp = vessel[i];
vessel[i] = vessel[j];
vessel[j] = temp;
int tempIndex = vesselIndex[i];
vesselIndex[i] = vesselIndex[j];
vesselIndex[j] = tempIndex;
}
}
}
for (int i = 0; i < vesselIndex.length; i++) {
System.out.println("H="+vesselIndex[i]+",count:"+vessel[i]);
}
}
private static ArrayList transition(File file) throws IOException {
System.out.println(file.getName());
BufferedImage img = ImageIO.read(file);
ArrayList list = new ArrayList();
for (int j = 0; j for (int j2 = 0; j2 < img.getHeight(); j2++) {
int binaryColor = img.getRGB(j, j2);
if(binaryColor==16777215) continue;
Color c = new Color(binaryColor);
RGB rgb = new RGB(c.getRed(), c.getGreen(), c.getBlue());
HSV hsv = ColorUtils.RGB2HSV(rgb);
if(!"NaN".equals(String.valueOf(hsv.getH())))
vessel[(int)hsv.getH()]++;
list.add(hsv);
System.out.println(hsv);
}
}
return list;
}
6、结果:(略掉count=0)此处省去大部分数据
H=15,count:31071
H=18,count:26936
H=16,count:24615
H=13,count:24031
H=17,count:21968
H=26,count:11921
H=10,count:11062
H=90,count:13
H=65,count:12
H=79,count:11
H=357,count:11
H=210,count:10
H=351,count:10
H=251,count:10
H=74,count:9
H=356,count:9
H=53,count:9
H=190,count:8
H=67,count:8
H=300,count:8
H=336,count:4
H=85,count:4
H=84,count:4
H=171,count:3
H=186,count:3
H=173,count:3
H=140,count:3
H=195,count:3
H=349,count:3
H=105,count:3
H=108,count:2
H=189,count:2
H=106,count:2
H=358,count:2
H=260,count:1
H=264,count:1
结果 (略掉未绘制部分)
H范围[0,50),很显示以上数据,上下可以再切掉10%~30%。这是当S,V都等于1时的图像,尝试修改S和V的值,范围在[0,1],就可以匹配到因光线等问题,造成的较亮或较暗的图像。而在做肤色匹配时,不考虑S和V,使准确性提高。
7、判断鲜肉(即筛选你想要的肤色)
public static boolean isFlesh2(Color c){
RGB rgb = new RGB(c.getRed(),c.getGreen(),c.getBlue());
HSV hsv = ColorUtils.RGB2HSV(rgb);
if(hsv.getH()>9&&hsv.getH()<43){
return true;
}
return false;
}
以上内容就是我们本节讲的主要内容,利用Java程序实现了对众多图片按照肤色提取。(帮助你找到心仪的小姐姐)。其实肤色提取对于人脸识别领域也是一项重大的技术,尤其是人脸识别作为生物身份验证手段的潜力逐渐凸显,使得对识别系统的性能要求越来越高。学习了以上内容,让你对肤色及色彩提取更为了解。