我希望这是问的正确地方。否则请为我的错误感到抱歉,并请pleace为我提供一个更好的网站。

我正在尝试使用一定范围的hsb图像实现一个超级简单的皮肤检测器。我正在使用此处和此处所述的方法。

我尝试使用网络摄像头中的视频源。如果我使用阳光照明,效果会很好(不是很好,但很好),但是在霓虹灯下..那是一团糟。为什么会检测到很多白色区域并且到处都有很多噪音。

为什么?

我正在使用第二个来源中所述的算法:


将图像转换为HSV色彩空间
将白色置于范围0 膨胀过滤器
腐蚀过滤器
模糊过滤器



#1 楼

实际上,使用简单的RGB生成模型而不是HSV可能会更好。


获取训练图像或一些带有某些皮肤的训练图像。
手动选择皮肤像素(例如,通过创建二进制蒙版)
计算RGB中肤色的均值和协方差(每个均应为3元素矢量)<​​br />对于未知像素,请使用协方差。
如果距离小于阈值,则将其分类为皮肤。
调整阈值以获得最佳性能。

编辑:
我不知道是否OpenCV具有计算协方差的功能,但是我可以告诉您如何自己做。假设您有$ n $ RGB像素。您将它们放入$ n $ x 3矩阵,我们称其为$ P $。然后计算$ m $,这是通过计算列的平均值得出的平均RGB向量。 $ m $将是一个1 x 3的向量。从$ P $的每一行中减去$ m $,然后调用所得矩阵$ Q $。现在要计算协方差,您要做的就是将$ Q $乘以自身的转置:$ C = Q'Q $。确保$ C $为3 x3。

Edit2:
您得到的值似乎太大。要获得最大协方差,请创建以下矩阵:

255 255 255
 0   0   0


并计算其协方差。您应该得到一个矩阵,其中每个值都近似为
32513。因此,请确保您的像素值介于0到255之间,并确保将其正确复制到float或double中。马氏距离以方差为单位,因此,该数字应较小。您的皮肤分类阈值应小于4。

评论


$ \ begingroup $
我在理解如何从图像中使用opencv获得3x3协方差矩阵时遇到问题。您能给我一些参考吗?
$ \ endgroup $
– nkint
2012-03-20 23:12

$ \ begingroup $
@nkint,请参阅编辑后的答案。
$ \ endgroup $
–迪马
2012年3月21日在12:47

$ \ begingroup $
好的,很好。在5行中,您使我理解了协方差。谢谢。有用。但我在存储结果时遇到问题。如果我的像素范围是0-255,那么我应该期望马哈拉诺比斯距离的数字是什么?如果我将它们储存在8盎司的纸上,它的确只占皮肤的一小部分;如果我将它们储存在32层的纸上,我会听到强烈的白噪声
$ \ endgroup $
– nkint
2012年3月21日在20:40

$ \ begingroup $
是的,我认为我做错了,因为我的协方差矩阵是:[10913058.00000000,7046611.50000000,3290781.50000000; 7046611.50000000,4811646.00000000,2225078.00000000; 3290781.50000000,2225078.00000000,1387631.87500000]
$ \ endgroup $
– nkint
2012年3月21日在20:52

$ \ begingroup $
您可以将协方差视为定义3D中的椭圆体。您可能可以在Matlab中对其进行可视化,但这可能需要大量工作。或者,您可以尝试查看椭球的2D投影,但这也需要一些工作。
$ \ endgroup $
–迪马
2012年3月22日17:11

#2 楼

请考虑应用霓虹灯时HSV颜色获得的不同值:此处是其偏差的示例。
尝试调整算法以使其适应这些值。

这里是另一种用于检测皮肤的算法,并且可以用于检测光照条件。您可以使用此算法。

另一种算法是与皮肤检测有关,但与霓虹灯效果没有太大关系。 />

#3 楼

到目前为止,您所获得的答案都指向了不错的替代方法,但是,如果您对使用诸如初始算法之类的东西感兴趣,则可能不难解决。您只需要针对OpenCV的HSV特性进行调整。鉴于结果古怪,我认为您可能在选择阈值和/或转换像素时使用了HSV的一种较为常见的数字表示形式?

OpenCV代表HSV的方式与您可能发现的大多数其他来源不同:


对您来说最大的不同是色相:OpenCV
表示色相介于0到179之间,而几乎其他所有东西都利用悬挂位来保存更多信息(w / 0-255)。
另一个区别:饱和度的测量是倒置的
与规范相比。所以255饱和度意味着opencv中是明亮的,
而不是白色(注意,我们回到了255-只有色相是0-180,
也许是因为'wheel'表示?)

可能为时已晚,无法为您提供帮助,但这是一个有趣的问题,其他人可能也会遇到相同的问题。

#4 楼

import sys
import numpy
import cv2

cap = cv2.VideoCapture(0)
while(1):
    _, im = cap.read()

    im_ycrcb = cv2.cvtColor(im, cv2.COLOR_BGR2YCR_CB)

    skin_ycrcb_mint = numpy.array((0, 133, 77))
    skin_ycrcb_maxt = numpy.array((255, 173, 127))
    skin_ycrcb = cv2.inRange(im_ycrcb, skin_ycrcb_mint, skin_ycrcb_maxt)

    cv2.imshow("Second Image", skin_ycrcb) # Second image
    contours, _ = cv2.findContours(skin_ycrcb, cv2.RETR_EXTERNAL, 
        cv2.CHAIN_APPROX_SIMPLE)
    for i, c in enumerate(contours):
        area = cv2.contourArea(c)
            if area > 1000:
                cv2.drawContours(im, contours, i, (255, 0, 0), 3)
    cv2.imshow("Final Image", im)         # Final image
    cv2.waitKey(1)