博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【JAVA】图像识别——HSV肤色提取 【转载】
阅读量:5935 次
发布时间:2019-06-19

本文共 6754 字,大约阅读时间需要 22 分钟。

OSCHINA上看到各种语言的抓妹子图的程序段,拿来跑一跑,都是爬虫的机制,而地址一般都是固定的,格式固定,才能抓到想要的图,这显示不够智能,于是把作者的代码改掉,变成了个下载图片的爬虫。然后问题就来了,大量的图片,不是我想要的,于是想到了图像识别,目前主要的分支有,找相似图,人脸识别,鉴黄等。   

OSCHINA上看到各种语言的抓妹子图的程序段,拿来跑一跑,都是爬虫的机制,而地址一般都是固定的,格式固定,才能抓到想要的图,这显示不够智能,于是把作者的代码改掉,变成了个下载图片的爬虫。然后问题就来了,大量的图片,不是我想要的,就这想到了图像识别,目前主要的分支有,找相似图,人脸识别,鉴黄等。

今天要说说肤色提取,大概就暴露了,我要选什么分支了,不多说,不多说 >_<!

肤色提取

开始使用了CSDN上某大神写的一段JAVA代码(用于检测黄色图片),使用了YUV色彩空间。效果还是很不错的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
  
* flesh
  
  
* @param c
  
* @return
  
*/
 
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色彩空间。

HSV六棱锥

  H参数表示色彩信息,即所处的光谱颜色的位置。该参数用一角度量来表示,红、绿、蓝分别相隔120度。互补色分别相差180度。

  纯度S为一比例值,范围从0到1,它表示成所选颜色的纯度和该颜色最大的纯度之间的比率。S=0时,只有灰度。

  V表示色彩的明亮程度,范围从0到1。有一点要注意:它和光强度之间并没有直接的联系。

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

HSV转化到RGB的算法

  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;

由算法,写JAVA实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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,为了近一步确定这个数值,做了如下实验。

先扣了一些美女图,只要肉,尽量选择有差异的。

JAVA实现统计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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<HSV> list = 
new 
ArrayList<HSV>();
  
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]<vessel[j]){
     
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<HSV> transition(File file) 
throws 
IOException{
  
System.out.println(file.getName());
  
BufferedImage img = ImageIO.read(file);
  
ArrayList<HSV> list = 
new 
ArrayList<HSV>();
  
for 
(
int 
j = 
0
; j <img.getWidth(); 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;
 
}

 

结果:(略掉count=0)

H=15,count:31071

H=18,count:26936

H=16,count:24615

H=13,count:24031

H=17,count:21968

H=12,count:21211

H=30,count:19438

H=38,count:16740

H=14,count:16470

H=33,count:16404

H=32,count:16217

H=28,count:15231

H=35,count:14929

H=20,count:14714

H=31,count:14353

H=36,count:13654

H=29,count:13515

H=21,count:13311

H=34,count:13133

H=19,count:12595

H=26,count:11921

H=10,count:11062

H=37,count:10669

H=11,count:10422

H=27,count:9726

H=22,count:9010

H=25,count:8629

H=24,count:8548

H=40,count:8375

H=23,count:8240

H=39,count:7295

H=41,count:4262

H=43,count:3365

H=0,count:3229

H=9,count:2628

H=60,count:1983

H=42,count:1469

H=8,count:1453

H=7,count:927

H=44,count:862

H=45,count:742

H=180,count:515

H=51,count:354

H=48,count:263

H=240,count:221

H=330,count:210

H=6,count:198

H=47,count:168

H=50,count:147

H=56,count:137

H=5,count:134

H=63,count:125

H=52,count:116

H=46,count:90

H=69,count:69

H=220,count:59

H=76,count:57

H=70,count:50

H=77,count:44

H=4,count:41

H=64,count:36

H=184,count:32

H=75,count:32

H=72,count:30

H=49,count:29

H=354,count:27

H=353,count:26

H=280,count:25

H=2,count:25

H=150,count:24

H=120,count:23

H=68,count:23

H=352,count:19

H=350,count:17

H=3,count:16

H=55,count:15

H=54,count:14

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=73,count:8

H=348,count:8

H=57,count:8

H=185,count:7

H=345,count:7

H=83,count:7

H=78,count:7

H=66,count:7

H=355,count:6

H=188,count:6

H=228,count:6

H=100,count:5

H=340,count:5

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=174,count:2

H=96,count:2

H=182,count:2

H=183,count:2

H=82,count:2

H=95,count:2

H=165,count:2

H=170,count:2

H=189,count:2

H=106,count:2

H=358,count:2

H=260,count:1

H=264,count:1

H=94,count:1

H=144,count:1

H=88,count:1

H=1,count:1

H=166,count:1

H=342,count:1

H=187,count:1

H=168,count:1

H=110,count:1

H=114,count:1

H=192,count:1

H=172,count:1

H=92,count:1

H=128,count:1

H=175,count:1

H=176,count:1

H=249,count:1

H=135,count:1

分析数据,H的范围大概在9~43之间

验证以上分析

public static void main(String[] args) throws IOException {

  BufferedImage dst = new BufferedImage(100, 360 * 5,

    BufferedImage.TYPE_INT_RGB);

  for (int i = 0; i < 100; i++) {

   //for (int j = 0; j < 360 * 5; j++) {

   for (int j = 0; j < 50 * 5; j++) {

    dst.setRGB(i, j, ColorUtils.RGB2Binary(ColorUtils.HSV2RGB(new HSV(j/5, 1, 1))));

   }

  }

  ImageIO.write(dst, "jpg", new File("D:\\hsv1.jpg"));

 }

结果 (略掉未绘制部分)

H范围[0,50),很显示以上数据,上下可以再切掉10%~30%。这是当S,V都等于1时的图像,尝试修改S和V的值,范围在[0,1],就可以匹配到因光线等问题,造成的较亮或较暗的图像。而在做肤色匹配时,不考虑S和V,使准确性提高。 

判断鲜肉

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

转载于:https://www.cnblogs.com/kan0n/p/4472344.html

你可能感兴趣的文章
linux FTP配置详解
查看>>
Oem7特殊机型激活提交处
查看>>
mysql数据库从删库到跑路之mysql库操作
查看>>
【练习】NSFile
查看>>
自己做的demo---c语言的基本语法,过阵子可以重新写一些算法跟数据结构了
查看>>
spring cloud 消费者
查看>>
淘宝倒计时
查看>>
Css 八卦
查看>>
LA 5713 秦始皇修路 MST
查看>>
Uva 242 邮票和信封
查看>>
MVC项目使用Oracle数据库运行提示:找不到请求的 .Net Framework Data Provider。可能没有安装...
查看>>
【Prince2科普】P2七大主题之质量
查看>>
利用反射将任意元素类型 的 List 转为 DataTable
查看>>
【学习Android NDK开发】Type Signatures(类型签名)
查看>>
对话框添加菜单栏和工具栏及其启用,禁用同步
查看>>
开源组件或者好用的资源地址
查看>>
python学习笔记-生成随机数
查看>>
破解:前一刻觉得还有好多事要做,突然间就不知道该干什么了
查看>>
HDU1235 统计同成绩学生人数【序列处理】
查看>>
python和shell变量互相传递
查看>>