utl*_*ngh 0 image-processing computer-vision
给定图像的所有像素的RGB值,我们如何找到给定像素具有肤色的概率以及图像的肤色百分比.
Google上的Noodling告诉我,白种人的肤色经常,或者通常,或者有时可能符合以下规则:
Blue channel: 140-180
Green channel: Blue * 1.15
Red channel: Blue * 1.5
Run Code Online (Sandbox Code Playgroud)
因此,考虑到这一点,我使用此命令行制作了一些与ImageMagick相对应的颜色样本:
#!/bin/bash
for b in $(seq 140 5 180); do
g=$(echo "$b * 1.15/1" | bc)
r=$(echo "$b * 1.5/1" | bc)
convert -label "R:$r,G:$g,B:$b" -size 200x200 xc:"rgb($r,$g,$b)" miff:-
done | montage - -frame 5 -tile 3x swatches.png
Run Code Online (Sandbox Code Playgroud)
得到了这个:

好吧,那些看起来很合理,现在我尝试使用它们来检测肤色,再次使用ImageMagick.就目前而言,只有这样你才能看到它,我将使用上面确定的色调范围中间的色调,将其检测为肤色,并将其检测为肤色.
convert -fuzz 5% face1.jpg -fill lime -opaque "rgb(240,184,160)" out.jpg
Run Code Online (Sandbox Code Playgroud)

嗯,不是很好.可能会增加模糊性?

嗯,仍然很垃圾 - 只捡起部分皮肤和一些白衬衫领.不同的面孔可能?

好吧,在检测到他时并不坏,虽然注意到它完全无法检测到他的右侧,但是从粉红色凯迪拉克中我们可以看到仍有一些问题:

还有小猪小姐......

也许我们可以在搜索中更有针对性,虽然我不能用3D绘制它,但我可以用二维解释.我们不是在我们的范围中间瞄准单个大圆(实际上是三维空间中的球体),也许我们可以定位沿着我们的范围扩展的一些较小的圆,从而包含更少的外来颜色......洋红色代表模糊程度.所以不是这样:

我们可以这样做:

使用此命令:
convert -fuzz 13% face1.jpg -fill lime \
-opaque "rgb(219,168,146)" \
-opaque "rgb(219,168,146)" \
-opaque "rgb(255,198,172)" out.jpg
Run Code Online (Sandbox Code Playgroud)

所以,你可以看到很难通过使用RGB值找到肤色,我甚至没有开始处理不同的种族,不同的照明等.
另一种方法可能是使用不同的色彩空间,例如HSL - 色调饱和度和亮度.我们对Lightness不太感兴趣,因为这只是曝光的一个功能,所以我们寻找与皮肤相匹配的色调和一定程度的饱和度以避免褪色.您可以使用ImageMagick这样做:
#!/bin/bash
convert face1.jpg -colorspace hsl -separate \
\( -clone 0 -threshold 7% -negate +write h.png \) \
\( -clone 1 -threshold 30% +write s.png \) \
-delete 0-2 -evaluate-sequence min out.png
Run Code Online (Sandbox Code Playgroud)
这就是说...拍摄图像face1.jpg并将其转换为HSL颜色空间,然后将图层分开,这样我们现在在堆栈中有3个图像.image 0是色调,image 1是饱和度,image 2是光明.下一行.取Hue层并将其阈值设置为7%,这意味着小红色,将其反转并保存(只有这样你才能看到它)h.png.下一行.取饱和度图层,然后说" 任何超过30%的饱和度对我来说都足够了 ",然后保存为文件s.png.下一行.从原始图像中删除3个原始图层(HS&L),只留下阈值色调和阈值饱和度图层.现在把它们放在彼此的顶部并选择最小的那个并保存它.关键是可以使用Hue或Saturation层来gate选择哪些像素.
这是文件,首先是Hue(h.png):

接下来的饱和度(s.png):

现在是组合输出文件.

一旦你的算法被整理出来以决定哪些像素是肤色的,你需要计算它们以计算你寻找的百分比.这很简单......我们所做的就是将所有非石灰绿色变为黑色(因此在平均值中计为零),然后将图像调整为单个像素并将其颜色作为文本:
convert -fuzz 13% face1.jpg -fill lime \
-opaque "rgb(219,168,146)" \
-opaque "rgb(219,168,146)" \
-opaque "rgb(255,198,172)" \
-fill black +opaque lime -resize 1x1! txt:
# ImageMagick pixel enumeration: 1,1,255,srgb
0,0: (0,92,0) #005C00 srgb(0,92,0)
Run Code Online (Sandbox Code Playgroud)
我们可以看到,毫不奇怪,没有红色和没有蓝色,绿色像素的平均颜色是92/255,因此36%的像素符合我们对皮肤色调的描述.
如果你想变得更复杂,你可能需要查看形状,纹理和上下文,或者训练皮肤分类器并在OpenCV中编写一大堆东西或者某些东西......